#include "pch.hxx" #include "impapi.h" #include "comconv.h" #include #include #include "commimp.h" #include #include #include #include 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); }