|
|
/*
* imaputil.cpp * * Purpose: * Implements IMAP utility functions * * Owner: * Raych * * Copyright (C) Microsoft Corp. 1996 */
//---------------------------------------------------------------------------
// Includes
//---------------------------------------------------------------------------
#include "pch.hxx"
#include "imapute.h"
#include "storutil.h"
#include "imapsync.h"
//---------------------------------------------------------------------------
// Forward Declarations
//---------------------------------------------------------------------------
DWORD ImapUtil_ReverseSentence(LPSTR pszSentence, char cDelimiter); void ImapUtil_ReverseString(LPSTR pszStart, LPSTR pszEnd);
//---------------------------------------------------------------------------
// Module Constants
//---------------------------------------------------------------------------
const char c_szIMAP_MSG_ANSWERED[] = "Answered"; const char c_szIMAP_MSG_FLAGGED[] = "Flagged"; const char c_szIMAP_MSG_DELETED[] = "Deleted"; const char c_szIMAP_MSG_DRAFT[] = "Draft"; const char c_szIMAP_MSG_SEEN[] = "Seen"; const char c_szBACKSLASH[] = "\\";
typedef struct tagIMFToStr_LUT { IMAP_MSGFLAGS imfValue; LPCSTR pszValue; } IMFTOSTR_LUT;
const IMFTOSTR_LUT g_IMFToStringLUT[] = { {IMAP_MSG_ANSWERED, c_szIMAP_MSG_ANSWERED}, {IMAP_MSG_FLAGGED, c_szIMAP_MSG_FLAGGED}, {IMAP_MSG_DELETED, c_szIMAP_MSG_DELETED}, {IMAP_MSG_SEEN, c_szIMAP_MSG_SEEN}, {IMAP_MSG_DRAFT, c_szIMAP_MSG_DRAFT}};
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
//***************************************************************************
// Function: ImapUtil_MsgFlagsToString
//
// Purpose:
// This function converts a IMAP_MSGFLAGS register to its string
// equivalent. For instance, IMAP_MSG_SEEN is converted to "(\Seen)".
//
// Arguments:
// IMAP_MSGFLAGS imfSource [in] - IMAP_MSGFLAGS register to convert to
// string.
// LPSTR *ppszDestination [out] - the string equivalent is returned here.
// If imfSource is 0, NULL is returned here. Otherwise, a string buffer
// is returned which the caller must MemFree when he is done with it.
// DWORD *pdwLengthOfDestination [out] - the length of *ppszDestination.
// Pass in NULL if not interested.
//
// Returns:
// HRESULT indicating success or failure. Remember that it is possible
// for a successful HRESULT to be returned, even is *ppszDestination is NULL.
//***************************************************************************
HRESULT ImapUtil_MsgFlagsToString(IMAP_MSGFLAGS imfSource, LPSTR *ppszDestination, DWORD *pdwLengthOfDestination) { CByteStream bstmOutput; HRESULT hrResult; const IMFTOSTR_LUT *pCurrent; const IMFTOSTR_LUT *pLastEntry; BOOL fFirstFlag;
TraceCall("ImapUtil_MsgFlagsToString"); Assert(NULL != ppszDestination); AssertSz(0 == (imfSource & ~IMAP_MSG_ALLFLAGS), "Quit feeding me garbage.");
// Codify assumptions
Assert(IMAP_MSG_ALLFLAGS == 0x0000001F);
*ppszDestination = NULL; if (NULL != pdwLengthOfDestination) *pdwLengthOfDestination = 0;
if (0 == (imfSource & IMAP_MSG_ALLFLAGS)) return S_FALSE; // Nothing to do here!
hrResult = bstmOutput.Write("(", 1, NULL); if (FAILED(hrResult)) goto exit;
fFirstFlag = TRUE; pCurrent = g_IMFToStringLUT; pLastEntry = pCurrent + sizeof(g_IMFToStringLUT)/sizeof(IMFTOSTR_LUT) - 1; while (pCurrent <= pLastEntry) {
if (imfSource & pCurrent->imfValue) { // Prepend a space to flag, if necessary
if (FALSE == fFirstFlag) { hrResult = bstmOutput.Write(g_szSpace, 1, NULL); if (FAILED(hrResult)) goto exit; } else fFirstFlag = FALSE;
// Output the backslash
hrResult = bstmOutput.Write(c_szBACKSLASH, sizeof(c_szBACKSLASH) - 1, NULL); if (FAILED(hrResult)) goto exit;
// Output string associated with this IMAP flag
hrResult = bstmOutput.Write(pCurrent->pszValue, lstrlen(pCurrent->pszValue), NULL); if (FAILED(hrResult)) goto exit; } // if (imfSource & pCurrent->imfValue)
// Advance current pointer
pCurrent += 1; } // while
hrResult = bstmOutput.Write(")", 1, NULL); if (FAILED(hrResult)) goto exit;
hrResult = bstmOutput.HrAcquireStringA(pdwLengthOfDestination, ppszDestination, ACQ_DISPLACE);
exit: return hrResult; } // IMAPMsgFlagsToString
//***************************************************************************
// Function: ImapUtil_FolderIDToPath
//
// Purpose:
// This function takes the given FolderID and returns the full path
// (including prefix) to the folder. The caller may also choose to append
// a string to the path.
//
// Arguments:
// FolderID idFolder [in] - FolderID to convert into a full path.
// char **ppszPath [out] - a full path to idFolder is returned here.
// LPDWORD pdwPathLen [out] - if non-NULL, the length of *ppszPath is
// returned here.
// char *pcHierarchyChar [out] - the hierarchy char used to interpret
// *ppszPath is returned here.
// CFolderCache *pFldrCache [in] - a CFolderCache to use to generate
// the path.
// LPCSTR pszAppendStr [in] - this can be NULL if the caller does not need
// to append a string to the path. Otherwise, a hierarchy character is
// appended to the path and this string is appended after the HC. This
// argument is typically used to tack a wildcard to the end of the path.
// LPCSTR pszRootFldrPrefix [in] - the root folder prefix for this IMAP
// account. If this is NULL, this function will find out for itself.
//
// Returns:
// HRESULT indicating success or failure.
//***************************************************************************
HRESULT ImapUtil_FolderIDToPath(FOLDERID idServer, FOLDERID idFolder, char **ppszPath, LPDWORD pdwPathLen, char *pcHierarchyChar, IMessageStore *pFldrCache, LPCSTR pszAppendStr, LPCSTR pszRootFldrPrefix) { FOLDERINFO fiPath; HRESULT hrResult; CByteStream bstmPath; DWORD dwLengthOfPath; LPSTR pszEnd; char szRootFldrPrefix[MAX_PATH]; char szAccount[CCHMAX_ACCOUNT_NAME]; BOOL fAppendStrHC = FALSE, fFreeFldrInfo = FALSE; BOOL fSpecialFldr = FALSE; DWORD dwLen; TraceCall("ImapUtil_FolderIDToPath"); if (FOLDERID_INVALID == idFolder || FOLDERID_INVALID == idServer) { hrResult = TraceResult(E_INVALIDARG); goto exit; }
// Build full path to current folder in reverse (leaf->root)
// Limited buffer overflow risk since user input limited to MAX_PATH
// Start off with target folder (leaf) and return its HC if so requested
hrResult = pFldrCache->GetFolderInfo(idFolder, &fiPath); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
fFreeFldrInfo = TRUE;
GetFolderAccountId(&fiPath, szAccount, ARRAYSIZE(szAccount));
if (NULL != pcHierarchyChar) { Assert((BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy); *pcHierarchyChar = (char) fiPath.bHierarchy; }
// Append anything the user asked us to (will be at end of str after reversal)
if (NULL != pszAppendStr) { char szBuf[MAX_PATH + 1];
// First, have to reverse the append string itself, in case it contains HC's
Assert(lstrlen(pszAppendStr) < ARRAYSIZE(szBuf)); StrCpyN(szBuf, pszAppendStr, ARRAYSIZE(szBuf)); dwLen = ImapUtil_ReverseSentence(szBuf, fiPath.bHierarchy);
hrResult = bstmPath.Write(szBuf, dwLen, NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; } fAppendStrHC = TRUE; }
// Check if user gave us a root folder prefix: otherwise we need to load it ourselves
if (NULL == pszRootFldrPrefix) { ImapUtil_LoadRootFldrPrefix(szAccount, szRootFldrPrefix, sizeof(szRootFldrPrefix)); pszRootFldrPrefix = szRootFldrPrefix; } else // Copy to our buffer because we're going to reverse the RFP
StrCpyN(szRootFldrPrefix, pszRootFldrPrefix, ARRAYSIZE(szRootFldrPrefix));
// Proceed to root
while (FALSE == fSpecialFldr && idServer != fiPath.idFolder) { LPSTR pszFolderName;
Assert(FOLDERID_INVALID != fiPath.idFolder); Assert(FOLDERID_ROOT != fiPath.idParent);
if (fAppendStrHC) { // Separate append str from path with HC
Assert((BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy); hrResult = bstmPath.Write(&fiPath.bHierarchy, sizeof(fiPath.bHierarchy), NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; } fAppendStrHC = FALSE; }
// Expand folder name to full path if this is a special folder
if (FOLDER_NOTSPECIAL != fiPath.tySpecial) { char szSpecialFldrPath[MAX_PATH * 2 + 2]; // Room for HC and null-term
fSpecialFldr = TRUE; hrResult = ImapUtil_SpecialFldrTypeToPath(szAccount, fiPath.tySpecial, szRootFldrPrefix, fiPath.bHierarchy, szSpecialFldrPath, sizeof(szSpecialFldrPath)); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
// Reverse special folder path so we can append it. It will be reversed back to normal
// There should be no trailing HC's
//Assert((BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy);
dwLen = ImapUtil_ReverseSentence(szSpecialFldrPath, fiPath.bHierarchy); Assert(dwLen == 0 || fiPath.bHierarchy != *(CharPrev(szSpecialFldrPath, szSpecialFldrPath + dwLen))); pszFolderName = szSpecialFldrPath; } else pszFolderName = fiPath.pszName;
// Write folder name to stream
hrResult = bstmPath.Write(pszFolderName, lstrlen(pszFolderName), NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
//Assert((BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy);
hrResult = bstmPath.Write(&fiPath.bHierarchy, sizeof(fiPath.bHierarchy), NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
pFldrCache->FreeRecord(&fiPath); fFreeFldrInfo = FALSE;
hrResult = pFldrCache->GetFolderInfo(fiPath.idParent, &fiPath); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; } fFreeFldrInfo = TRUE;
} // while
if (FALSE == fSpecialFldr && '\0' != szRootFldrPrefix[0]) { if (fAppendStrHC) { // Separate append str from path with HC
Assert((BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy); hrResult = bstmPath.Write(&fiPath.bHierarchy, sizeof(fiPath.bHierarchy), NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; } fAppendStrHC = FALSE; }
// Reverse root folder path so we can append it. It will be reversed back to normal
// There should be no trailing HC's (ImapUtil_LoadRootFldrPrefix guarantees this)
Assert((BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy); dwLen = ImapUtil_ReverseSentence(szRootFldrPrefix, fiPath.bHierarchy); Assert(dwLen == 0 || fiPath.bHierarchy != *(CharPrev(szRootFldrPrefix, szRootFldrPrefix + dwLen)));
hrResult = bstmPath.Write(szRootFldrPrefix, dwLen, NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; } }
// OK, path won't get any larger. Acquire mem buffer so we can reverse it
hrResult = bstmPath.HrAcquireStringA(&dwLengthOfPath, ppszPath, ACQ_DISPLACE); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
// Blow away trailing hierarchy character or it becomes leading HC
pszEnd = CharPrev(*ppszPath, *ppszPath + dwLengthOfPath); Assert('%' == *pszEnd || (BYTE)INVALID_HIERARCHY_CHAR != fiPath.bHierarchy); if (*pszEnd == (char) fiPath.bHierarchy) *pszEnd = '\0';
// Reverse the 'sentence' (HC is delimiter) to get path
dwLen = ImapUtil_ReverseSentence(*ppszPath, fiPath.bHierarchy); if (NULL != pdwPathLen) *pdwPathLen = dwLen;
exit: if (fFreeFldrInfo) pFldrCache->FreeRecord(&fiPath);
return hrResult; } // ImapUtil_FolderIDToPath
//***************************************************************************
// Function: ImapUtil_ReverseSentence
//
// Purpose:
// This function reverses the words in the given sentence, where words are
// separated by the given delimiter. For instance, "one two three" with space
// as the delimiter is returned as "three two one".
//
// Arguments:
// LPSTR pszSentence [in/out] - the sentence to be reversed. The sentence
// is reversed in place.
// char cDelimiter [in] - the character separating the words in the
// sentence.
//
// Returns:
// DWORD indicating length of reversed sentence.
//***************************************************************************
DWORD ImapUtil_ReverseSentence(LPSTR pszSentence, char cDelimiter) { LPSTR pszStartWord, psz; Assert(NULL != pszSentence); BOOL fFoundDelimiter; BOOL fSkipByte = FALSE;
TraceCall("ImapUtil_ReverseSentence");
if ('\0' == cDelimiter) return 0; // Nothing to reverse
// Check if first character is a delimiter
if (cDelimiter != *pszSentence) { pszStartWord = pszSentence; psz = pszSentence; fFoundDelimiter = FALSE; } else { // Skip first delimiter char (it will be reversed at end of fn)
pszStartWord = pszSentence + 1; psz = pszSentence + 1; fFoundDelimiter = TRUE; }
// First, reverse each word in the sentence
while (1) { char cCurrent = *psz;
if (fSkipByte) { fSkipByte = FALSE; if ('\0' != cCurrent) psz += 1; continue; }
if (cDelimiter == cCurrent || '\0' == cCurrent) { // We've gone past a word! Reverse it!
ImapUtil_ReverseString(pszStartWord, psz - 1); pszStartWord = psz + 1; // Set us up for next word
fFoundDelimiter = TRUE; }
if ('\0' == cCurrent) break; else { if (IsDBCSLeadByteEx(GetACP(), cCurrent)) fSkipByte = TRUE; psz += 1; } } // while (1)
// Now reverse the entire sentence string (psz points to null-terminator)
if (fFoundDelimiter && psz > pszSentence) ImapUtil_ReverseString(pszSentence, psz - 1);
return (DWORD) (psz - pszSentence); } // ImapUtil_ReverseSentence
//***************************************************************************
// Function: ImapUtil_ReverseString
//
// Purpose:
// This function reverses the given string in-place
//
// Arguments:
// LPSTR pszStart [in/out] - start of the string to be reversed.
// LPSTR pszEnd [in/out] - the end of the string to be reversed.
//***************************************************************************
void ImapUtil_ReverseString(LPSTR pszStart, LPSTR pszEnd) { TraceCall("ImapUtil_ReverseString"); Assert(NULL != pszStart); Assert(NULL != pszEnd);
while (pszStart < pszEnd) { char cTemp;
// Swap characters
cTemp = *pszStart; *pszStart = *pszEnd; *pszEnd = cTemp;
// Advance pointers
pszStart += 1; pszEnd -= 1; } // while
} // ImapUtil_ReverseString
//***************************************************************************
// Function: ImapUtil_SpecialFldrTypeToPath
//
// Purpose:
// This function returns the path for the given special folder type.
//
// Arguments:
// LPSTR pszAccountID [in] - ID of IMAP account where special folder resides.
// SPECIALFOLDER sfType [in] - the special folder whose path should be returned
// (eg, FOLDER_SENT).
// LPCSTR pszRootFldrPrefix [in] - the root folder prefix for this IMAP
// account. If this is NULL, this function will find out for itself.
// LPSTR pszPath [out] - pointer to a buffer to receieve the special folder
// path.
// DWORD dwSizeOfPath [in] - size of buffer pointed to by pszPath.
//
// Returns:
// HRESULT indicating success or failure. This can include:
//
// STORE_E_NOREMOTESPECIALFLDR: indicates the given special folder has
// been disabled by the user for this IMAP server.
//***************************************************************************
HRESULT ImapUtil_SpecialFldrTypeToPath(LPCSTR pszAccountID, SPECIALFOLDER sfType, LPSTR pszRootFldrPrefix, char cHierarchyChar, LPSTR pszPath, DWORD dwSizeOfPath) { HRESULT hrResult = E_FAIL; IImnAccount *pAcct = NULL; DWORD dw; int iLen;
TraceCall("ImapUtil_SpecialFldrTypeToPath"); AssertSz(dwSizeOfPath >= MAX_PATH * 2 + 2, "RFP + Special Folder Path = Big Buffer, Dude"); // Room for HC, null-term
*pszPath = '\0'; // Initialize
switch (sfType) { case FOLDER_INBOX: StrCpyN(pszPath, c_szINBOX, dwSizeOfPath); hrResult = S_OK; break;
case FOLDER_SENT: case FOLDER_DRAFT: Assert(g_pAcctMan); if (g_pAcctMan) { hrResult = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccountID, &pAcct); } if (FAILED(hrResult)) break;
hrResult = pAcct->GetPropDw(AP_IMAP_SVRSPECIALFLDRS, &dw); if (FAILED(hrResult)) break; else if (FALSE == dw) { hrResult = STORE_E_NOREMOTESPECIALFLDR; break; }
// First prepend the root folder prefix
// Check if user gave us a root folder prefix: otherwise we need to load it ourselves
if (NULL == pszRootFldrPrefix) ImapUtil_LoadRootFldrPrefix(pszAccountID, pszPath, dwSizeOfPath); else StrCpyN(pszPath, pszRootFldrPrefix, dwSizeOfPath);
iLen = lstrlen(pszPath); if (iLen > 0 && (DWORD)iLen + 1 < dwSizeOfPath) { pszPath[iLen] = cHierarchyChar; iLen += 1; pszPath[iLen] = '\0'; }
hrResult = pAcct->GetPropSz(FOLDER_SENT == sfType ? AP_IMAP_SENTITEMSFLDR : AP_IMAP_DRAFTSFLDR, pszPath + iLen, dwSizeOfPath - iLen); break;
case FOLDER_DELETED: case FOLDER_ERRORS: case FOLDER_JUNK: case FOLDER_MSNPROMO: case FOLDER_OUTBOX: case FOLDER_BULKMAIL: hrResult = STORE_E_NOREMOTESPECIALFLDR; break;
default: AssertSz(FALSE, "Invalid special folder type!"); hrResult = E_INVALIDARG; break; } // switch (sfType)
if (NULL != pAcct) pAcct->Release();
// Check for blank path
if (SUCCEEDED(hrResult) && '\0' == *pszPath) hrResult = STORE_E_NOREMOTESPECIALFLDR; return hrResult; } // ImapUtil_SpecialFldrTypeToPath
//***************************************************************************
// Function: ImapUtil_LoadRootFldrPrefix
//
// Purpose:
// This function loads the "Root Folder Path" option from the account
// manager. The Root Folder Path (prefix) identifies the parent of all of
// the user's folders. Thus, the Root Folder Path forms a prefix for all
// mailboxes which are not INBOX.
//
// Arguments:
// LPCTSTR pszAccountID [in] - ID of the account
// LPSTR pszRootFolderPrefix [out] - destination for Root Folder Path
// DWORD dwSizeofPrefixBuffer [in] - size of buffer pointed to by
// pszRootFolderPrefix.
//***************************************************************************
void ImapUtil_LoadRootFldrPrefix(LPCTSTR pszAccountID, LPSTR pszRootFolderPrefix, DWORD dwSizeofPrefixBuffer) { IImnAccount *pAcct = NULL; HRESULT hrResult = E_UNEXPECTED; LPSTR pLastChar;
Assert(g_pAcctMan); Assert(NULL != pszAccountID); Assert(NULL != pszRootFolderPrefix); Assert(0 != dwSizeofPrefixBuffer); if (!g_pAcctMan) return;
// Initialize variables
pAcct = NULL; pszRootFolderPrefix[0] = '\0'; // If we can't find a prefix, default to NONE
// Get the prefix from the account manager
hrResult = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccountID, &pAcct); if (FAILED(hrResult)) goto exit;
hrResult = pAcct->GetPropSz(AP_IMAP_ROOT_FOLDER, pszRootFolderPrefix, dwSizeofPrefixBuffer); if (FAILED(hrResult)) goto exit;
// OK, we now have the root folder prefix. Strip trailing hierarchy chars,
// since we probably don't know server HC when we try to list the prefix
pLastChar = CharPrev(pszRootFolderPrefix, pszRootFolderPrefix + lstrlen(pszRootFolderPrefix)); while (pLastChar >= pszRootFolderPrefix && ('/' == *pLastChar || '\\' == *pLastChar || '.' == *pLastChar)) { *pLastChar = '\0'; // Bye-bye, potential hierarchy char
pLastChar = CharPrev(pszRootFolderPrefix, pLastChar); } // while
exit: if (NULL != pAcct) pAcct->Release(); } // ImapUtil_LoadRootFldrPrefix
//***************************************************************************
// Function: ImapUtil_GetSpecialFolderType
//
// Purpose:
// This function takes the given account name and folder path, and
// determines whether the path points to a special IMAP folder. Note that
// although it is possible for a path to represent more than one type of
// IMAP special folder, only ONE special folder type is returned (based
// on evaluation order).
//
// Arguments:
// LPSTR pszAccountID [in] - ID of the IMAP account whose special folder
// paths we want to compare pszFullPath to.
// LPSTR pszFullPath [in] - path to a potential special folder residing on
// the pszAccountID account.
// char cHierarchyChar [in] - hierarchy char used to interpret pszFullPath.
// LPSTR pszRootFldrPrefix [in] - the root folder prefix for this IMAP
// account. If this is NULL, this function will find out for itself.
// SPECIALFOLDER *psfType [out] - the special folder type of given folder
// (eg, FOLDER_NOTSPECIAL, FOLDER_SENT). Pass NULL if not interested.
//
// Returns:
// LPSTR pointing to leaf name of special folder path. For instance, if
// the Drafts folder is set to "one/two/three/Drafts" and this function is
// called to process "one/two/three/Drafts/foo", then this function will
// return "Drafts/foo". If no match is found, NULL is returned.
//***************************************************************************
LPSTR ImapUtil_GetSpecialFolderType(LPSTR pszAccountID, LPSTR pszFullPath, char cHierarchyChar, LPSTR pszRootFldrPrefix, SPECIALFOLDER *psfType) { HRESULT hrResult; SPECIALFOLDER sfType = FOLDER_NOTSPECIAL; BOOL fSpecialFldrPrefix = FALSE; IImnAccount *pAccount = NULL; DWORD dw; int iLeafNameOffset = 0; int iTmp; int iLen; char sz[MAX_PATH * 2 + 2]; // Room for HC plus null-term
Assert(INVALID_HIERARCHY_CHAR != cHierarchyChar); Assert(g_pAcctMan); if (!g_pAcctMan) goto exit;
// First check if this is INBOX or one of its children
iLen = lstrlen(c_szInbox); if (0 == StrCmpNI(pszFullPath, c_szInbox, iLen) && (cHierarchyChar == pszFullPath[iLen] || '\0' == pszFullPath[iLen])) { fSpecialFldrPrefix = TRUE; iLeafNameOffset = 0; // "INBOX" is always the leaf name
if ('\0' == pszFullPath[iLen]) { sfType = FOLDER_INBOX; // Exact match for "INBOX"
goto exit; } }
hrResult = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccountID, &pAccount); if (FAILED(hrResult)) goto exit;
#ifdef DEBUG
hrResult = pAccount->GetServerTypes(&dw); Assert(SUCCEEDED(hrResult) && (SRV_IMAP & dw)); #endif // DEBUG
hrResult = pAccount->GetPropDw(AP_IMAP_SVRSPECIALFLDRS, &dw); if (SUCCEEDED(hrResult) && dw) { int iLenRFP;
// Check if user gave us a root folder prefix: otherwise we need to load it ourselves
if (NULL == pszRootFldrPrefix) ImapUtil_LoadRootFldrPrefix(pszAccountID, sz, sizeof(sz)); else StrCpyN(sz, pszRootFldrPrefix, ARRAYSIZE(sz));
iLenRFP = lstrlen(sz); if (iLenRFP > 0 && (DWORD)iLenRFP + 1 < sizeof(sz)) { sz[iLenRFP] = cHierarchyChar; iLenRFP += 1; sz[iLenRFP] = '\0'; }
hrResult = pAccount->GetPropSz(AP_IMAP_SENTITEMSFLDR, sz + iLenRFP, sizeof(sz) - iLenRFP); if (SUCCEEDED(hrResult)) { iLen = lstrlen(sz); if (0 == StrCmpNI(sz, pszFullPath, iLen) && (cHierarchyChar == pszFullPath[iLen] || '\0' == pszFullPath[iLen])) { fSpecialFldrPrefix = TRUE; iTmp = (int) (ImapUtil_ExtractLeafName(sz, cHierarchyChar) - sz); iLeafNameOffset = max(iTmp, iLeafNameOffset); if ('\0' == pszFullPath[iLen]) { sfType = FOLDER_SENT; // Exact match for Sent Items
goto exit; } } }
hrResult = pAccount->GetPropSz(AP_IMAP_DRAFTSFLDR, sz + iLenRFP, sizeof(sz) - iLenRFP); if (SUCCEEDED(hrResult)) { iLen = lstrlen(sz); if (0 == StrCmpNI(sz, pszFullPath, iLen) && (cHierarchyChar == pszFullPath[iLen] || '\0' == pszFullPath[iLen])) { fSpecialFldrPrefix = TRUE; iTmp = (int) (ImapUtil_ExtractLeafName(sz, cHierarchyChar) - sz); iLeafNameOffset = max(iTmp, iLeafNameOffset); if ('\0' == pszFullPath[iLen]) { sfType = FOLDER_DRAFT; // Exact match for Drafts folder
goto exit; } } } } // if (AP_IMAP_SVRSPECIALFLDRS)
exit: if (NULL != pAccount) pAccount->Release();
if (NULL != psfType) *psfType = sfType;
if (fSpecialFldrPrefix) return pszFullPath + iLeafNameOffset; else return NULL; } // ImapUtil_GetSpecialFolderType
//***************************************************************************
// Function: ImapUtil_ExtractLeafName
//
// Purpose:
// This function takes an IMAP folder path and extracts the leaf node name.
//
// Arguments:
// LPSTR pszFolderPath [in] - a string containing the IMAP folder path.
// char cHierarchyChar [in] - the hierarchy char used in pszFolderPath.
//
// Returns:
// A pointer to the leaf node name in pszFolderPath. The default return
// value is pszFolderPath, if no hierarchy characters were found.
//***************************************************************************
LPSTR ImapUtil_ExtractLeafName(LPSTR pszFolderPath, char cHierarchyChar) { LPSTR pszLastHierarchyChar, p;
// Find out where the last hierarchy character lives
pszLastHierarchyChar = pszFolderPath; p = pszFolderPath; while ('\0' != *p) { if (cHierarchyChar == *p) pszLastHierarchyChar = p;
p += 1; }
// Adjust pszLastHierarchyChar to point to leaf name
if (cHierarchyChar == *pszLastHierarchyChar) return pszLastHierarchyChar + 1; else return pszFolderPath; } // ImapUtil_ExtractLeafName
HRESULT ImapUtil_UIDToMsgSeqNum(IIMAPTransport *pIMAPTransport, DWORD_PTR dwUID, LPDWORD pdwMsgSeqNum) { HRESULT hrTemp; DWORD *pdwMsgSeqNumToUIDArray = NULL; DWORD dwHighestMsgSeqNum; DWORD dw; BOOL fFound = FALSE;
TraceCall("ImapUtil_UIDToMsgSeqNum");
if (NULL == pIMAPTransport || 0 == dwUID) { TraceResult(E_INVALIDARG); goto exit; }
// Quickly check the highest MSN
hrTemp = pIMAPTransport->GetHighestMsgSeqNum(&dwHighestMsgSeqNum); if (FAILED(hrTemp) || 0 == dwHighestMsgSeqNum) { TraceError(hrTemp); goto exit; }
// OK, no more laziness, we gotta do a linear search now
hrTemp = pIMAPTransport->GetMsgSeqNumToUIDArray(&pdwMsgSeqNumToUIDArray, &dwHighestMsgSeqNum); if (FAILED(hrTemp)) { TraceResult(hrTemp); goto exit; }
Assert(dwHighestMsgSeqNum > 0); for (dw = 0; dw < dwHighestMsgSeqNum; dw++) { // Look for match or overrun
if (0 != pdwMsgSeqNumToUIDArray[dw] && dwUID <= pdwMsgSeqNumToUIDArray[dw]) { if (dwUID == pdwMsgSeqNumToUIDArray[dw]) { if (NULL != pdwMsgSeqNum) *pdwMsgSeqNum = dw + 1;
fFound = TRUE; } break; } } // for
exit: SafeMemFree(pdwMsgSeqNumToUIDArray);
if (fFound) return S_OK; else return E_FAIL; } // ImapUtil_UIDToMsgSeqNum
// *** REMOVE THIS after Beta-2! This sets the AP_IMAP_DIRTY flag if no IMAP special folders
// found after OE4->OE5 migration. We can then prompt user to refresh folder list.
void ImapUtil_B2SetDirtyFlag(void) { IImnAccountManager *pAcctMan = NULL; IImnEnumAccounts *pAcctEnum = NULL; IImnAccount *pAcct = NULL; HRESULT hrResult;
TraceCall("ImapUtil_B2SetDirtyFlag");
// Enumerate through all accounts. Set AP_IMAP_DIRTY flag on all IMAP accounts
hrResult = HrCreateAccountManager(&pAcctMan); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
hrResult = pAcctMan->Init(NULL); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
hrResult = pAcctMan->Enumerate(SRV_IMAP, &pAcctEnum); if (FAILED(hrResult)) { TraceResult(hrResult); goto exit; }
hrResult = pAcctEnum->GetNext(&pAcct); while (SUCCEEDED(hrResult)) { DWORD dwIMAPDirty;
hrResult = pAcct->GetPropDw(AP_IMAP_DIRTY, &dwIMAPDirty); if (FAILED(hrResult)) { TraceResult(hrResult); dwIMAPDirty = 0; }
// Mark this IMAP account as dirty so we prompt user to refresh folder list
dwIMAPDirty |= (IMAP_FLDRLIST_DIRTY | IMAP_OE4MIGRATE_DIRTY); hrResult = pAcct->SetPropDw(AP_IMAP_DIRTY, dwIMAPDirty); TraceError(hrResult); // Record but otherwise ignore result
hrResult = pAcct->SaveChanges(); TraceError(hrResult); // Record but otherwise ignore result
// Get next account
SafeRelease(pAcct); hrResult = pAcctEnum->GetNext(&pAcct); }
exit: SafeRelease(pAcctMan); SafeRelease(pAcctEnum); }
|