Leaked source code of windows server 2003
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.
 
 
 
 
 
 

749 lines
20 KiB

#include "pch.hxx"
#include "impapi.h"
#include "comconv.h"
#include <newimp.h>
#include <eudrimp.h>
#include "commimp.h"
#include <mapi.h>
#include <mapix.h>
#include <import.h>
#include <dllmain.h>
ASSERTDATA
HRESULT FindSnm(EUDORANODE *pParent, EUDORANODE **pplist, TCHAR *npath);
INT_PTR CALLBACK SelectCommUserDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HRESULT GetCommunicatorDirectory(char *szUser, char *szDir, int cch);
const static char c_szSnmExt[] = "\\*.snm";
const static char c_szSnmHeader[] = "# Netscape folder cache"; //used for avoiding processing Netscape 3.0 SNM files
const static char c_szDrafts[] = "Drafts";
const static char c_szUnsent[] = "Unsent Messages";
const static char c_szSent[] = "Sent";
CCommunicatorImport::CCommunicatorImport()
{
DllAddRef();
m_cRef = 1;
m_plist = NULL;
*m_szUser = 0;
}
CCommunicatorImport::~CCommunicatorImport()
{
if (m_plist != NULL)
EudoraFreeFolderList(m_plist);
DllRelease();
}
ULONG CCommunicatorImport::AddRef()
{
m_cRef++;
return(m_cRef);
}
ULONG CCommunicatorImport::Release()
{
ULONG cRef;
cRef = --m_cRef;
if (cRef == 0)
delete this;
return(cRef);
}
HRESULT CCommunicatorImport::QueryInterface(REFIID riid, LPVOID *ppv)
{
HRESULT hr = S_OK;
if (ppv == NULL)
return(E_INVALIDARG);
*ppv = NULL;
if (IID_IMailImport == riid)
*ppv = (IMailImport *)this;
else if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else
hr = E_NOINTERFACE;
if (*ppv != NULL)
((LPUNKNOWN)*ppv)->AddRef();
return(hr);
}
typedef struct tagSELCOMMINFO
{
char szUser[MAX_PATH];
HKEY hkey;
} SELCOMMINFO;
const static char c_szRegNscp[] = "Software\\Netscape\\Netscape Navigator\\Users";
HRESULT CCommunicatorImport::InitializeImport(HWND hwnd)
{
DWORD cUsers;
int iRet;
HKEY hkey;
HRESULT hr;
SELCOMMINFO si;
hr = S_OK;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegNscp, 0, KEY_ALL_ACCESS, &hkey))
{
if (ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, 0, &cUsers, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
{
if (cUsers > 1)
{
si.hkey = hkey;
iRet = (int) DialogBoxParam(g_hInstImp, MAKEINTRESOURCE(iddSelectCommUser), hwnd, SelectCommUserDlgProc, (LPARAM)&si);
if (iRet == IDCANCEL)
hr = S_FALSE;
else if (iRet == IDOK)
StrCpyN(m_szUser, si.szUser, ARRAYSIZE(m_szUser));
else
hr = E_FAIL;
}
}
RegCloseKey(hkey);
}
return(hr);
}
INT_PTR CALLBACK SelectCommUserDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND hwndT;
WORD id;
DWORD iSubKey, cb;
char sz[MAX_PATH];
SELCOMMINFO *psi;
int index;
switch (msg)
{
case WM_INITDIALOG:
Assert(lParam != NULL);
psi = (SELCOMMINFO *)lParam;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)psi);
hwndT = GetDlgItem(hwnd, IDC_USERLIST);
// fill list
iSubKey = 0;
cb = sizeof(sz);
while (ERROR_SUCCESS == RegEnumKeyEx(psi->hkey, iSubKey, sz, &cb, NULL, NULL, NULL, NULL))
{
SendMessage(hwndT, LB_ADDSTRING, 0, (LPARAM)sz);
iSubKey++;
cb = sizeof(sz);
}
SendMessage(hwndT, LB_SETCURSEL, 0, 0);
return(TRUE);
case WM_COMMAND:
id = LOWORD(wParam);
switch (id)
{
case IDOK:
psi = (SELCOMMINFO *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
Assert(psi != NULL);
hwndT = GetDlgItem(hwnd, IDC_USERLIST);
index = (int) SendMessage(hwndT, LB_GETCURSEL, 0, 0);
Assert(index >= 0);
if (SendMessage(hwndT, LB_GETTEXTLEN, (WPARAM)index, 0) < ARRAYSIZE(psi->szUser))
SendMessage(hwndT, LB_GETTEXT, (WPARAM)index, (LPARAM)psi->szUser);
// fall through
case IDCANCEL:
EndDialog(hwnd, id);
return(TRUE);
}
break;
}
return(FALSE);
}
const static char c_szCommunicatorKey[] = "SOFTWARE\\Netscape\\Netscape Navigator\\Users";
const static char c_szCurrentUser[] = "CurrentUser";
const static char c_szDirRoot[] = "DirRoot";
const static char c_szMailDir[] = "\\Mail";
HRESULT GetCommunicatorDirectory(char *szUser, char *szDir, int cch)
{
char sz[MAX_PATH], szTemp[MAX_PATH], szExpanded[MAX_PATH], *psz;
HKEY hkResult, hkResult1;
LONG lRes;
DWORD cb, dwType;
HRESULT hr;
hr = E_FAIL;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szCommunicatorKey, 0, KEY_QUERY_VALUE, &hkResult))
{
if (szUser == NULL)
{
cb = sizeof(sz);
lRes = RegQueryValueEx(hkResult, c_szCurrentUser, NULL, NULL, (LPBYTE)sz, &cb);
szUser = sz;
}
else
{
Assert(*szUser != 0);
lRes = ERROR_SUCCESS;
}
if (lRes == ERROR_SUCCESS)
{
cb = sizeof(szTemp);
if (ERROR_SUCCESS == RegOpenKeyEx(hkResult, szUser, 0, KEY_QUERY_VALUE, &hkResult1))
{
if (ERROR_SUCCESS == RegQueryValueEx(hkResult1, c_szDirRoot, NULL, &dwType, (LPBYTE)szTemp, &cb))
{
if (REG_EXPAND_SZ == dwType)
{
ZeroMemory(szExpanded, ARRAYSIZE(szExpanded));
ExpandEnvironmentStrings(szTemp, szExpanded, ARRAYSIZE(szExpanded));
psz = szExpanded;
}
else
psz = szTemp;
if (!GetStorePath(psz, szDir, cch))
{
StrCpyN(szDir, psz, cch);
StrCatBuff(szDir, c_szMailDir, cch);
}
hr = S_OK;
}
RegCloseKey(hkResult1);
}
}
RegCloseKey(hkResult);
}
return(hr);
}
HRESULT CCommunicatorImport::GetDirectory(char *szDir, UINT cch)
{
HRESULT hr;
Assert(szDir != NULL);
hr = GetCommunicatorDirectory(*m_szUser != 0 ? m_szUser : NULL, szDir, cch);
if (FAILED(hr))
*szDir = 0;
return(S_OK);
}
HRESULT CCommunicatorImport::SetDirectory(char *szDir)
{
HRESULT hr;
Assert(szDir != NULL);
if (!ValidStoreDirectory(szDir, NETSCAPE))
return(S_FALSE);
if (m_plist != NULL)
{
EudoraFreeFolderList(m_plist);
m_plist = NULL;
}
hr = FindSnm(NULL, &m_plist, szDir);
return(hr);
}
HRESULT CCommunicatorImport::EnumerateFolders(DWORD_PTR dwCookie, IEnumFOLDERS **ppEnum)
{
CCommunicatorEnumFOLDERS *pEnum;
EUDORANODE *pnode;
Assert(ppEnum != NULL);
*ppEnum = NULL;
if (dwCookie == COOKIE_ROOT)
pnode = m_plist;
else
pnode = ((EUDORANODE *)dwCookie)->pchild;
if (pnode == NULL)
return(S_FALSE);
pEnum = new CCommunicatorEnumFOLDERS(pnode);
if (pEnum == NULL)
return(E_OUTOFMEMORY);
*ppEnum = pEnum;
return(S_OK);
}
STDMETHODIMP CCommunicatorImport::ImportFolder(DWORD_PTR dwCookie, IFolderImport *pImport)
{
char szHdr[64];
EUDORANODE *pnode;
HRESULT hr = E_FAIL;
TCHAR cMsgFile[MAX_PATH];
BYTE *pSnm, *pMsg, *pEnd, *pEndMsg, *pT, *pNextMsg, *pLast;
ULONG i, lMsgs, lTotalMsgs, lNumNulls, cbMsg, cbSnm, cExtra, uOffset, uMsgSize, cMsgImp;
ULONG lRoof = 32;
ULONG Offset = 0;
int nNumLevels = 1;
HANDLE mapSnm, mapMsg, hSnm, hMsg;
Assert(pImport != NULL);
pnode = (EUDORANODE *)dwCookie;
Assert(pnode != NULL);
if (pnode->iFileType == SNM_DRAFT)
m_bDraft = TRUE;
else
m_bDraft = FALSE;
Assert((pnode->iFileType == SNM_FILE ) || (pnode->iFileType == SNM_DRAFT));
hr = E_FAIL;
pSnm = NULL;
mapSnm = NULL;
pMsg = NULL;
mapMsg = NULL;
StrCpyN(cMsgFile, pnode->szFile, ARRAYSIZE(cMsgFile));
cMsgFile[(lstrlen(cMsgFile)) - 4] = 0;
hMsg = CreateFile(cMsgFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hMsg == INVALID_HANDLE_VALUE)
return(hrFolderOpenFail);
cbMsg = GetFileSize(hMsg, NULL);
if (cbMsg == 0)
{
CloseHandle(hMsg);
return(S_OK);
}
hSnm = CreateFile(pnode->szFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hSnm == INVALID_HANDLE_VALUE)
{
CloseHandle(hMsg);
return(hrFolderOpenFail);
}
cbSnm = GetFileSize(hSnm, NULL);
if (cbSnm < 2560)
{
// the .snm file header is 2560 bytes in size, so anything less
// than this is bogus or doesn't have messages anyway, so no point
// in continuing
goto DoneImport;
}
mapSnm = CreateFileMapping(hSnm, NULL, PAGE_READONLY, 0, 0, NULL);
if (mapSnm == NULL)
goto DoneImport;
pSnm = (BYTE *)MapViewOfFile(mapSnm, FILE_MAP_READ, 0, 0, 0);
if (pSnm == NULL)
goto DoneImport;
pEnd = pSnm + cbSnm;
// Do something else to verify the genuineness of the SNM file (like
// comparing the two separately stored values of "total # of messages").
// 1) Confirm that this is not a NS 3.0 SNM file.
CopyMemory(szHdr, pSnm, ARRAYSIZE(c_szSnmHeader) - 1);
szHdr[ARRAYSIZE(c_szSnmHeader) - 1] = 0;
if (0 == lstrcmp(szHdr, c_szSnmHeader))
{
// this is a Version 3.0 SNM file
goto DoneImport;
}
// 2) Do someting else!!! We need to verify as much as possible or we'll
// end up hanging.
mapMsg = CreateFileMapping(hMsg, NULL, PAGE_READONLY, 0, 0, NULL);
if (mapMsg == NULL)
goto DoneImport;
pMsg = (BYTE *)MapViewOfFile(mapMsg, FILE_MAP_READ, 0, 0, 0);
if (pMsg == NULL)
goto DoneImport;
pEndMsg = pMsg + cbMsg;
// Get the total number of messages in the SNM file
lTotalMsgs = GetOffset(pSnm, cbSnm, 400, 0); //408 - 8 as we add 8 in GetOffset
cMsgImp = 0;
pLast = pMsg;
pImport->SetMessageCount(lTotalMsgs);
if (lTotalMsgs > 0)
{
Offset = (ULONG)GetPrimaryOffset(pSnm, cbSnm);
// Find the number of 'Levels'
if(Offset < cbSnm)
{
while(lRoof < lTotalMsgs)
{
lRoof *= 32;
nNumLevels++;
}
hr = ProcessBlocks(pSnm, cbSnm, pMsg, cbMsg, nNumLevels, Offset, pImport);
}
}
DoneImport:
if (pSnm != NULL)
UnmapViewOfFile(pSnm);
if (mapSnm != NULL)
CloseHandle(mapSnm);
if (pMsg != NULL)
UnmapViewOfFile(pMsg);
if (mapMsg != NULL)
CloseHandle(mapMsg);
CloseHandle(hSnm);
CloseHandle(hMsg);
return(hr);
}
HRESULT CCommunicatorImport::ProcessBlocks(BYTE* pSnm, ULONG cbSnm,
BYTE* pMsg, ULONG cbMsg,
int nLayer, ULONG Offset,
IFolderImport *pImport)
{
HRESULT hr = S_OK;
HRESULT hr1 = E_FAIL;
Assert(Offset + 7 < cbSnm);
int nNumLoops = (int)pSnm[Offset + 7];
ULONG NewOffset = 0;
for(int nElement = 0; nElement < nNumLoops; nElement++)
{
if(hr != hrUserCancel)
{
if(nLayer == 1)
{
NewOffset = GetOffset(pSnm, cbSnm, Offset, 2*nElement);
// We use 2*nElement above to access elements 8 bytes apart.
hr1 = ProcessMessages(pSnm,cbSnm, pMsg, cbMsg, NewOffset, pImport);
if(FAILED(hr1))
hr = E_FAIL;
if(hr1 == hrUserCancel)
return hr1;
}
else
{
NewOffset = GetOffset(pSnm, cbSnm, Offset, nElement);
hr = ProcessBlocks(pSnm, cbSnm, pMsg, cbMsg, nLayer - 1, NewOffset, pImport);
}
}
else
return(hrUserCancel);
}
return(hr);
}
ULONG CCommunicatorImport::GetPrimaryOffset(BYTE* pSnm, ULONG cbSnm)
{
return GetOffset(pSnm, cbSnm, 416, 0); //424 - 8 as we add 8 in GetOffset
}
ULONG CCommunicatorImport::GetOffset(BYTE* pSnm, ULONG cbSnm, ULONG Offset, int nElement)
{
Assert (3 + Offset + (4*(nElement + 2)) < cbSnm); // One common check point!!!
ULONG result = 0;
result = (ULONG)pSnm[0 + Offset + (4*(nElement + 2))]*16777216 +
(ULONG)pSnm[1 + Offset + (4*(nElement + 2))]*65536 +
(ULONG)pSnm[2 + Offset + (4*(nElement + 2))]*256 +
(ULONG)pSnm[3 + Offset + (4*(nElement + 2))];
return result;
}
HRESULT CCommunicatorImport::ProcessMessages(BYTE* pSnm, ULONG cbSnm,
BYTE* pMsg, ULONG cbMsg,
ULONG NewOffset,
IFolderImport* pImport)
{
ULONG lMsgOffset = 0;
ULONG uMsgSize = 0;
HRESULT hr = E_FAIL;
LPSTREAM lpstm = NULL;
int nPriority = 1;
DWORD dwFlags = 0;
nPriority = (int)*(pSnm + NewOffset + 47);
switch(nPriority)
{
case 1:
case 4:
dwFlags |= MSG_PRI_NORMAL;
break;
case 2:
case 3:
dwFlags |= MSG_PRI_LOW;
break;
case 5:
case 6:
dwFlags |= MSG_PRI_HIGH;
break;
default:
dwFlags |= MSG_PRI_NORMAL;
break;
}
lMsgOffset = GetOffset(pSnm, cbSnm, NewOffset + 18, 0); //26 - 8 as we add 8 in GetOffset
uMsgSize = GetOffset(pSnm, cbSnm, NewOffset + 40, 0); //48 - 8 as we add 8 in GetOffset
Assert(lMsgOffset + uMsgSize <= cbMsg);
Assert(pImport != NULL);
hr = HrByteToStream(&lpstm, pMsg + lMsgOffset, uMsgSize);
if (SUCCEEDED(hr))
{
Assert(lpstm != NULL);
// 0x01 == read
if (((pSnm + NewOffset) != NULL) && (0 == ((pSnm + NewOffset)[45] & 0x01)))
dwFlags |= MSG_STATE_UNREAD;
if(m_bDraft)
dwFlags |= MSG_STATE_UNSENT;
hr = pImport->ImportMessage(MSG_TYPE_MAIL, dwFlags, lpstm, NULL, 0);
lpstm->Release();
}
return hr;
}
CCommunicatorEnumFOLDERS::CCommunicatorEnumFOLDERS(EUDORANODE *plist)
{
Assert(plist != NULL);
m_cRef = 1;
m_plist = plist;
m_pnext = plist;
}
CCommunicatorEnumFOLDERS::~CCommunicatorEnumFOLDERS()
{
}
ULONG CCommunicatorEnumFOLDERS::AddRef()
{
m_cRef++;
return(m_cRef);
}
ULONG CCommunicatorEnumFOLDERS::Release()
{
ULONG cRef;
cRef = --m_cRef;
if (cRef == 0)
delete this;
return(cRef);
}
HRESULT CCommunicatorEnumFOLDERS::QueryInterface(REFIID riid, LPVOID *ppv)
{
HRESULT hr = S_OK;
if (ppv == NULL)
return(E_INVALIDARG);
*ppv = NULL;
if (IID_IEnumFOLDERS == riid)
*ppv = (IEnumFOLDERS *)this;
else if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else
hr = E_NOINTERFACE;
if (*ppv != NULL)
((LPUNKNOWN)*ppv)->AddRef();
return(hr);
}
HRESULT CCommunicatorEnumFOLDERS::Next(IMPORTFOLDER *pfldr)
{
Assert(pfldr != NULL);
if (m_pnext == NULL)
return(S_FALSE);
ZeroMemory(pfldr, sizeof(IMPORTFOLDER));
pfldr->dwCookie = (DWORD_PTR)m_pnext;
// To map Netscape's "Sent" folder to OE's "Sent Items" - Bug 2688.
if (m_pnext->type != FOLDER_TYPE_SENT)
StrCpyN(pfldr->szName, m_pnext->szName, ARRAYSIZE(pfldr->szName));
else
StrCpyN(pfldr->szName, "Sent Items", ARRAYSIZE(pfldr->szName));
pfldr->type = m_pnext->type;
pfldr->fSubFolders = (m_pnext->pchild != NULL);
m_pnext = m_pnext->pnext;
return(S_OK);
}
HRESULT CCommunicatorEnumFOLDERS::Reset()
{
m_pnext = m_plist;
return(S_OK);
}
/*******************************************************************
* FUNCTION NAME:FindSnm
*
* PURPOSE:To Get the Snm files in a folder
*
* PARAMETERS:
*
* IN:parent EUDORANODE ,previously processed EUDORANODE
*
* OUT: Pointer to the first node in the tree
*
* RETURNS: TRUE or FALSE
*******************************************************************/
HRESULT FindSnm(EUDORANODE *pparent, EUDORANODE **pplist,TCHAR *npath)
{
HRESULT hr;
HANDLE h1, h2;
TCHAR path[MAX_PATH], path1[MAX_PATH], szInbox[CCHMAX_STRINGRES], szTrash[CCHMAX_STRINGRES];
TCHAR szNewPath[MAX_PATH];
WIN32_FIND_DATA FindFileData;
WIN32_FIND_DATA SbdFileData;
EUDORANODE *newp, *newp1, *last = NULL, *plist = NULL;
Assert(pplist != NULL);
Assert(npath != NULL);
*pplist = NULL;
StrCpyN(path, npath, ARRAYSIZE(path));
StrCatBuff(path, c_szSnmExt, ARRAYSIZE(path));
h1 = FindFirstFile(path, &FindFileData);
if (h1 == INVALID_HANDLE_VALUE)
return(S_OK);
hr = E_OUTOFMEMORY;
LoadString(g_hInstImp, idsInbox, szInbox, ARRAYSIZE(szInbox));
LoadString(g_hInstImp, idsTrash, szTrash, ARRAYSIZE(szTrash));
do
{
if (!MemAlloc((void **)&newp, sizeof(EUDORANODE)))
goto err;
ZeroMemory(newp, sizeof(EUDORANODE));
if (plist == NULL)
{
Assert(last == NULL);
plist = newp;
}
else
{
last->pnext = newp;
}
last = newp;
StrCpyN(newp->szName, FindFileData.cFileName, ARRAYSIZE(newp->szName));
wnsprintf(newp->szFile, ARRAYSIZE(newp->szFile), "%s\\%s", npath, newp->szName);
newp->szName[(lstrlen(newp->szName)) - 4] = 0;
if (0 == lstrcmpi(newp->szName, szInbox))
newp->type = FOLDER_TYPE_INBOX;
else if (0 == lstrcmpi(newp->szName, szTrash))
newp->type = FOLDER_TYPE_DELETED;
else if(0 == lstrcmpi(newp->szName, c_szSent)) //c_szSent need not be localised as per my investigation - v-sramas.
newp->type = FOLDER_TYPE_SENT;
newp->pparent = pparent;
newp->depth = (pparent == NULL ? 0 : (pparent->depth + 1));
// This following will be used later to set the flag of
// a message so that it is editable (MSG_STATE_UNSENT).
if ((0 == lstrcmpi(newp->szName, c_szDrafts)) ||(0 == lstrcmpi(newp->szName, c_szUnsent)))
newp->iFileType = SNM_DRAFT;
else
newp->iFileType = SNM_FILE;
// Search for a corresponding .SBD folder - file now.
wnsprintf(path1, ARRAYSIZE(path1), "%s", newp->szFile);
path1[(lstrlen(path1)) - 3] = 0;
StrCatBuff(path1, "sbd", ARRAYSIZE(path1));
h2 = FindFirstFile(path1, &SbdFileData);
if (h2 != INVALID_HANDLE_VALUE)
{
//Recurse here
wnsprintf(szNewPath, ARRAYSIZE(szNewPath), "%s\\%s", npath, SbdFileData.cFileName);
FindSnm(newp, &newp->pchild, szNewPath);
}
}
while (FindNextFile(h1, &FindFileData));
hr = S_OK;
err:
FindClose(h1);
if (FAILED(hr) && plist != NULL)
{
EudoraFreeFolderList(plist);
plist = NULL;
}
*pplist = plist;
return(hr);
}