766 lines
24 KiB
C++
766 lines
24 KiB
C++
|
//
|
||
|
// WebCheck Mail Agent
|
||
|
//
|
||
|
// A user specifies that they are to be notified via email when a web checked
|
||
|
// object (usually a page) changes.
|
||
|
//
|
||
|
// When the subscription is the delivery agent will call the mail agent upon completion
|
||
|
// with a temporary ISubscriptionItem
|
||
|
//
|
||
|
// Julian Jiggins (julianj), January 8, 1997
|
||
|
//
|
||
|
|
||
|
#include "private.h"
|
||
|
#include "mapi.h"
|
||
|
#include "smtp.h"
|
||
|
#include "mlang.h"
|
||
|
|
||
|
#include <mluisupp.h>
|
||
|
|
||
|
#undef TF_THISMODULE
|
||
|
#define TF_THISMODULE TF_MAILAGENT
|
||
|
|
||
|
//
|
||
|
// Global strings
|
||
|
// REVIEW move to a better place
|
||
|
//
|
||
|
#define MAIL_HANDLER TEXT("Software\\Clients\\Mail")
|
||
|
#define MAIL_ATHENA TEXT("Internet Mail and News")
|
||
|
#define SUBJECT_LINE TEXT("Subscription delivered")
|
||
|
#define MESSAGE_PREFIX TEXT(" \r\nThe website you requested ")
|
||
|
#define MESSAGE_SUFFIX TEXT(" has been delivered")
|
||
|
|
||
|
#define ATHENA_SMTP_SERVER \
|
||
|
TEXT("Software\\Microsoft\\Internet Mail and News\\Mail\\SMTP")
|
||
|
#define NETSCAPE_SMTP_SERVER \
|
||
|
TEXT("Software\\Netscape\\netscape Navigator\\Services\\SMTP_Server")
|
||
|
#define EUDORA_COMMANDLINE TEXT("Software\\Qualcomm\\Eudora\\CommandLine")
|
||
|
|
||
|
#define NOTE_TEXT_LENGTH 4096
|
||
|
|
||
|
#define ENCODING_STRLEN 32
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Email helper functions
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// Returns a MemAlloc'd string with HTMLBreak inserted in place of '\d'.
|
||
|
//
|
||
|
void AddHTMLBreakText(LPSTR szText, LPSTR szHTMLBreak, LPSTR *lpHTMLText)
|
||
|
{
|
||
|
ASSERT(szText);
|
||
|
ASSERT(szHTMLBreak);
|
||
|
ASSERT(!*lpHTMLText);
|
||
|
|
||
|
LPSTR lpTmp = NULL, lpTmp2 = NULL, lpHTMLAbstract = NULL;
|
||
|
int cbCRs = 0;
|
||
|
int cbLFs = 0;
|
||
|
DWORD dwExtra = 0;
|
||
|
|
||
|
//
|
||
|
// Count number of carriage returns
|
||
|
//
|
||
|
for (lpTmp = szText; *lpTmp; lpTmp++)
|
||
|
{
|
||
|
if (*lpTmp == 0x0d)
|
||
|
cbCRs++;
|
||
|
if (*lpTmp == 0x0a)
|
||
|
cbLFs++;
|
||
|
}
|
||
|
|
||
|
dwExtra = lstrlenA(szText) - cbCRs - cbLFs + cbCRs * lstrlenA(szHTMLBreak) + 1;
|
||
|
|
||
|
//
|
||
|
// Allocate appropriate size string
|
||
|
//
|
||
|
*lpHTMLText = lpHTMLAbstract = (LPSTR)MemAlloc(LPTR, dwExtra);
|
||
|
if (!lpHTMLAbstract)
|
||
|
return;
|
||
|
|
||
|
//
|
||
|
// Create new HTML abstract string.
|
||
|
//
|
||
|
for (lpTmp = szText; *lpTmp; lpTmp++)
|
||
|
{
|
||
|
if (*lpTmp == 0x0d)
|
||
|
{
|
||
|
for (lpTmp2 = szHTMLBreak; *lpTmp2; lpTmp2++, lpHTMLAbstract++)
|
||
|
*lpHTMLAbstract = *lpTmp2;
|
||
|
}
|
||
|
else if (*lpTmp != 0x0a)
|
||
|
{
|
||
|
*lpHTMLAbstract = *lpTmp;
|
||
|
lpHTMLAbstract++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*lpHTMLAbstract = '\0';
|
||
|
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
void DBG_OUTPUT_MAPI_ERROR(ULONG ul)
|
||
|
{
|
||
|
switch(ul)
|
||
|
{
|
||
|
case MAPI_E_LOGON_FAILURE:
|
||
|
DBG("MailAgent: MAPI LOGON FAILURE"); break;
|
||
|
case MAPI_E_FAILURE:
|
||
|
DBG("MailAgent: MAPI_E_FAILURE"); break;
|
||
|
default:
|
||
|
DBG("MailAgent: Failed to send mail message"); break;
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
#define DBG_OUTPUT_MAPI_ERROR(ul)
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Build an HTML message containing a frameset that effectively inlines
|
||
|
// the requested URL
|
||
|
//
|
||
|
BOOL BuildHTMLMessage(LPSTR szEmailAddress, LPSTR szName, LPSTR szURL,
|
||
|
CHAR **ppHTMLMessage, LPSTR szTitle, LPSTR szAbstract,
|
||
|
LPSTR szSrcCharset)
|
||
|
{
|
||
|
*ppHTMLMessage = NULL; // clear out parameter
|
||
|
|
||
|
CHAR * lpBuffer = NULL;
|
||
|
|
||
|
CHAR szWrapper[NOTE_TEXT_LENGTH];
|
||
|
CHAR szMessageFormat[NOTE_TEXT_LENGTH];
|
||
|
CHAR szMessageFormat2[NOTE_TEXT_LENGTH];
|
||
|
CHAR szMessageText[NOTE_TEXT_LENGTH];
|
||
|
CHAR szMessageHTML[NOTE_TEXT_LENGTH];
|
||
|
CHAR szTextBreak[10];
|
||
|
CHAR szHTMLBreak[10];
|
||
|
|
||
|
//
|
||
|
// Load the wrapper for the HTML message. This is the header stuff
|
||
|
// and multipart MIME and HTML goop
|
||
|
//
|
||
|
int iRet = MLLoadStringA(IDS_AGNT_HTMLMESSAGEWRAPPER, szWrapper, NOTE_TEXT_LENGTH);
|
||
|
ASSERT(iRet > 0);
|
||
|
|
||
|
if (szTitle != NULL) {
|
||
|
|
||
|
// NOTE: Size is probably slightly larger than necessary due to %1's.
|
||
|
|
||
|
LPSTR lpHTMLAbstract = NULL, lpNewAbstract = NULL;
|
||
|
DWORD dwTotalSize = 0;
|
||
|
//
|
||
|
// load string for single HTML line break as well as tag on for custom email
|
||
|
//
|
||
|
|
||
|
MLLoadStringA(IDS_AGNT_EMAILMESSAGE, szMessageText, ARRAYSIZE(szMessageText));
|
||
|
|
||
|
MLLoadStringA(IDS_AGNT_HTMLBREAKSINGLE, szHTMLBreak, ARRAYSIZE(szHTMLBreak));
|
||
|
|
||
|
//
|
||
|
// Create new abstract string (szAbstract + email tagger)
|
||
|
//
|
||
|
dwTotalSize = lstrlenA(szAbstract) + lstrlenA(szMessageText) + 1;
|
||
|
|
||
|
LPSTR szNewAbstract = (LPSTR)MemAlloc(LPTR, dwTotalSize * sizeof(CHAR));
|
||
|
if (!szNewAbstract)
|
||
|
return FALSE;
|
||
|
|
||
|
lstrcpyA(szNewAbstract, szAbstract);
|
||
|
StrCatA(szNewAbstract, szMessageText);
|
||
|
|
||
|
AddHTMLBreakText(szNewAbstract, szHTMLBreak, &lpHTMLAbstract);
|
||
|
if (!lpHTMLAbstract)
|
||
|
{
|
||
|
MemFree(szNewAbstract);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dwTotalSize = lstrlenA(szWrapper) + lstrlenA(szEmailAddress) +
|
||
|
2*lstrlenA(szTitle) + lstrlenA(szNewAbstract) + lstrlenA(szSrcCharset) +
|
||
|
lstrlenA(lpHTMLAbstract) + lstrlenA(szURL) + 1;
|
||
|
|
||
|
lpBuffer = (CHAR *)MemAlloc(LPTR, dwTotalSize * sizeof(CHAR));
|
||
|
if (!lpBuffer)
|
||
|
return FALSE;
|
||
|
|
||
|
LPSTR lpArguments[6];
|
||
|
lpArguments[0] = szEmailAddress;
|
||
|
lpArguments[1] = szTitle;
|
||
|
lpArguments[2] = szNewAbstract;
|
||
|
lpArguments[3] = szSrcCharset; // the charset of the HTML page
|
||
|
lpArguments[4] = szURL;
|
||
|
lpArguments[5] = lpHTMLAbstract;
|
||
|
|
||
|
//
|
||
|
// Reason for FormatMessage is that wsprintf is limited up to 1024 bytes
|
||
|
//
|
||
|
|
||
|
FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||
|
szWrapper, 0, 0, lpBuffer, dwTotalSize, (va_list *)&lpArguments[0]);
|
||
|
|
||
|
MemFree(szNewAbstract);
|
||
|
MemFree(lpHTMLAbstract);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Load line breaks for the plaintext and html messages
|
||
|
//
|
||
|
iRet = MLLoadStringA(IDS_AGNT_TEXTBREAK, szTextBreak, ARRAYSIZE(szTextBreak));
|
||
|
ASSERT(iRet > 0);
|
||
|
iRet = MLLoadStringA(IDS_AGNT_HTMLBREAK, szHTMLBreak, ARRAYSIZE(szHTMLBreak));
|
||
|
ASSERT(iRet > 0);
|
||
|
|
||
|
//
|
||
|
// Load the actual text message to put sent
|
||
|
//
|
||
|
iRet = MLLoadStringA(IDS_AGNT_HTMLMESSAGETEXT, szMessageFormat, NOTE_TEXT_LENGTH);
|
||
|
ASSERT(iRet > 0);
|
||
|
|
||
|
iRet = MLLoadStringA(IDS_AGNT_HTMLMESSAGETEXT2, szMessageFormat2, NOTE_TEXT_LENGTH);
|
||
|
ASSERT(iRet > 0);
|
||
|
|
||
|
//
|
||
|
// Insert the text messages into the wrapper. Note two message get
|
||
|
// Once in the mime section for text/ascii and once in the
|
||
|
// noframes section of the text/html frameset. This is a work around
|
||
|
// for clients (like Outlook) that think they can render HTML
|
||
|
// but cannot really.
|
||
|
// The second message IDS_AGNT_HTMLMESSAGETEXT2 should NOT be localized
|
||
|
// this is only going to be seen by Exchange users. In the future exchange
|
||
|
// will handle html mail correct, so it acceptable that for example
|
||
|
// Japanese Exchange users see english in this message. Most Japanese
|
||
|
// users will user Outlook Express and so will just see the html message
|
||
|
//
|
||
|
|
||
|
// First we format 2 text messages, one for text and one for HTML,
|
||
|
// since message itself is relatively small we know its < 1024 bytes
|
||
|
|
||
|
iRet = wnsprintfA(szMessageText, ARRAYSIZE(szMessageText), szMessageFormat,
|
||
|
szName, szTextBreak, szURL, szTextBreak);
|
||
|
ASSERT(iRet > lstrlenA(szMessageFormat));
|
||
|
|
||
|
iRet = wnsprintfA(szMessageHTML, ARRAYSIZE(szMessageHTML), szMessageFormat2,
|
||
|
szName, szHTMLBreak, szURL, szHTMLBreak);
|
||
|
ASSERT(iRet > lstrlenA(szMessageFormat2));
|
||
|
|
||
|
DWORD dwTotalSize = lstrlenA(szWrapper) + lstrlenA(szEmailAddress) +
|
||
|
lstrlenA(szName) + lstrlenA(szMessageText) + lstrlenA(szSrcCharset) +
|
||
|
lstrlenA(szMessageHTML) + lstrlenA(szURL) + 1;
|
||
|
|
||
|
lpBuffer = (CHAR *)MemAlloc(LPTR, dwTotalSize * sizeof(CHAR));
|
||
|
if (!lpBuffer)
|
||
|
return FALSE;
|
||
|
|
||
|
LPSTR lpArguments[6];
|
||
|
lpArguments[0] = szEmailAddress; // target email address
|
||
|
lpArguments[1] = szName; // the name of the page that goes in the subject line
|
||
|
lpArguments[2] = szMessageText; // the plain text message
|
||
|
lpArguments[3] = szSrcCharset; // the charset of the HTML page
|
||
|
lpArguments[4] = szURL; // the href of the page that goes in the frame set
|
||
|
lpArguments[5] = szMessageHTML; // the plain text message that goes in the
|
||
|
// noframes part of the frameset
|
||
|
|
||
|
DWORD dwRet;
|
||
|
dwRet = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||
|
szWrapper, 0, 0, lpBuffer, dwTotalSize, (va_list *)&lpArguments[0]);
|
||
|
ASSERT(dwRet);
|
||
|
}
|
||
|
|
||
|
*ppHTMLMessage = lpBuffer;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Build the actual text of the message to be sent via SMTP,
|
||
|
// load format string from resource and insert URL and URL's friently name.
|
||
|
//
|
||
|
void BuildSMTPMessage(LPSTR szName, LPSTR szURL, LPSTR *szMessage,
|
||
|
LPSTR szTitle, LPSTR szAbstract)
|
||
|
{
|
||
|
CHAR szFormatText[NOTE_TEXT_LENGTH];
|
||
|
int i;
|
||
|
ASSERT(szMessage);
|
||
|
|
||
|
if (!szMessage)
|
||
|
return;
|
||
|
|
||
|
|
||
|
*szMessage = NULL;
|
||
|
|
||
|
if (szTitle != NULL) {
|
||
|
i = MLLoadStringA(IDS_AGNT_SMTPMESSAGE_OTHER, szFormatText, NOTE_TEXT_LENGTH);
|
||
|
ASSERT(i != 0);
|
||
|
|
||
|
DWORD dwLen = lstrlenA(szFormatText) + lstrlenA(szTitle) + lstrlenA(szAbstract) + 1;
|
||
|
|
||
|
*szMessage = (LPSTR) MemAlloc(LPTR, dwLen * sizeof(CHAR));
|
||
|
if (!*szMessage)
|
||
|
return;
|
||
|
|
||
|
LPSTR lpArgs[2];
|
||
|
lpArgs[0] = szTitle;
|
||
|
lpArgs[1] = szAbstract;
|
||
|
|
||
|
FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||
|
szFormatText, 0, 0, *szMessage, dwLen, (va_list *)&lpArgs[0]);
|
||
|
|
||
|
} else {
|
||
|
i = MLLoadStringA(IDS_AGNT_SMTPMESSAGE, szFormatText, NOTE_TEXT_LENGTH);
|
||
|
ASSERT(i != 0);
|
||
|
|
||
|
DWORD dwLen = lstrlenA(szFormatText) + 2*lstrlenA(szName) + lstrlenA(szURL) + 1;
|
||
|
|
||
|
*szMessage = (LPSTR) MemAlloc(LPTR, dwLen * sizeof(CHAR));
|
||
|
if (!*szMessage)
|
||
|
return;
|
||
|
|
||
|
LPSTR lpArgs[3];
|
||
|
lpArgs[0] = lpArgs[1] = szName;
|
||
|
lpArgs[2] = szURL;
|
||
|
|
||
|
FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||
|
szFormatText, 0, 0, *szMessage, dwLen, (va_list *)&lpArgs[0]);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
//
|
||
|
// Build MAPI message structure
|
||
|
//
|
||
|
|
||
|
void BuildMAPIMessage(
|
||
|
LPTSTR lpszName,
|
||
|
LPTSTR lpszURL,
|
||
|
LPTSTR lpszEmailAddress,
|
||
|
MapiMessage * lpMessage,
|
||
|
MapiRecipDesc * lpRecipient,
|
||
|
LPTSTR lpszNoteText, // [out]
|
||
|
LPTSTR lpszSubject, // [out]
|
||
|
LPTSTR lpszTitle, // [in] title, NULL if not custom
|
||
|
LPTSTR lpszAbstract) // [in] abstract, NULL if not custom
|
||
|
{
|
||
|
TCHAR szFmtNoteText[NOTE_TEXT_LENGTH];
|
||
|
TCHAR szFmtSubject[INTERNET_MAX_URL_LENGTH];
|
||
|
int i;
|
||
|
|
||
|
//
|
||
|
// zero out the passed in mapi structures
|
||
|
//
|
||
|
ZeroMemory(lpMessage, sizeof(MapiMessage));
|
||
|
ZeroMemory(lpRecipient, sizeof(MapiRecipDesc));
|
||
|
#error The wsprintf's below need to be converted to wnsprintf
|
||
|
//
|
||
|
// Load the strings containing the bulk of the email message
|
||
|
//
|
||
|
if (lpszTitle != NULL) {
|
||
|
MLLoadString(IDS_AGNT_MAPIMESSAGE_OTHER, szFmtNoteText, NOTE_TEXT_LENGTH);
|
||
|
MLLoadString(IDS_AGNT_MAPISUBJECT_OTHER, szFmtSubject, INTERNET_MAX_URL_LENGTH);
|
||
|
|
||
|
i = wsprintf(lpszNoteText, szFmtNoteText, lpszAbstract);
|
||
|
ASSERT(i < NOTE_TEXT_LENGTH);
|
||
|
i = wsprintf(lpszSubject, szFmtSubject, lpszTitle);
|
||
|
ASSERT(i < INTERNET_MAX_URL_LENGTH);
|
||
|
|
||
|
} else {
|
||
|
MLLoadString(IDS_AGNT_MAPIMESSAGE, szFmtNoteText, NOTE_TEXT_LENGTH);
|
||
|
MLLoadString(IDS_AGNT_MAPISUBJECT, szFmtSubject, INTERNET_MAX_URL_LENGTH);
|
||
|
|
||
|
i = wsprintf(lpszNoteText, szFmtNoteText, lpszName, lpszURL);
|
||
|
ASSERT(i < NOTE_TEXT_LENGTH);
|
||
|
i = wsprintf(lpszSubject, szFmtSubject, lpszName);
|
||
|
ASSERT(i < INTERNET_MAX_URL_LENGTH);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Build a mapi mail recipient structure
|
||
|
//
|
||
|
lpRecipient->ulRecipClass = MAPI_TO;
|
||
|
lpRecipient->lpszName = lpszEmailAddress;
|
||
|
|
||
|
//
|
||
|
// Fill in the message subject line, recipient and note text
|
||
|
//
|
||
|
lpMessage->nRecipCount = 1;
|
||
|
lpMessage->lpRecips = lpRecipient;
|
||
|
lpMessage->lpszNoteText = lpszNoteText;
|
||
|
lpMessage->lpszSubject = lpszSubject;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Use the MLANG apis to translate the string
|
||
|
//
|
||
|
// Returns success if translation occurred, fails otherwise
|
||
|
//
|
||
|
// Note if lpszSrcCharSet is NULL then use CP_ACP as the codepage
|
||
|
//
|
||
|
|
||
|
HRESULT TranslateCharset(
|
||
|
LPSTR lpszSrcString, LPSTR lpszDstString, UINT uiDstSize,
|
||
|
LPSTR lpszSrcCharset, LPSTR lpszDstCharset
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
WCHAR wszSrcCharset[ENCODING_STRLEN];
|
||
|
WCHAR wszDstCharset[ENCODING_STRLEN];
|
||
|
|
||
|
if (lpszSrcString == NULL || lpszDstString == NULL ||
|
||
|
lpszDstCharset == NULL)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
SHAnsiToUnicode(lpszDstCharset, wszDstCharset, ARRAYSIZE(wszDstCharset));
|
||
|
if (lpszSrcCharset)
|
||
|
SHAnsiToUnicode(lpszSrcCharset, wszSrcCharset, ARRAYSIZE(wszSrcCharset));
|
||
|
|
||
|
LPMULTILANGUAGE2 pIML2 = NULL;
|
||
|
|
||
|
//
|
||
|
// Create the MLANG object
|
||
|
//
|
||
|
if (SUCCEEDED(CoCreateInstance (CLSID_CMultiLanguage, NULL,
|
||
|
CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (void**)&pIML2)))
|
||
|
{
|
||
|
UINT srcCodePage = (UINT)-1, dstCodePage;
|
||
|
MIMECSETINFO mcsi = {0};
|
||
|
|
||
|
//
|
||
|
// First get the source code page either from the passed in string
|
||
|
// name of source Charset or from the default one if null if passed in
|
||
|
//
|
||
|
if (lpszSrcCharset == NULL)
|
||
|
{
|
||
|
srcCodePage = GetACP();
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Use the mlang object to get the codepages
|
||
|
//
|
||
|
hr = pIML2->GetCharsetInfo(wszSrcCharset, &mcsi);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
srcCodePage = mcsi.uiInternetEncoding;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pIML2->GetCharsetInfo(wszDstCharset, &mcsi);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
dstCodePage = mcsi.uiInternetEncoding;
|
||
|
|
||
|
if (srcCodePage != dstCodePage)
|
||
|
{
|
||
|
//
|
||
|
// To work around a bug in the Mlang::ConvertString api
|
||
|
// have to pass in a ptr to length of the src string
|
||
|
//
|
||
|
UINT uiSrcSize = lstrlenA(lpszSrcString) + 1;
|
||
|
|
||
|
DWORD dwMode = 0;
|
||
|
hr = pIML2->ConvertString(
|
||
|
&dwMode,
|
||
|
srcCodePage,
|
||
|
dstCodePage,
|
||
|
(LPBYTE)lpszSrcString,
|
||
|
&uiSrcSize,
|
||
|
(LPBYTE)lpszDstString,
|
||
|
&uiDstSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpynA(lpszDstString, lpszSrcString, uiDstSize);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pIML2->Release();
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Mail notification implementation
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// Notify via email that the pszURL has changed
|
||
|
//
|
||
|
// There are 3 ways to send via email -
|
||
|
//
|
||
|
// Use straight MAPI (IE Exchange or Outlook)
|
||
|
// Most people don't have Exchange in the real world.
|
||
|
//
|
||
|
// Use Athena's MAPI implementation
|
||
|
// It's broken and doesn't handle UI'less mode
|
||
|
//
|
||
|
// Use straight SMTP,
|
||
|
// Need to get the name of an SMTP server
|
||
|
//
|
||
|
HRESULT
|
||
|
NotifyViaEMail(
|
||
|
LPSTR lpszURL, // url that was downloaded
|
||
|
LPSTR lpszEmailAddress, // email address to send notification to
|
||
|
LPSTR lpszSMTPServer, // SMTP server to use to deliver email
|
||
|
LPSTR &lpszName, // friendly name of url (probably page title)
|
||
|
LPSTR lpszTitle, // optional: NULL if not custom message
|
||
|
LPSTR lpszAbstract, // optional: NULL if not custom message
|
||
|
LPSTR lpszCharSet, // optional: charset of html page
|
||
|
BOOL fSendHTMLEmail ) // TRUE if registry allows it and check mode
|
||
|
// supports it.
|
||
|
{
|
||
|
BOOL b;
|
||
|
|
||
|
LPSTR lpszSMTPMessage;
|
||
|
|
||
|
//
|
||
|
// lpszName comes from the title of the web page. If the charset of the page
|
||
|
// is not the same as the one that this version of IE has been localized to
|
||
|
// then we need to use the MLANG api's to coerce the string into the correct
|
||
|
// charset
|
||
|
//
|
||
|
CHAR szTargetEncoding[ENCODING_STRLEN];
|
||
|
MLLoadStringA(IDS_TARGET_CHARSET_EMAIL, szTargetEncoding, ARRAYSIZE(szTargetEncoding));
|
||
|
|
||
|
//
|
||
|
// Allocate buffer for new name. This is a conversion from one dbcs charset
|
||
|
// to another so size shouldn't but to be safe use *2 multiplier.
|
||
|
//
|
||
|
UINT uiSize = lstrlenA(lpszName) * 2;
|
||
|
LPSTR lpszNewName = (LPSTR) MemAlloc(LMEM_FIXED, uiSize * sizeof(CHAR));
|
||
|
|
||
|
if (lpszNewName)
|
||
|
{
|
||
|
//
|
||
|
// Note check for S_OK as will return S_FALSE if there is no appropriate
|
||
|
// translation installed on this machine
|
||
|
//
|
||
|
if (S_OK == TranslateCharset(lpszName, lpszNewName, uiSize, lpszCharSet,
|
||
|
szTargetEncoding))
|
||
|
{
|
||
|
//
|
||
|
// if translation occurred alias new name to old name
|
||
|
//
|
||
|
SAFELOCALFREE(lpszName);
|
||
|
lpszName = lpszNewName;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SAFELOCALFREE(lpszNewName); // don't need newname after all
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we are requested to HTML mail and we successfully built the html
|
||
|
//
|
||
|
if (!(fSendHTMLEmail &&
|
||
|
BuildHTMLMessage(lpszEmailAddress, lpszName, lpszURL, &lpszSMTPMessage,
|
||
|
lpszTitle, lpszAbstract, lpszCharSet)))
|
||
|
{
|
||
|
//
|
||
|
// If sending a simple notification or BuildHTMLMessage failed
|
||
|
// force fSendHTMLEmail to false and build simple smtp message
|
||
|
//
|
||
|
fSendHTMLEmail = FALSE;
|
||
|
BuildSMTPMessage(lpszName, lpszURL, &lpszSMTPMessage, lpszTitle, lpszAbstract);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disable MAPI for now
|
||
|
//
|
||
|
//-----------------------------------------
|
||
|
//BUG BUG: If this is enabled then wsprintf on message text should be changed to FormatMessage
|
||
|
// due to 1KB message limit.
|
||
|
#if 0
|
||
|
|
||
|
//
|
||
|
// First try and load a full mapi implementation (exchange or outlook)
|
||
|
//
|
||
|
HMODULE hmodMail = LoadNormalMapi();
|
||
|
if (hmodMail != NULL)
|
||
|
{
|
||
|
//
|
||
|
// Get mapi function entry points
|
||
|
//
|
||
|
LPMAPISENDMAIL pfnSendMail;
|
||
|
LPMAPILOGON pfnLogon;
|
||
|
MapiMessage message;
|
||
|
MapiRecipDesc recipient;
|
||
|
|
||
|
pfnSendMail = (LPMAPISENDMAIL)GetProcAddress(hmodMail, "MAPISendMail");
|
||
|
pfnLogon = (LPMAPILOGON) GetProcAddress(hmodMail, "MAPILogon");
|
||
|
if (pfnSendMail != NULL && pfnLogon != NULL)
|
||
|
{
|
||
|
//
|
||
|
// Logon to mapi provider
|
||
|
//
|
||
|
LHANDLE hSession = 0;
|
||
|
LPSTR lpszProfileName = NULL; // for now logon on with NULL
|
||
|
LPSTR lpszPassword = NULL; // credentials
|
||
|
ULONG ul = pfnLogon(0, lpszProfileName, lpszPassword, 0, 0, &hSession);
|
||
|
if (ul != SUCCESS_SUCCESS)
|
||
|
{
|
||
|
DBG_OUTPUT_MAPI_ERROR(ul);
|
||
|
//
|
||
|
// Fall through to try other mail delivery methods
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TCHAR szSubject[INTERNET_MAX_URL_LENGTH];
|
||
|
|
||
|
//
|
||
|
// Fill in the text, subject line and recipient in mapi message
|
||
|
//
|
||
|
BuildMAPIMessage(lpszName, lpszURL, lpszEmailAddress,
|
||
|
&message, &recipient,
|
||
|
szSubject, lpszSMTPMessage, szTitle, szAbstract);
|
||
|
|
||
|
//
|
||
|
// Actually send the message via MAPI with no UI
|
||
|
//
|
||
|
ul = pfnSendMail(0, 0, &message, 0, 0);
|
||
|
if (ul != SUCCESS_SUCCESS)
|
||
|
{
|
||
|
DBG_OUTPUT_MAPI_ERROR(ul);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FreeLibrary(hmodMail);
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
FreeLibrary(hmodMail);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Send message to given address and from given address
|
||
|
//
|
||
|
if (lpszSMTPMessage)
|
||
|
{
|
||
|
b = SMTPSendMessage(lpszSMTPServer, lpszEmailAddress,
|
||
|
lpszEmailAddress, lpszSMTPMessage);
|
||
|
|
||
|
MemFree(lpszSMTPMessage);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b = FALSE;
|
||
|
}
|
||
|
|
||
|
if (b)
|
||
|
return S_OK;
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Helper function to send email
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
HRESULT SendEmailFromItem(ISubscriptionItem *pItem)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
LPSTR pszURL = NULL;
|
||
|
LPSTR pszName = NULL;
|
||
|
LPSTR pszTitle = NULL;
|
||
|
LPSTR pszAbstract = NULL;
|
||
|
LPSTR pszCharSet = NULL;
|
||
|
|
||
|
// Get the Email URL to send. Fall back to the download URL.
|
||
|
ReadAnsiSTR(pItem, c_szPropEmailURL, &pszURL);
|
||
|
if (!pszURL)
|
||
|
ReadAnsiSTR(pItem, c_szPropURL, &pszURL);
|
||
|
ASSERT(pszURL);
|
||
|
|
||
|
// Get the friendly name. Fall back to the download URL.
|
||
|
ReadAnsiSTR(pItem, c_szPropName, &pszName);
|
||
|
ASSERT(pszName);
|
||
|
if (!pszName)
|
||
|
ReadAnsiSTR(pItem, c_szPropURL, &pszName);
|
||
|
|
||
|
// Get Email Title and Abstract if flag is set.
|
||
|
DWORD dwEmailFlags = 0;
|
||
|
ReadDWORD(pItem, c_szPropEmailFlags, &dwEmailFlags);
|
||
|
if (dwEmailFlags & MAILAGENT_FLAG_CUSTOM_MSG)
|
||
|
{
|
||
|
ReadAnsiSTR(pItem, c_szPropEmailTitle, &pszTitle);
|
||
|
ASSERT(pszTitle);
|
||
|
ReadAnsiSTR(pItem, c_szPropEmailAbstract, &pszAbstract);
|
||
|
ASSERT(pszAbstract);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the charset in the notification
|
||
|
//
|
||
|
ReadAnsiSTR(pItem, c_szPropCharSet, &pszCharSet);
|
||
|
|
||
|
// Get Email address and SMTP server
|
||
|
TCHAR tszBuf[MAX_PATH];
|
||
|
CHAR szEmailAddress[MAX_PATH];
|
||
|
CHAR szSMTPServer[MAX_PATH];
|
||
|
|
||
|
ReadDefaultEmail(tszBuf, ARRAYSIZE(tszBuf));
|
||
|
SHTCharToAnsi(tszBuf, szEmailAddress, ARRAYSIZE(szEmailAddress));
|
||
|
ReadDefaultSMTPServer(tszBuf, ARRAYSIZE(tszBuf));
|
||
|
SHTCharToAnsi(tszBuf, szSMTPServer, ARRAYSIZE(szSMTPServer));
|
||
|
|
||
|
// Send the email
|
||
|
if (pszURL && pszName)
|
||
|
{
|
||
|
//
|
||
|
// Check if HTML Mail notification is enabled or disabled thru the registry
|
||
|
//
|
||
|
BOOL fSendHTMLEmail = FALSE;
|
||
|
|
||
|
if (!ReadRegValue(HKEY_CURRENT_USER, c_szRegKey,
|
||
|
TEXT("EnableHTMLMailNotification"),
|
||
|
&fSendHTMLEmail, sizeof(DWORD)))
|
||
|
{
|
||
|
fSendHTMLEmail = TRUE; // default to on if not read from registry
|
||
|
}
|
||
|
|
||
|
// Now make sure our crawling mode supports HTML mail. We don't
|
||
|
// want to send HTML if we're in check-for-change only.
|
||
|
DWORD dwTemp = 0;
|
||
|
ReadDWORD(pItem, c_szPropCrawlChangesOnly, &dwTemp);
|
||
|
if (dwTemp != 0)
|
||
|
{
|
||
|
fSendHTMLEmail = FALSE;
|
||
|
}
|
||
|
// else, leave fSendHTMLEmail in its reg-based setting.
|
||
|
|
||
|
hr = NotifyViaEMail(pszURL, szEmailAddress, szSMTPServer,
|
||
|
pszName, pszTitle, pszAbstract, pszCharSet,
|
||
|
fSendHTMLEmail );
|
||
|
}
|
||
|
|
||
|
// Clean up.
|
||
|
SAFELOCALFREE(pszURL);
|
||
|
SAFELOCALFREE(pszName);
|
||
|
SAFELOCALFREE(pszTitle);
|
||
|
SAFELOCALFREE(pszAbstract);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|