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.
606 lines
18 KiB
606 lines
18 KiB
// =================================================================================
|
|
// I M N A P I . C P P - IMN exported apis
|
|
// =================================================================================
|
|
#include "pch.hxx"
|
|
#include "mimeole.h"
|
|
#include "mimeutil.h"
|
|
#include "imnapi.h"
|
|
#include "ipab.h"
|
|
#include <error.h>
|
|
#include "demand.h"
|
|
|
|
#ifdef TNEF
|
|
// =================================================================================
|
|
// Globals
|
|
// =================================================================================
|
|
static HINSTANCE g_hImnTnefDll = NULL;
|
|
|
|
// =================================================================================
|
|
// Defines
|
|
// =================================================================================
|
|
#define IMNTNEF_DLL "imntnef.dll"
|
|
|
|
// =================================================================================
|
|
// imntnef function decls
|
|
// =================================================================================
|
|
typedef HRESULT (STDAPICALLTYPE *PFNHRGETTNEFRTFSTREAM)(LPSTREAM lpstmTnef, LPSTREAM lpstmRtf);
|
|
typedef HRESULT (STDAPICALLTYPE *PFNHRINIT)(BOOL fInit);
|
|
|
|
// =================================================================================
|
|
// Globals
|
|
// =================================================================================
|
|
PFNHRINIT g_pfnHrInit = NULL;
|
|
PFNHRGETTNEFRTFSTREAM g_pfnHrGetTnefRtfStream = NULL;
|
|
|
|
#endif // TNEF
|
|
|
|
|
|
// =================================================================================
|
|
//
|
|
// HrMailMsgToImsg:
|
|
//
|
|
// =================================================================================
|
|
HRESULT HrMailMsgToImsg(LPMIMEMESSAGE lpMailMsg, LPMESSAGEINFO pMsgInfo, LPIMSG lpimsg)
|
|
{
|
|
ADRINFO adrinfo;
|
|
HRESULT hr = S_OK;
|
|
ULONG count,
|
|
i;
|
|
IMSGPRIORITY Pri;
|
|
LPHBODY rghAttach = 0;
|
|
PROPVARIANT rVariant;
|
|
LPMIMEMESSAGE pMsg = NULL;
|
|
LPSTREAM lpstmAttach = NULL;
|
|
LPWABAL lpwabal = NULL;
|
|
LPWSTR pwszSubj = NULL,
|
|
pwszFile = NULL;
|
|
|
|
|
|
Assert(lpMailMsg != NULL);
|
|
Assert(lpimsg != NULL);
|
|
|
|
ZeroMemory(lpimsg, sizeof(IMSG));
|
|
|
|
MimeOleGetBodyPropW(lpMailMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &pwszSubj);
|
|
lpimsg->lpszSubject = PszToANSI(CP_ACP, pwszSubj);
|
|
if (pwszSubj && !lpimsg->lpszSubject)
|
|
IF_NULLEXIT(lpimsg->lpszSubject);
|
|
|
|
rVariant.vt = VT_FILETIME;
|
|
if (SUCCEEDED(lpMailMsg->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &rVariant)))
|
|
CopyMemory(&lpimsg->ftReceive, &rVariant.filetime, sizeof(FILETIME));
|
|
|
|
rVariant.vt = VT_FILETIME;
|
|
if (SUCCEEDED(lpMailMsg->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant)))
|
|
CopyMemory(&lpimsg->ftSend, &rVariant.filetime, sizeof(FILETIME));
|
|
|
|
|
|
// flags
|
|
if (pMsgInfo != NULL)
|
|
{
|
|
if (pMsgInfo->dwFlags & ARF_READ)
|
|
lpimsg->uFlags |= MSGFLAG_READ;
|
|
if (!!(pMsgInfo->dwFlags & ARF_UNSENT))
|
|
lpimsg->uFlags |= MSGFLAG_UNSENT;
|
|
if (!!(pMsgInfo->dwFlags & ARF_SUBMITTED))
|
|
lpimsg->uFlags |= MSGFLAG_SUBMIT;
|
|
}
|
|
|
|
// Priority
|
|
Pri = IMSG_PRI_NORMAL;
|
|
rVariant.vt = VT_UI4;
|
|
if (SUCCEEDED(lpMailMsg->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant)))
|
|
Pri = (IMSGPRIORITY)rVariant.ulVal;
|
|
|
|
switch (Pri)
|
|
{
|
|
case IMSG_PRI_LOW:
|
|
lpimsg->wPriority = PRI_LOW;
|
|
break;
|
|
|
|
case IMSG_PRI_HIGH:
|
|
lpimsg->wPriority = PRI_HIGH;
|
|
break;
|
|
|
|
case IMSG_PRI_NORMAL:
|
|
default:
|
|
lpimsg->wPriority = PRI_NORMAL;
|
|
break;
|
|
}
|
|
|
|
lpMailMsg->GetTextBody(TXT_HTML, IET_DECODED, &lpimsg->lpstmHtml, NULL);
|
|
|
|
// get the plain text body
|
|
lpMailMsg->GetTextBody(TXT_PLAIN, IET_DECODED, &lpimsg->lpstmBody, NULL);
|
|
|
|
IF_FAILEXIT(HrGetWabalFromMsg(lpMailMsg, &lpwabal));
|
|
|
|
// get the sender/recipient information
|
|
if (lpwabal)
|
|
{
|
|
count = lpwabal->CEntries();
|
|
if (count > 0)
|
|
{
|
|
IF_NULLEXIT(MemAlloc((LPVOID*)&lpimsg->lpIaddr, sizeof(IADDRINFO)*count));
|
|
|
|
ZeroMemory(lpimsg->lpIaddr, sizeof(IADDRINFO)*count);
|
|
|
|
if (lpwabal->FGetFirst(&adrinfo))
|
|
{
|
|
i = 0;
|
|
|
|
do
|
|
{
|
|
switch(adrinfo.lRecipType)
|
|
{
|
|
case MAPI_TO:
|
|
lpimsg->lpIaddr[i].dwType = IADDR_TO;
|
|
break;
|
|
|
|
case MAPI_ORIG:
|
|
lpimsg->lpIaddr[i].dwType = IADDR_FROM;
|
|
break;
|
|
|
|
case MAPI_CC:
|
|
lpimsg->lpIaddr[i].dwType = IADDR_CC;
|
|
break;
|
|
|
|
case MAPI_BCC:
|
|
lpimsg->lpIaddr[i].dwType = IADDR_BCC;
|
|
break;
|
|
|
|
case MAPI_REPLYTO:
|
|
goto GetNext;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
|
|
lpimsg->lpIaddr[i].lpszAddress = PszToANSI(CP_ACP, adrinfo.lpwszAddress);
|
|
if (adrinfo.lpwszAddress && !lpimsg->lpIaddr[i].lpszAddress)
|
|
IF_NULLEXIT(NULL);
|
|
|
|
lpimsg->lpIaddr[i].lpszDisplay = PszToANSI(CP_ACP, adrinfo.lpwszDisplay);
|
|
if (adrinfo.lpwszDisplay && !lpimsg->lpIaddr[i].lpszDisplay)
|
|
IF_NULLEXIT(NULL);
|
|
|
|
i++;
|
|
GetNext:
|
|
;
|
|
}
|
|
while(lpwabal->FGetNext(&adrinfo));
|
|
|
|
lpimsg->cAddress = i;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Loop through the attachments
|
|
IF_FAILEXIT(hr = lpMailMsg->GetAttachments(&count, &rghAttach));
|
|
|
|
if (count > 0)
|
|
{
|
|
IF_NULLEXIT(MemAlloc((LPVOID*)&lpimsg->lpIatt, sizeof(IATTINFO)*count));
|
|
|
|
ZeroMemory(lpimsg->lpIatt, sizeof(IATTINFO)*count);
|
|
|
|
for (i=0; i<count; i++)
|
|
{
|
|
if (lpMailMsg->IsContentType(rghAttach[i], STR_CNT_MESSAGE, STR_SUB_RFC822)!=S_OK)
|
|
{
|
|
// it's a file
|
|
IMimeBody *pBody = 0;
|
|
|
|
lpimsg->lpIatt[i].lpstmAtt=0;
|
|
lpimsg->lpIatt[i].dwType = IATT_FILE;
|
|
|
|
if (lpMailMsg->BindToObject(rghAttach[i], IID_IMimeBody, (LPVOID *)&pBody)==S_OK)
|
|
{
|
|
if (SUCCEEDED(pBody->GetData(IET_BINARY, &lpstmAttach)))
|
|
{
|
|
lpimsg->lpIatt[i].lpstmAtt = lpstmAttach;
|
|
}
|
|
pBody->Release();
|
|
}
|
|
|
|
if (!lpimsg->lpIatt[i].lpstmAtt)
|
|
lpimsg->lpIatt[i].fError = TRUE;
|
|
|
|
MimeOleGetBodyPropW(lpMailMsg, rghAttach[i], PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &pwszFile);
|
|
lpimsg->lpIatt[i].lpszFileName = PszToANSI(CP_ACP, pwszFile);
|
|
if (pwszFile && !lpimsg->lpIatt[i].lpszFileName)
|
|
IF_NULLEXIT(NULL);
|
|
SafeMimeOleFree(pwszFile);
|
|
}
|
|
else
|
|
{
|
|
// message attachment
|
|
lpimsg->lpIatt[i].dwType = IATT_MSG;
|
|
|
|
IF_FAILEXIT(hr = lpMailMsg->BindToObject(rghAttach[i], IID_IMimeMessage, (LPVOID *)&pMsg));
|
|
|
|
IF_NULLEXIT(MemAlloc((void **)&lpimsg->lpIatt[i].lpImsg, sizeof(IMSG)));
|
|
|
|
IF_FAILEXIT(hr = HrMailMsgToImsg(pMsg, NULL, lpimsg->lpIatt[i].lpImsg));
|
|
SafeRelease(pMsg);
|
|
}
|
|
}
|
|
lpimsg->cAttach = i;
|
|
}
|
|
|
|
exit:
|
|
ReleaseObj(lpwabal);
|
|
|
|
if (FAILED(hr))
|
|
FreeImsg(lpimsg);
|
|
|
|
ReleaseObj(pMsg);
|
|
MemFree(rghAttach);
|
|
MemFree(pwszSubj);
|
|
MemFree(pwszFile);
|
|
return hr;
|
|
}
|
|
|
|
// =================================================================================
|
|
// HrImsgToMailMsg
|
|
// =================================================================================
|
|
HRESULT HrImsgToMailMsg (LPIMSG lpImsg, LPMIMEMESSAGE *lppMailMsg, LPSTREAM *lppstmMsg)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
ULONG i;
|
|
LPSTREAM lpstmPlain = NULL, lpstmAttMsg = NULL;
|
|
LPWABAL lpWabal = NULL;
|
|
LPMIMEMESSAGE lpMailMsg=NULL,
|
|
lpAttMailMsg=0;
|
|
PROPVARIANT rVariant;
|
|
|
|
// Check Params
|
|
Assert (lpImsg && lppMailMsg);
|
|
|
|
// Create CMailMsg
|
|
hr = HrCreateMessage(&lpMailMsg);
|
|
if(FAILED(hr))
|
|
goto exit;
|
|
|
|
// Properties
|
|
MimeOleSetBodyPropA(lpMailMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, lpImsg->lpszSubject);
|
|
|
|
rVariant.vt = VT_FILETIME;
|
|
CopyMemory(&rVariant.filetime, &lpImsg->ftSend, sizeof(FILETIME));
|
|
lpMailMsg->SetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant);
|
|
|
|
if (lpImsg->lpstmHtml)
|
|
{
|
|
// Rewind the stream
|
|
HrRewindStream (lpImsg->lpstmHtml);
|
|
|
|
// Set Body Stream
|
|
lpMailMsg->SetTextBody(TXT_HTML, IET_DECODED, NULL, lpImsg->lpstmHtml, NULL);
|
|
}
|
|
|
|
// Set BODY_PLAIN
|
|
if (lpImsg->lpstmBody)
|
|
{
|
|
// Rewind the stream
|
|
HrRewindStream (lpImsg->lpstmBody);
|
|
|
|
// Set Body Stream
|
|
lpMailMsg->SetTextBody(TXT_PLAIN, IET_DECODED, NULL, lpImsg->lpstmBody, NULL);
|
|
}
|
|
|
|
// Priority
|
|
switch (lpImsg->wPriority)
|
|
{
|
|
case PRI_LOW:
|
|
rVariant.ulVal = IMSG_PRI_LOW;
|
|
break;
|
|
|
|
case PRI_HIGH:
|
|
rVariant.ulVal = IMSG_PRI_HIGH;
|
|
break;
|
|
|
|
default:
|
|
rVariant.ulVal = IMSG_PRI_NORMAL;
|
|
break;
|
|
}
|
|
rVariant.vt = VT_UI4;
|
|
lpMailMsg->SetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant);
|
|
|
|
// Get Address List
|
|
CHECKHR(hr=HrCreateWabalObject(&lpWabal));
|
|
|
|
// Loop Addresses
|
|
for (i=0; i<lpImsg->cAddress; i++)
|
|
{
|
|
LONG lRecipType;
|
|
switch (lpImsg->lpIaddr[i].dwType)
|
|
{
|
|
case IADDR_TO:
|
|
lRecipType = MAPI_TO;
|
|
break;
|
|
|
|
case IADDR_FROM:
|
|
lRecipType = MAPI_ORIG;
|
|
break;
|
|
|
|
case IADDR_CC:
|
|
lRecipType = MAPI_CC;
|
|
break;
|
|
|
|
case IADDR_BCC:
|
|
lRecipType = MAPI_BCC;
|
|
break;
|
|
|
|
default:
|
|
Assert (FALSE);
|
|
break;
|
|
}
|
|
CHECKHR(hr = lpWabal->HrAddEntryA(lpImsg->lpIaddr[i].lpszDisplay, lpImsg->lpIaddr[i].lpszAddress, lRecipType));
|
|
}
|
|
|
|
CHECKHR(hr=HrSetWabalOnMsg(lpMailMsg, lpWabal));
|
|
|
|
// Loop through the attachments
|
|
for (i=0; i<lpImsg->cAttach; i++)
|
|
{
|
|
// Errored Attachment
|
|
if (lpImsg->lpIatt[i].fError)
|
|
continue;
|
|
|
|
// Handle Attachment Type
|
|
switch (lpImsg->lpIatt[i].dwType)
|
|
{
|
|
case IATT_FILE:
|
|
LPSTR lpszFile;
|
|
|
|
if (lpImsg->lpIatt[i].lpszFileName != NULL || lpImsg->lpIatt[i].lpszPathName != NULL)
|
|
{
|
|
lpszFile = lpImsg->lpIatt[i].lpszFileName ? lpImsg->lpIatt[i].lpszFileName : lpImsg->lpIatt[i].lpszPathName;
|
|
|
|
// AttachFile will work of lpstmAtt is NULL or NOT
|
|
CHECKHR(hr=lpMailMsg->AttachFile(lpszFile, lpImsg->lpIatt[i].lpstmAtt, NULL));
|
|
}
|
|
break;
|
|
|
|
case IATT_MSG:
|
|
CHECKHR (hr = HrImsgToMailMsg (lpImsg->lpIatt[i].lpImsg, &lpAttMailMsg, &lpstmAttMsg));
|
|
|
|
CHECKHR (hr = lpMailMsg->AttachObject(IID_IMimeMessage, (LPVOID)lpAttMailMsg, NULL));
|
|
SafeRelease (lpAttMailMsg);
|
|
SafeRelease (lpstmAttMsg);
|
|
break;
|
|
|
|
case IATT_OLE:
|
|
default:
|
|
Assert (FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Does the user want me to stream it out
|
|
if (lppstmMsg)
|
|
{
|
|
CHECKHR (hr = lpMailMsg->GetMessageSource(lppstmMsg, COMMIT_ONLYIFDIRTY));
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease (lpWabal);
|
|
SafeRelease (lpstmPlain);
|
|
SafeRelease (lpAttMailMsg);
|
|
SafeRelease (lpstmAttMsg);
|
|
|
|
if (FAILED (hr))
|
|
{
|
|
SafeRelease (lpMailMsg);
|
|
if(lppstmMsg)
|
|
SafeRelease ((*lppstmMsg));
|
|
}
|
|
else
|
|
{
|
|
*lppMailMsg = lpMailMsg;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
#ifdef TNEF
|
|
|
|
// =================================================================================
|
|
// HrInitImnTnefDll
|
|
// =================================================================================
|
|
HRESULT HrInitImnTnefDll (BOOL fInit)
|
|
{
|
|
// Locals
|
|
static BOOL s_fUnableToLoadDll = FALSE;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Init
|
|
if (fInit)
|
|
{
|
|
// Have we failed to load the required dll
|
|
if (s_fUnableToLoadDll)
|
|
return E_FAIL;
|
|
|
|
// Make sure the dll is loaded
|
|
if (g_hImnTnefDll == NULL)
|
|
{
|
|
// Wait
|
|
SetCursor (LoadCursor (NULL, IDC_WAIT));
|
|
|
|
// Load the dll
|
|
g_hImnTnefDll = LoadLibrary (IMNTNEF_DLL);
|
|
|
|
// Did it load ?
|
|
if (g_hImnTnefDll == NULL)
|
|
{
|
|
SetCursor (LoadCursor (NULL, IDC_ARROW));
|
|
s_fUnableToLoadDll = TRUE;
|
|
hr = TRAPHR (E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Get the proc addresses
|
|
g_pfnHrInit = (PFNHRINIT)GetProcAddress (g_hImnTnefDll, "HrInit");
|
|
g_pfnHrGetTnefRtfStream = (PFNHRGETTNEFRTFSTREAM)GetProcAddress (g_hImnTnefDll, "HrGetTnefRtfStream");
|
|
|
|
// Failed to get proc address
|
|
if (g_pfnHrInit == NULL || g_pfnHrGetTnefRtfStream == NULL)
|
|
{
|
|
SetCursor (LoadCursor (NULL, IDC_ARROW));
|
|
FreeLibrary (g_hImnTnefDll);
|
|
g_hImnTnefDll = NULL;
|
|
g_pfnHrInit = NULL;
|
|
g_pfnHrGetTnefRtfStream = NULL;
|
|
s_fUnableToLoadDll = TRUE;
|
|
hr = TRAPHR (E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Try to init the dll
|
|
hr = (*g_pfnHrInit)(TRUE);
|
|
if (FAILED (hr))
|
|
{
|
|
SetCursor (LoadCursor (NULL, IDC_ARROW));
|
|
(*g_pfnHrInit)(FALSE);
|
|
FreeLibrary (g_hImnTnefDll);
|
|
g_hImnTnefDll = NULL;
|
|
g_pfnHrInit = NULL;
|
|
g_pfnHrGetTnefRtfStream = NULL;
|
|
s_fUnableToLoadDll = TRUE;
|
|
hr = TRAPHR (E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Reset cursor
|
|
SetCursor (LoadCursor (NULL, IDC_ARROW));
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
// Is the dll loaded
|
|
if (g_hImnTnefDll)
|
|
{
|
|
// Deinit
|
|
(*g_pfnHrInit)(FALSE);
|
|
FreeLibrary (g_hImnTnefDll);
|
|
g_hImnTnefDll = NULL;
|
|
g_pfnHrInit = NULL;
|
|
g_pfnHrGetTnefRtfStream = NULL;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// =================================================================================
|
|
// HrGetTnefRtfStream
|
|
// =================================================================================
|
|
HRESULT HrGetTnefRtfStream (LPSTREAM lpstmTnef, LPSTREAM lpstmRtf)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
|
|
// Init our tnef converter dll
|
|
hr = HrInitImnTnefDll (TRUE);
|
|
if (FAILED (hr))
|
|
goto exit;
|
|
|
|
// Can we do it
|
|
if (!g_hImnTnefDll || !g_pfnHrGetTnefRtfStream)
|
|
{
|
|
hr = TRAPHR (E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Call into the dll
|
|
hr = (*g_pfnHrGetTnefRtfStream)(lpstmTnef, lpstmRtf);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
#endif // TNEF
|
|
|
|
|
|
// =====================================================================================
|
|
// FreeImsg
|
|
// =====================================================================================
|
|
VOID WINAPI_16 FreeImsg (LPIMSG lpImsg)
|
|
{
|
|
// Locals
|
|
ULONG i;
|
|
|
|
// Nothing
|
|
if (lpImsg == NULL)
|
|
return;
|
|
|
|
// Free Stuff
|
|
if (lpImsg->lpszSubject)
|
|
MemFree(lpImsg->lpszSubject);
|
|
lpImsg->lpszSubject = NULL;
|
|
|
|
if (lpImsg->lpstmBody)
|
|
lpImsg->lpstmBody->Release ();
|
|
lpImsg->lpstmBody = NULL;
|
|
|
|
if (lpImsg->lpstmHtml)
|
|
lpImsg->lpstmHtml->Release ();
|
|
lpImsg->lpstmHtml = NULL;
|
|
|
|
// Walk Address list
|
|
for (i=0; i<lpImsg->cAddress; i++)
|
|
{
|
|
if (lpImsg->lpIaddr[i].lpszAddress)
|
|
MemFree(lpImsg->lpIaddr[i].lpszAddress);
|
|
lpImsg->lpIaddr[i].lpszAddress = NULL;
|
|
|
|
if (lpImsg->lpIaddr[i].lpszDisplay)
|
|
MemFree(lpImsg->lpIaddr[i].lpszDisplay);
|
|
lpImsg->lpIaddr[i].lpszDisplay = NULL;
|
|
}
|
|
|
|
// Free Address list
|
|
if (lpImsg->lpIaddr)
|
|
MemFree(lpImsg->lpIaddr);
|
|
lpImsg->lpIaddr = NULL;
|
|
|
|
// Walk Attachment list
|
|
for (i=0; i<lpImsg->cAttach; i++)
|
|
{
|
|
if (lpImsg->lpIatt[i].lpszFileName)
|
|
MemFree(lpImsg->lpIatt[i].lpszFileName);
|
|
lpImsg->lpIatt[i].lpszFileName = NULL;
|
|
|
|
if (lpImsg->lpIatt[i].lpszPathName)
|
|
MemFree(lpImsg->lpIatt[i].lpszPathName);
|
|
lpImsg->lpIatt[i].lpszPathName = NULL;
|
|
|
|
if (lpImsg->lpIatt[i].lpszExt)
|
|
MemFree(lpImsg->lpIatt[i].lpszExt);
|
|
lpImsg->lpIatt[i].lpszExt = NULL;
|
|
|
|
if (lpImsg->lpIatt[i].lpImsg)
|
|
{
|
|
FreeImsg (lpImsg->lpIatt[i].lpImsg);
|
|
MemFree(lpImsg->lpIatt[i].lpImsg);
|
|
lpImsg->lpIatt[i].lpImsg = NULL;
|
|
}
|
|
|
|
if (lpImsg->lpIatt[i].lpstmAtt)
|
|
lpImsg->lpIatt[i].lpstmAtt->Release ();
|
|
lpImsg->lpIatt[i].lpstmAtt = NULL;
|
|
}
|
|
|
|
// Free the att list
|
|
if (lpImsg->lpIatt)
|
|
MemFree(lpImsg->lpIatt);
|
|
}
|