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.
1062 lines
35 KiB
1062 lines
35 KiB
// --------------------------------------------------------------------------------
|
|
// Trigger.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "containx.h"
|
|
#include "symcache.h"
|
|
#include "containx.h"
|
|
#include "stackstr.h"
|
|
#include "variantx.h"
|
|
#include "mimeapi.h"
|
|
#ifndef MAC
|
|
#include <shlwapi.h>
|
|
#endif // !MAC
|
|
#include "demand.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_FILENAME
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_FILENAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
BOOL fUseProperty;
|
|
LPWSTR pszExt;
|
|
LPWSTR pszFileName=NULL;
|
|
LPPROPSYMBOL pSymbol;
|
|
|
|
// Handle Dispatch Type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_DELETEPROP:
|
|
if (pContainer->_HrIsTriggerCaller(PID_PAR_FILENAME, IST_DELETEPROP) == S_FALSE)
|
|
{
|
|
pContainer->DeleteProp(SYM_PAR_FILENAME);
|
|
}
|
|
break;
|
|
|
|
case IST_POSTSETPROP:
|
|
// Update PID_PAR_NAME, if it didn't generate this
|
|
if (pContainer->_HrIsTriggerCaller(PID_PAR_NAME, IST_POSTSETPROP) == S_FALSE)
|
|
pContainer->SetProp(SYM_PAR_NAME, dwFlags, pValue);
|
|
|
|
// Update PAR_FILENAME, if it didn't generate this
|
|
if (pContainer->_HrIsTriggerCaller(PID_PAR_FILENAME, IST_POSTSETPROP) == S_FALSE)
|
|
pContainer->SetProp(SYM_PAR_FILENAME, dwFlags, pValue);
|
|
break;
|
|
|
|
case IST_POSTGETPROP:
|
|
// Cleanup the file name
|
|
if (!ISFLAGSET(dwFlags, PDF_ENCODED))
|
|
MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
// Try to get PID_PAR_FILENAME first
|
|
if (FAILED(pContainer->GetPropW(SYM_PAR_FILENAME, &pszFileName)))
|
|
{
|
|
// Try to get PID_PAR_NAME
|
|
if (FAILED(pContainer->GetPropW(SYM_PAR_NAME, &pszFileName)))
|
|
{
|
|
hr = MIME_E_NO_DATA;
|
|
goto exit;
|
|
}
|
|
else
|
|
pSymbol = SYM_PAR_NAME;
|
|
}
|
|
else
|
|
pSymbol = SYM_PAR_FILENAME;
|
|
|
|
// Set Source
|
|
fUseProperty = TRUE;
|
|
|
|
// Locate the extension of the file
|
|
pszExt = PathFindExtensionW(pszFileName);
|
|
|
|
// If .com
|
|
if (pszExt && StrCmpIW(pszExt, L".com") == 0)
|
|
{
|
|
// Locals
|
|
LPWSTR pszCntType=NULL;
|
|
LPWSTR pszSubType=NULL;
|
|
|
|
// Get the file information
|
|
if (SUCCEEDED(MimeOleGetFileInfoW(pszFileName, &pszCntType, &pszSubType, NULL, NULL, NULL)))
|
|
{
|
|
// Extension is .com and content types don't match what is in the body
|
|
if (pContainer->IsContentTypeW(pszCntType, pszSubType) == S_FALSE)
|
|
{
|
|
// Generate It
|
|
if (SUCCEEDED(pContainer->_HrGenerateFileName(NULL, dwFlags, pValue)))
|
|
fUseProperty = FALSE;
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
SafeMemFree(pszCntType);
|
|
SafeMemFree(pszSubType);
|
|
}
|
|
|
|
// Raid-63402: OE: cc: mail problems with OE
|
|
// Empty file extension ?
|
|
else if (NULL == pszExt || L'\0' == *pszExt)
|
|
{
|
|
// Generate a new filename
|
|
CHECKHR(hr = pContainer->_HrGenerateFileName(pszFileName, dwFlags, pValue));
|
|
|
|
// Done
|
|
fUseProperty = FALSE;
|
|
}
|
|
|
|
// Return per user request
|
|
if (fUseProperty)
|
|
{
|
|
// Use the property
|
|
CHECKHR(hr = pContainer->GetProp(pSymbol, dwFlags, pValue));
|
|
}
|
|
|
|
// Cleanup the file name
|
|
if (!ISFLAGSET(dwFlags, PDF_ENCODED))
|
|
MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszFileName);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_GENFNAME
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_GENFNAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPERTY pProperty;
|
|
LPSTR pszDefExt=NULL,
|
|
pszData=NULL,
|
|
pszFree=NULL,
|
|
pszSuggest=NULL;
|
|
LPCSTR pszCntType=NULL;
|
|
MIMEVARIANT rSource;
|
|
|
|
// Handle Dispatch Type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_POSTGETPROP:
|
|
if (!ISFLAGSET(dwFlags, PDF_ENCODED))
|
|
MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
// Try to just get the normal filename
|
|
if (SUCCEEDED(TRIGGER_ATT_FILENAME(pContainer, IST_GETDEFAULT, dwFlags, pValue, NULL)))
|
|
goto exit;
|
|
|
|
// Call back into the container
|
|
CHECKHR(hr = pContainer->_HrGenerateFileName(NULL, dwFlags, pValue));
|
|
|
|
// Cleanup the file name
|
|
if (!ISFLAGSET(dwFlags, PDF_ENCODED))
|
|
MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszData);
|
|
SafeMemFree(pszFree);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_NORMSUBJ
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_NORMSUBJ(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MIMEVARIANT rSubject;
|
|
MIMEVARIANT rNormal;
|
|
LPSTR pszNormal,
|
|
pszFree=NULL;
|
|
LPWSTR pszNormalW,
|
|
pszFreeW=NULL;
|
|
ULONG i=0,
|
|
cch=0;
|
|
LPPROPERTY pSubject;
|
|
|
|
// Handle Dispatch Type
|
|
if (IST_GETDEFAULT == tyTrigger)
|
|
{
|
|
// Get Subject
|
|
pSubject = pContainer->m_prgIndex[PID_HDR_SUBJECT];
|
|
|
|
// No Data
|
|
if (NULL == pSubject)
|
|
{
|
|
hr = MIME_E_NO_DATA;
|
|
goto exit;
|
|
}
|
|
|
|
switch (pValue->type)
|
|
{
|
|
case MVT_STRINGA:
|
|
{
|
|
// Set Subject Type
|
|
rSubject.type = MVT_STRINGA;
|
|
|
|
// Return per user request
|
|
CHECKHR(hr = pContainer->HrConvertVariant(pSubject, CVF_NOALLOC, &rSubject));
|
|
|
|
// Set Normal subject
|
|
pszFree = rSubject.fCopy ? NULL : rSubject.rStringA.pszVal;
|
|
pszNormal = rSubject.rStringA.pszVal;
|
|
|
|
// Less than 5 "xxx: "
|
|
if (rSubject.rStringA.cchVal >= 4)
|
|
{
|
|
// 1, 2, 3, 4 spaces followed by a ':' then a space
|
|
while (cch < 7 && i < rSubject.rStringA.cchVal)
|
|
{
|
|
// Skip Lead Bytes
|
|
if (IsDBCSLeadByte(rSubject.rStringA.pszVal[i]))
|
|
{
|
|
i++;
|
|
cch++;
|
|
}
|
|
|
|
// Colon
|
|
else if (':' == rSubject.rStringA.pszVal[i])
|
|
{
|
|
if (i+1 >= rSubject.rStringA.cchVal)
|
|
{
|
|
i++;
|
|
pszNormal = (LPSTR)(rSubject.rStringA.pszVal + i);
|
|
break;
|
|
}
|
|
|
|
else if (cch <= 4 && ' ' == rSubject.rStringA.pszVal[i+1])
|
|
{
|
|
i++;
|
|
pszNormal = PszSkipWhiteA((LPSTR)(rSubject.rStringA.pszVal + i));
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// Next Character
|
|
i++;
|
|
cch++;
|
|
}
|
|
}
|
|
|
|
// Reset Source
|
|
if (pszNormal != rSubject.rStringA.pszVal)
|
|
{
|
|
rSubject.rStringA.pszVal = pszNormal;
|
|
rSubject.rStringA.cchVal = lstrlen(pszNormal);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MVT_STRINGW:
|
|
{
|
|
// Set Subject Type
|
|
rSubject.type = MVT_STRINGW;
|
|
|
|
// Return per user request
|
|
CHECKHR(hr = pContainer->HrConvertVariant(pSubject, CVF_NOALLOC, &rSubject));
|
|
|
|
// Set Normal subject
|
|
pszFreeW = rSubject.fCopy ? NULL : rSubject.rStringW.pszVal;
|
|
pszNormalW = rSubject.rStringW.pszVal;
|
|
|
|
// Less than 5 "xxx: "
|
|
if (rSubject.rStringW.cchVal >= 4)
|
|
{
|
|
// 1, 2, or 3 spaces followed by a ':' then a space
|
|
while (cch < 7 && i < rSubject.rStringW.cchVal)
|
|
{
|
|
// Colon
|
|
if (L':' == rSubject.rStringW.pszVal[i])
|
|
{
|
|
if (i+1 >= rSubject.rStringW.cchVal)
|
|
{
|
|
i++;
|
|
pszNormalW = (LPWSTR)(rSubject.rStringW.pszVal + i);
|
|
break;
|
|
}
|
|
|
|
else if (cch <= 4 && L' ' == rSubject.rStringW.pszVal[i+1])
|
|
{
|
|
i++;
|
|
pszNormalW = PszSkipWhiteW((LPWSTR)(rSubject.rStringW.pszVal + i));
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// Next Character
|
|
i++;
|
|
cch++;
|
|
}
|
|
}
|
|
|
|
// Reset Source
|
|
if (pszNormalW != rSubject.rStringW.pszVal)
|
|
{
|
|
rSubject.rStringW.pszVal = pszNormalW;
|
|
rSubject.rStringW.cchVal = lstrlenW(pszNormalW);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
AssertSz(FALSE, "Didn't prepare for this type!!!");
|
|
break;
|
|
}
|
|
|
|
// Return per user request
|
|
CHECKHR(hr = pContainer->HrConvertVariant(pSubject->pSymbol, pSubject->pCharset, IET_DECODED, dwFlags, 0, &rSubject, pValue));
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszFree);
|
|
SafeMemFree(pszFreeW);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_HDR_SUBJECT
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_HDR_SUBJECT(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Handle Dispatch type
|
|
if (IST_DELETEPROP == tyTrigger)
|
|
pContainer->DeleteProp(SYM_ATT_NORMSUBJ);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_HDR_CNTTYPE
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_HDR_CNTTYPE(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CStringParser cString;
|
|
CHAR chToken;
|
|
MIMEVARIANT rValue;
|
|
LPSTR pszCntType=NULL;
|
|
|
|
// Invalid Arg
|
|
Assert(pContainer);
|
|
|
|
// Handle Dispatch type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_DELETEPROP:
|
|
pContainer->DeleteProp(SYM_ATT_PRITYPE);
|
|
pContainer->DeleteProp(SYM_ATT_SUBTYPE);
|
|
break;
|
|
|
|
case IST_POSTSETPROP:
|
|
// If not generated from corresponding atributes
|
|
if (pContainer->_HrIsTriggerCaller(PID_ATT_PRITYPE, IST_POSTSETPROP) == S_OK ||
|
|
pContainer->_HrIsTriggerCaller(PID_ATT_SUBTYPE, IST_POSTSETPROP) == S_OK)
|
|
goto exit;
|
|
|
|
// Validate the Variant
|
|
if (ISSTRINGA(pValue))
|
|
{
|
|
// Locals
|
|
CHAR szPriType[255];
|
|
|
|
// Set the Members
|
|
cString.Init(pValue->rStringA.pszVal, pValue->rStringA.cchVal, PSF_NOTRAILWS | PSF_NOCOMMENTS);
|
|
|
|
// Set Parse Tokens
|
|
chToken = cString.ChParse("/");
|
|
if ('\0' == chToken && 0 == cString.CchValue())
|
|
goto exit;
|
|
|
|
// Setup the Variant
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = (LPSTR)cString.PszValue();
|
|
rValue.rStringA.cchVal = cString.CchValue();
|
|
|
|
// Save Primary Type
|
|
StrCpyN(szPriType, rValue.rStringA.pszVal, ARRAYSIZE(szPriType));
|
|
|
|
// Add New attribute...
|
|
CHECKHR(hr = pContainer->SetProp(SYM_ATT_PRITYPE, 0, &rValue));
|
|
|
|
// Raid-52462: outlook express: mail with bad content type header comes in as an attachment
|
|
// Seek end of sub content-type
|
|
chToken = cString.ChParse(" ;");
|
|
if (0 == cString.CchValue())
|
|
{
|
|
// Locals
|
|
LPCSTR pszSubType = PszDefaultSubType(szPriType);
|
|
ULONG cchCntType;
|
|
|
|
// Set Default SubType
|
|
CHECKHR(hr = pContainer->SetProp(SYM_ATT_SUBTYPE, pszSubType));
|
|
|
|
// Build ContentType
|
|
DWORD cchSize = (lstrlen(szPriType) + lstrlen(pszSubType) + 2);
|
|
CHECKALLOC(pszCntType = PszAllocA(cchSize));
|
|
|
|
// Format the ContentType
|
|
cchCntType = wnsprintf(pszCntType, cchSize, "%s/%s", szPriType, pszSubType);
|
|
|
|
// Setup a variant
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = (LPSTR)pszCntType;
|
|
rValue.rStringA.cchVal = cchCntType;
|
|
|
|
// Store the variant data
|
|
Assert(pContainer->m_prgIndex[PID_HDR_CNTTYPE]);
|
|
CHECKHR(hr = pContainer->_HrStoreVariantValue(pContainer->m_prgIndex[PID_HDR_CNTTYPE], 0, &rValue));
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Setup the Variant
|
|
rValue.rStringA.pszVal = (LPSTR)cString.PszValue();
|
|
rValue.rStringA.cchVal = cString.CchValue();
|
|
|
|
// Add New attribute...
|
|
CHECKHR(hr = pContainer->SetProp(SYM_ATT_SUBTYPE, 0, &rValue));
|
|
|
|
// We should be done
|
|
Assert(';' == chToken || '(' == chToken || '\0' == chToken || ' ' == chToken);
|
|
}
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = (LPSTR)STR_MIME_TEXT_PLAIN;
|
|
rValue.rStringA.cchVal = lstrlen(STR_MIME_TEXT_PLAIN);
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTTYPE, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszCntType);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_PRITYPE
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_PRITYPE(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPERTY pSubType;
|
|
LPSTR pszSubType;
|
|
ULONG cchSubType;
|
|
MIMEVARIANT rValue;
|
|
|
|
// Define a Stack String
|
|
STACKSTRING_DEFINE(rContentType, 255);
|
|
|
|
// Handle Dispatch Type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_POSTSETPROP:
|
|
{
|
|
// If inside content type dispatch setprop
|
|
if (pContainer->_HrIsTriggerCaller(PID_HDR_CNTTYPE, IST_POSTSETPROP) == S_OK)
|
|
goto exit;
|
|
|
|
// Asser Type
|
|
Assert(pValue && ISSTRINGA(pValue));
|
|
|
|
// Get pCntType
|
|
pSubType = pContainer->m_prgIndex[PID_ATT_SUBTYPE];
|
|
|
|
// Is the subtype set yet
|
|
if (pSubType)
|
|
{
|
|
Assert(ISSTRINGA(&pSubType->rValue));
|
|
pszSubType = pSubType->rValue.rStringA.pszVal;
|
|
cchSubType = pSubType->rValue.rStringA.cchVal;
|
|
}
|
|
else
|
|
{
|
|
pszSubType = (LPSTR)STR_SUB_PLAIN;
|
|
cchSubType = lstrlen(STR_SUB_PLAIN);
|
|
}
|
|
|
|
// Make Sure the stack string can hold the data
|
|
DWORD cchSize = (cchSubType + pValue->rStringA.cchVal + 2);
|
|
STACKSTRING_SETSIZE(rContentType, cchSize);
|
|
|
|
// Init rValue
|
|
ZeroMemory(&rValue, sizeof(MIMEVARIANT));
|
|
|
|
// Format the content type
|
|
rValue.rStringA.cchVal = wnsprintf(rContentType.pszVal, cchSize, "%s/%s", pValue->rStringA.pszVal, pszSubType);
|
|
|
|
// Setup the value
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = rContentType.pszVal;
|
|
|
|
// SetProp
|
|
CHECKHR(hr = pContainer->SetProp(SYM_HDR_CNTTYPE, 0, &rValue));
|
|
}
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = (LPSTR)STR_CNT_TEXT;
|
|
rValue.rStringA.cchVal = lstrlen(STR_CNT_TEXT);
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTTYPE, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
STACKSTRING_FREE(rContentType);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_SUBTYPE
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_SUBTYPE(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPERTY pPriType;
|
|
LPSTR pszPriType;
|
|
ULONG cchPriType;
|
|
MIMEVARIANT rValue;
|
|
|
|
// Define a Stack String
|
|
STACKSTRING_DEFINE(rContentType, 255);
|
|
|
|
// Handle Dispatch Type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_POSTSETPROP:
|
|
{
|
|
// If inside content type dispatch setprop
|
|
if (pContainer->_HrIsTriggerCaller(PID_HDR_CNTTYPE, IST_POSTSETPROP) == S_OK)
|
|
goto exit;
|
|
|
|
// Asser Type
|
|
Assert(pValue && ISSTRINGA(pValue));
|
|
|
|
// Get pCntType
|
|
pPriType = pContainer->m_prgIndex[PID_ATT_PRITYPE];
|
|
|
|
// Is the subtype set yet
|
|
if (pPriType)
|
|
{
|
|
Assert(ISSTRINGA(&pPriType->rValue));
|
|
pszPriType = pPriType->rValue.rStringA.pszVal;
|
|
cchPriType = pPriType->rValue.rStringA.cchVal;
|
|
}
|
|
else
|
|
{
|
|
pszPriType = (LPSTR)STR_CNT_TEXT;
|
|
cchPriType = lstrlen(STR_CNT_TEXT);
|
|
}
|
|
|
|
// Make Sure the stack string can hold the data
|
|
DWORD cchSize = (cchPriType + pValue->rStringA.cchVal + 2);
|
|
STACKSTRING_SETSIZE(rContentType, cchSize);
|
|
|
|
// Init rValue
|
|
ZeroMemory(&rValue, sizeof(MIMEVARIANT));
|
|
|
|
// Format the content type
|
|
rValue.rStringA.cchVal = wnsprintf(rContentType.pszVal, cchSize, "%s/%s", pszPriType, pValue->rStringA.pszVal);
|
|
|
|
// Setup the value
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = rContentType.pszVal;
|
|
|
|
// SetProp
|
|
CHECKHR(hr = pContainer->SetProp(SYM_HDR_CNTTYPE, 0, &rValue));
|
|
}
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
rValue.type = MVT_STRINGA;
|
|
rValue.rStringA.pszVal = (LPSTR)STR_SUB_PLAIN;
|
|
rValue.rStringA.cchVal = lstrlen(STR_SUB_PLAIN);
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTTYPE, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
STACKSTRING_FREE(rContentType);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_HDR_CNTXFER
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_HDR_CNTXFER(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MIMEVARIANT rSource;
|
|
|
|
// Handle Dispatch Type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_GETDEFAULT:
|
|
rSource.type = MVT_STRINGA;
|
|
rSource.rStringA.pszVal = (LPSTR)STR_ENC_7BIT;
|
|
rSource.rStringA.cchVal = lstrlen(STR_ENC_7BIT);
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTXFER, NULL, IET_DECODED, dwFlags, 0, &rSource, pValue));
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_PAR_NAME
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_PAR_NAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Handle Dispatch type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_POSTSETPROP:
|
|
if (pContainer->_HrIsTriggerCaller(PID_ATT_FILENAME, IST_POSTSETPROP) == S_FALSE)
|
|
pContainer->SetProp(SYM_ATT_FILENAME, dwFlags, pValue);
|
|
break;
|
|
}
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_PAR_FILENAME
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_PAR_FILENAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Handle Dispatch type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_DELETEPROP:
|
|
if (pContainer->_HrIsTriggerCaller(PID_ATT_FILENAME, IST_DELETEPROP) == S_FALSE)
|
|
pContainer->DeleteProp(SYM_ATT_FILENAME);
|
|
break;
|
|
|
|
case IST_POSTSETPROP:
|
|
if (pContainer->_HrIsTriggerCaller(PID_ATT_FILENAME, IST_POSTSETPROP) == S_FALSE)
|
|
pContainer->SetProp(SYM_ATT_FILENAME, dwFlags, pValue);
|
|
break;
|
|
}
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_SENTTIME
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_SENTTIME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Handle Dispatch type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_DELETEPROP:
|
|
pContainer->DeleteProp(SYM_HDR_DATE);
|
|
break;
|
|
|
|
case IST_POSTSETPROP:
|
|
pContainer->SetProp(SYM_HDR_DATE, dwFlags, pValue);
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
// Raid-39471-Mail: Date showing as jan 01, 1601 in readnote for attached message
|
|
if (FAILED(pContainer->GetProp(SYM_HDR_DATE, dwFlags, pValue)))
|
|
{
|
|
// Get Known Property
|
|
LPPROPERTY pProperty = pContainer->m_prgIndex[PID_HDR_RECEIVED];
|
|
if (pProperty && ISSTRINGA(&pProperty->rValue))
|
|
{
|
|
// Try Getting Sent Time
|
|
CHECKHR(hr = pContainer->GetProp(SYM_ATT_RECVTIME, dwFlags, pValue));
|
|
}
|
|
else
|
|
{
|
|
// Locals
|
|
SYSTEMTIME st;
|
|
MIMEVARIANT rValue;
|
|
|
|
// Setup rValue
|
|
rValue.type = MVT_VARIANT;
|
|
rValue.rVariant.vt = VT_FILETIME;
|
|
|
|
// Get current systemtime
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &rValue.rVariant.filetime);
|
|
|
|
// If the Conversion Fails, get the current time
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_SENTTIME, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_RECVTIME
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_RECVTIME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MIMEVARIANT rSource;
|
|
LPMIMEVARIANT pSource;
|
|
LPPROPERTY pProperty;
|
|
|
|
// Handle Dispatch Type
|
|
switch(tyTrigger)
|
|
{
|
|
case IST_DELETEPROP:
|
|
pContainer->DeleteProp(SYM_HDR_RECEIVED);
|
|
break;
|
|
|
|
case IST_GETDEFAULT:
|
|
// Get Known Property
|
|
pProperty = pContainer->m_prgIndex[PID_HDR_RECEIVED];
|
|
if (NULL == pProperty || !ISSTRINGA(&pProperty->rValue))
|
|
{
|
|
// Try Getting Sent Time
|
|
MimeOleGetSentTime(pContainer, dwFlags, pValue);
|
|
}
|
|
|
|
// Otherwise, try to convert it
|
|
else
|
|
{
|
|
// If StringA
|
|
if (MVT_STRINGA == pProperty->rValue.type)
|
|
{
|
|
// Find the first header which has a semi-colon in it
|
|
while(1)
|
|
{
|
|
// Seek to last colon
|
|
LPSTR psz = pProperty->rValue.rStringA.pszVal;
|
|
int i;
|
|
for (i = 0; psz[i] ; i++);
|
|
rSource.rStringA.pszVal = psz + i; // set to end of string
|
|
for (; i >= 0 ; i--)
|
|
{
|
|
if (psz[i] == ';')
|
|
{
|
|
rSource.rStringA.pszVal = psz + i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ('\0' == *rSource.rStringA.pszVal)
|
|
{
|
|
// No more values
|
|
if (NULL == pProperty->pNextValue)
|
|
{
|
|
// Try Getting Sent Time
|
|
MimeOleGetSentTime(pContainer, dwFlags, pValue);
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Goto next
|
|
pProperty = pProperty->pNextValue;
|
|
}
|
|
|
|
// Otherwise, we must have a good property
|
|
else
|
|
break;
|
|
}
|
|
|
|
// Step over ';
|
|
rSource.rStringA.pszVal++;
|
|
|
|
// Setup Source
|
|
rSource.type = MVT_STRINGA;
|
|
rSource.rStringA.cchVal = lstrlen(rSource.rStringA.pszVal);
|
|
pSource = &rSource;
|
|
}
|
|
|
|
// Otherwise, just try to conver the current property data
|
|
else
|
|
pSource = &pProperty->rValue;
|
|
|
|
// If the Conversion Fails, get the current time
|
|
if (FAILED(pContainer->HrConvertVariant(SYM_ATT_RECVTIME, NULL, IET_DECODED, dwFlags, 0, pSource, pValue)))
|
|
{
|
|
// Try Getting Sent Time
|
|
MimeOleGetSentTime(pContainer, dwFlags, pValue);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimePropertyContainer::TRIGGER_ATT_PRIORITY
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimePropertyContainer::TRIGGER_ATT_PRIORITY(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
|
|
DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
MIMEVARIANT rSource;
|
|
PROPVARIANT rVariant;
|
|
LPMIMEVARIANT pSource;
|
|
LPPROPERTY pProperty;
|
|
|
|
// Handle Dispatch type
|
|
switch(tyTrigger)
|
|
{
|
|
// IST_VARIANT_TO_STRINGA
|
|
case IST_VARIANT_TO_STRINGA:
|
|
Assert(pValue && pDest && MVT_VARIANT == pValue->type && MVT_STRINGA == pDest->type);
|
|
if (VT_UI4 != pValue->rVariant.vt)
|
|
{
|
|
hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
|
|
goto exit;
|
|
}
|
|
|
|
switch(pValue->rVariant.ulVal)
|
|
{
|
|
// IMSG_PRI_LOW
|
|
case IMSG_PRI_LOW:
|
|
pDest->rStringA.pszVal = (LPSTR)STR_PRI_MS_LOW;
|
|
pDest->rStringA.cchVal = lstrlen(STR_PRI_MS_LOW);
|
|
break;
|
|
|
|
// IMSG_PRI_HIGH
|
|
case IMSG_PRI_HIGH:
|
|
pDest->rStringA.pszVal = (LPSTR)STR_PRI_MS_HIGH;
|
|
pDest->rStringA.cchVal = lstrlen(STR_PRI_MS_HIGH);
|
|
break;
|
|
|
|
// IMSG_PRI_NORMAL
|
|
default:
|
|
case IMSG_PRI_NORMAL:
|
|
pDest->rStringA.pszVal = (LPSTR)STR_PRI_MS_NORMAL;
|
|
pDest->rStringA.cchVal = lstrlen(STR_PRI_MS_NORMAL);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// IST_VARIANT_TO_STRINGW
|
|
case IST_VARIANT_TO_STRINGW:
|
|
Assert(pValue && pDest && MVT_VARIANT == pValue->type && MVT_STRINGW == pDest->type);
|
|
if (VT_UI4 != pValue->rVariant.vt)
|
|
{
|
|
hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
|
|
goto exit;
|
|
}
|
|
|
|
switch(pValue->rVariant.ulVal)
|
|
{
|
|
// IMSG_PRI_LOW
|
|
case IMSG_PRI_LOW:
|
|
#ifndef WIN16
|
|
pDest->rStringW.pszVal = L"Low";
|
|
#else
|
|
pDest->rStringW.pszVal = "Low";
|
|
#endif // !WIN16
|
|
pDest->rStringW.cchVal = 3;
|
|
break;
|
|
|
|
// IMSG_PRI_HIGH
|
|
case IMSG_PRI_HIGH:
|
|
#ifndef WIN16
|
|
pDest->rStringW.pszVal = L"High";
|
|
#else
|
|
pDest->rStringW.pszVal = "High";
|
|
#endif // !WIN16
|
|
pDest->rStringW.cchVal = 4;
|
|
break;
|
|
|
|
// IMSG_PRI_NORMAL
|
|
default:
|
|
case IMSG_PRI_NORMAL:
|
|
#ifndef WIN16
|
|
pDest->rStringW.pszVal = L"Normal";
|
|
#else
|
|
pDest->rStringW.pszVal = "Normal";
|
|
#endif // !WIN16
|
|
pDest->rStringW.cchVal = 6;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// IST_VARIANT_TO_VARIANT
|
|
case IST_VARIANT_TO_VARIANT:
|
|
Assert(pValue && pDest && MVT_VARIANT == pValue->type && MVT_VARIANT == pDest->type);
|
|
if (VT_UI4 != pValue->rVariant.vt && VT_UI4 != pDest->rVariant.vt)
|
|
{
|
|
hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
|
|
goto exit;
|
|
}
|
|
|
|
// Nice and Easy
|
|
pDest->rVariant.ulVal = pValue->rVariant.ulVal;
|
|
break;
|
|
|
|
// IST_STRINGA_TO_VARIANT
|
|
case IST_STRINGA_TO_VARIANT:
|
|
Assert(pValue && pDest && MVT_STRINGA == pValue->type && MVT_VARIANT == pDest->type);
|
|
if (VT_UI4 != pDest->rVariant.vt)
|
|
{
|
|
hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
|
|
goto exit;
|
|
}
|
|
|
|
// Priority From String
|
|
pDest->rVariant.ulVal = PriorityFromStringA(pValue->rStringA.pszVal);
|
|
break;
|
|
|
|
// IST_STRINGW_TO_VARIANT
|
|
case IST_STRINGW_TO_VARIANT:
|
|
Assert(pValue && pDest && MVT_STRINGW == pValue->type && MVT_VARIANT == pDest->type);
|
|
if (VT_UI4 != pDest->rVariant.vt)
|
|
{
|
|
hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
|
|
goto exit;
|
|
}
|
|
|
|
// Priority From String
|
|
pDest->rVariant.ulVal = PriorityFromStringW(pValue->rStringW.pszVal);
|
|
break;
|
|
|
|
// IST_DELETEPROP
|
|
case IST_DELETEPROP:
|
|
pContainer->DeleteProp(SYM_HDR_XPRI);
|
|
pContainer->DeleteProp(SYM_HDR_XMSPRI);
|
|
break;
|
|
|
|
// IST_POSTSETPROP
|
|
case IST_POSTSETPROP:
|
|
// Setup rSource
|
|
rSource.type = MVT_VARIANT;
|
|
rSource.rVariant.vt = VT_UI4;
|
|
|
|
// Convert to User's Variant to a Integer Priority
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_PRIORITY, NULL, IET_DECODED, 0, 0, pValue, &rSource));
|
|
|
|
// Setup rVariant
|
|
rVariant.vt = VT_LPSTR;
|
|
|
|
// Switch on priority
|
|
switch(rSource.rVariant.ulVal)
|
|
{
|
|
case IMSG_PRI_LOW:
|
|
CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XMSPRI), STR_PRI_MS_LOW));
|
|
CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XPRI), STR_PRI_LOW));
|
|
break;
|
|
|
|
case IMSG_PRI_NORMAL:
|
|
CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XMSPRI), STR_PRI_MS_NORMAL));
|
|
CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XPRI), STR_PRI_NORMAL));
|
|
break;
|
|
|
|
case IMSG_PRI_HIGH:
|
|
CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XMSPRI), STR_PRI_MS_HIGH));
|
|
CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XPRI), STR_PRI_HIGH));
|
|
break;
|
|
|
|
default:
|
|
hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
|
|
goto exit;
|
|
}
|
|
|
|
// Done
|
|
break;
|
|
|
|
// IST_GETDEFAULT
|
|
case IST_GETDEFAULT:
|
|
// Get the Priority Property
|
|
pProperty = pContainer->m_prgIndex[PID_HDR_XPRI];
|
|
if (NULL == pProperty)
|
|
pProperty = pContainer->m_prgIndex[PID_HDR_XMSPRI];
|
|
|
|
// No Data
|
|
if (NULL == pProperty)
|
|
{
|
|
rSource.type = MVT_VARIANT;
|
|
rSource.rVariant.vt = VT_UI4;
|
|
rSource.rVariant.ulVal = IMSG_PRI_NORMAL;
|
|
pSource = &rSource;
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
pSource = &pProperty->rValue;
|
|
|
|
// Convert to User's Variant
|
|
CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_PRIORITY, NULL, IET_DECODED, dwFlags, 0, pSource, pValue));
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|