summaryrefslogtreecommitdiffstats
path: root/mailnews/import/oexpress
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
committerMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
commit302bf1b523012e11b60425d6eee1221ebc2724eb (patch)
treeb191a895f8716efcbe42f454f37597a545a6f421 /mailnews/import/oexpress
parent21b3f6247403c06f85e1f45d219f87549862198f (diff)
downloadUXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.gz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.lz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.xz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.zip
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
Diffstat (limited to 'mailnews/import/oexpress')
-rw-r--r--mailnews/import/oexpress/OEDebugLog.h20
-rw-r--r--mailnews/import/oexpress/WabObject.cpp1132
-rw-r--r--mailnews/import/oexpress/WabObject.h64
-rw-r--r--mailnews/import/oexpress/moz.build19
-rw-r--r--mailnews/import/oexpress/nsOE5File.cpp631
-rw-r--r--mailnews/import/oexpress/nsOE5File.h52
-rw-r--r--mailnews/import/oexpress/nsOEAddressIterator.cpp396
-rw-r--r--mailnews/import/oexpress/nsOEAddressIterator.h36
-rw-r--r--mailnews/import/oexpress/nsOEImport.cpp657
-rw-r--r--mailnews/import/oexpress/nsOEImport.h42
-rw-r--r--mailnews/import/oexpress/nsOEMailbox.cpp673
-rw-r--r--mailnews/import/oexpress/nsOEMailbox.h27
-rw-r--r--mailnews/import/oexpress/nsOERegUtil.cpp27
-rw-r--r--mailnews/import/oexpress/nsOERegUtil.h20
-rw-r--r--mailnews/import/oexpress/nsOEScanBoxes.cpp859
-rw-r--r--mailnews/import/oexpress/nsOEScanBoxes.h76
-rw-r--r--mailnews/import/oexpress/nsOESettings.cpp921
-rw-r--r--mailnews/import/oexpress/nsOESettings.h22
-rw-r--r--mailnews/import/oexpress/nsOEStringBundle.cpp71
-rw-r--r--mailnews/import/oexpress/nsOEStringBundle.h38
20 files changed, 5783 insertions, 0 deletions
diff --git a/mailnews/import/oexpress/OEDebugLog.h b/mailnews/import/oexpress/OEDebugLog.h
new file mode 100644
index 000000000..47cc6b2ea
--- /dev/null
+++ b/mailnews/import/oexpress/OEDebugLog.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef OEDebugLog_h___
+#define OEDebugLog_h___
+
+// Use MOZ_LOG for logging.
+#include "mozilla/Logging.h"
+extern PRLogModuleInfo *OELOGMODULE; // Logging module
+
+#define IMPORT_LOG0(x) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (x))
+#define IMPORT_LOG1(x, y) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (x, y))
+#define IMPORT_LOG2(x, y, z) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (x, y, z))
+#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d))
+
+
+
+#endif /* OEDebugLog_h___ */
diff --git a/mailnews/import/oexpress/WabObject.cpp b/mailnews/import/oexpress/WabObject.cpp
new file mode 100644
index 000000000..e206b74f8
--- /dev/null
+++ b/mailnews/import/oexpress/WabObject.cpp
@@ -0,0 +1,1132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <tchar.h>
+#include "nscore.h"
+#include "nsOE5File.h"
+#include "wabobject.h"
+#include <algorithm>
+
+enum {
+ ieidPR_DISPLAY_NAME = 0,
+ ieidPR_ENTRYID,
+ ieidPR_OBJECT_TYPE,
+ ieidMax
+};
+
+static const SizedSPropTagArray(ieidMax, ptaEid)=
+{
+ ieidMax,
+ {
+ PR_DISPLAY_NAME,
+ PR_ENTRYID,
+ PR_OBJECT_TYPE,
+ }
+};
+
+
+enum {
+ iemailPR_DISPLAY_NAME = 0,
+ iemailPR_ENTRYID,
+ iemailPR_EMAIL_ADDRESS,
+ iemailPR_OBJECT_TYPE,
+ iemailMax
+};
+static const SizedSPropTagArray(iemailMax, ptaEmail)=
+{
+ iemailMax,
+ {
+ PR_DISPLAY_NAME,
+ PR_ENTRYID,
+ PR_EMAIL_ADDRESS,
+ PR_OBJECT_TYPE
+ }
+};
+
+typedef struct {
+ bool multiLine;
+ ULONG tag;
+ char * pLDIF;
+} AddrImportField;
+
+#define kExtraUserFields 10
+AddrImportField extraUserFields[kExtraUserFields] = {
+ {true, PR_COMMENT, "description:"},
+ {false, PR_BUSINESS_TELEPHONE_NUMBER, "telephonenumber:"},
+ {false, PR_HOME_TELEPHONE_NUMBER, "homephone:"},
+ {false, PR_COMPANY_NAME, "o:"},
+ {false, PR_TITLE, "title:"},
+ {false, PR_BUSINESS_FAX_NUMBER, "facsimiletelephonenumber:"},
+ {false, PR_LOCALITY, "locality:"},
+ {false, PR_STATE_OR_PROVINCE, "st:"},
+ {true, PR_STREET_ADDRESS, "streetaddress:"},
+ {false, PR_POSTAL_CODE, "postalcode:"}
+};
+
+#define kWhitespace " \t\b\r\n"
+
+#define TR_OUTPUT_EOL "\r\n"
+
+#define kLDIFPerson "objectclass: top" TR_OUTPUT_EOL "objectclass: person" TR_OUTPUT_EOL
+#define kLDIFGroup "objectclass: top" TR_OUTPUT_EOL "objectclass: groupOfNames" TR_OUTPUT_EOL
+
+/*********************************************************************************/
+
+
+// contructor for CWAB object
+//
+// pszFileName - FileName of WAB file to open
+// if no file name is specified, opens the default
+//
+CWAB::CWAB(nsIFile *file)
+{
+ // Here we load the WAB Object and initialize it
+ m_pUniBuff = NULL;
+ m_uniBuffLen = 0;
+
+ m_bInitialized = false;
+ m_lpAdrBook = NULL;
+ m_lpWABObject = NULL;
+ m_hinstWAB = NULL;
+
+ {
+ TCHAR szWABDllPath[MAX_PATH];
+ DWORD dwType = 0;
+ ULONG cbData = sizeof(szWABDllPath);
+ HKEY hKey = NULL;
+
+ *szWABDllPath = '\0';
+
+ // First we look under the default WAB DLL path location in the
+ // Registry.
+ // WAB_DLL_PATH_KEY is defined in wabapi.h
+ //
+ if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_READ, &hKey)) {
+ RegQueryValueEx(hKey, "", NULL, &dwType, (LPBYTE) szWABDllPath, &cbData);
+ if (dwType == REG_EXPAND_SZ) {
+ // Expand the environment variables
+ DWORD bufferSize = ExpandEnvironmentStrings(szWABDllPath, NULL, 0);
+ if (bufferSize && bufferSize < MAX_PATH) {
+ TCHAR tmp[MAX_PATH];
+ ExpandEnvironmentStrings(szWABDllPath, tmp, bufferSize);
+ _tcscpy(szWABDllPath, tmp);
+ }
+ else {
+ // This is an error condition. Nothing else is initialized yet, so simply return.
+ return;
+ }
+
+ }
+ }
+ else {
+ if (GetSystemDirectory(szWABDllPath, MAX_PATH)) {
+ _tcsncat(szWABDllPath, WAB_DLL_NAME,
+ std::min(_tcslen(WAB_DLL_NAME), MAX_PATH - _tcslen(szWABDllPath) - 1));
+ }
+ else {
+ // Yet another error condition.
+ return;
+ }
+ }
+
+ if(hKey) RegCloseKey(hKey);
+
+ // if the Registry came up blank, we do a loadlibrary on the wab32.dll
+ // WAB_DLL_NAME is defined in wabapi.h
+ //
+ m_hinstWAB = LoadLibrary((lstrlen(szWABDllPath)) ? szWABDllPath : WAB_DLL_NAME);
+ }
+
+ if(m_hinstWAB)
+ {
+ // if we loaded the dll, get the entry point
+ //
+ m_lpfnWABOpen = (LPWABOPEN) GetProcAddress(m_hinstWAB, "WABOpen");
+
+ if(m_lpfnWABOpen)
+ {
+ char fName[2] = {0, 0};
+ HRESULT hr = E_FAIL;
+ WAB_PARAM wp = {0};
+ wp.cbSize = sizeof(WAB_PARAM);
+ if (file != nullptr) {
+ nsCString path;
+ file->GetNativePath(path);
+ wp.szFileName = (LPTSTR) ToNewCString(path);
+ }
+ else
+ wp.szFileName = (LPTSTR) fName;
+
+ // if we choose not to pass in a WAB_PARAM object,
+ // the default WAB file will be opened up
+ //
+ hr = m_lpfnWABOpen(&m_lpAdrBook,&m_lpWABObject,&wp,0);
+
+ if(!hr)
+ m_bInitialized = TRUE;
+
+ }
+ }
+
+}
+
+
+// Destructor
+//
+CWAB::~CWAB()
+{
+ if (m_pUniBuff)
+ delete [] m_pUniBuff;
+
+ if(m_bInitialized)
+ {
+ if(m_lpAdrBook)
+ m_lpAdrBook->Release();
+
+ if(m_lpWABObject)
+ m_lpWABObject->Release();
+
+ if(m_hinstWAB)
+ FreeLibrary(m_hinstWAB);
+ }
+}
+
+
+HRESULT CWAB::IterateWABContents(CWabIterator *pIter, int *pDone)
+{
+ if (!m_bInitialized || !m_lpAdrBook)
+ return E_FAIL;
+
+ ULONG ulObjType = 0;
+ LPMAPITABLE lpAB = NULL;
+ ULONG cRows = 0;
+ LPSRowSet lpRowAB = NULL;
+ LPABCONT lpContainer = NULL;
+ int cNumRows = 0;
+ nsresult keepGoing;
+
+ HRESULT hr = E_FAIL;
+
+ ULONG lpcbEID = 0;
+ LPENTRYID lpEID = NULL;
+ ULONG rowCount = 0;
+ ULONG curCount = 0;
+
+ nsString uniStr;
+
+ // Get the entryid of the root PAB container
+ //
+ hr = m_lpAdrBook->GetPAB(&lpcbEID, &lpEID);
+
+ if (HR_FAILED(hr))
+ goto exit;
+
+ ulObjType = 0;
+
+ // Open the root PAB container
+ // This is where all the WAB contents reside
+ //
+ hr = m_lpAdrBook->OpenEntry(lpcbEID,
+ (LPENTRYID)lpEID,
+ NULL,
+ 0,
+ &ulObjType,
+ (LPUNKNOWN *)&lpContainer);
+
+ m_lpWABObject->FreeBuffer(lpEID);
+
+ lpEID = NULL;
+
+ if(HR_FAILED(hr))
+ goto exit;
+
+ // Get a contents table of all the contents in the
+ // WABs root container
+ //
+ hr = lpContainer->GetContentsTable(0, &lpAB);
+
+ if(HR_FAILED(hr))
+ goto exit;
+
+ hr = lpAB->GetRowCount(0, &rowCount);
+ if (HR_FAILED(hr))
+ rowCount = 100;
+ if (rowCount == 0)
+ rowCount = 1;
+
+ // Order the columns in the ContentsTable to conform to the
+ // ones we want - which are mainly DisplayName, EntryID and
+ // ObjectType
+ // The table is gauranteed to set the columns in the order
+ // requested
+ //
+ hr =lpAB->SetColumns((LPSPropTagArray)&ptaEid, 0);
+
+ if(HR_FAILED(hr))
+ goto exit;
+
+
+ // Reset to the beginning of the table
+ //
+ hr = lpAB->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
+
+ if(HR_FAILED(hr))
+ goto exit;
+
+ // Read all the rows of the table one by one
+ //
+
+ do {
+
+ hr = lpAB->QueryRows(1, 0, &lpRowAB);
+
+ if(HR_FAILED(hr))
+ break;
+
+ if(lpRowAB)
+ {
+ cNumRows = lpRowAB->cRows;
+
+ if (cNumRows)
+ {
+ LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
+ LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
+ ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
+
+ // There are 2 kinds of objects - the MAPI_MAILUSER contact object
+ // and the MAPI_DISTLIST contact object
+ // For the purposes of this sample, we will only consider MAILUSER
+ // objects
+ //
+ if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
+ {
+ // We will now take the entry-id of each object and cache it
+ // on the listview item representing that object. This enables
+ // us to uniquely identify the object later if we need to
+ //
+ CStrToUnicode(lpsz, uniStr);
+ keepGoing = pIter->EnumUser(uniStr.get(), lpEID, cbEID);
+ curCount++;
+ if (pDone) {
+ *pDone = (curCount * 100) / rowCount;
+ if (*pDone > 100)
+ *pDone = 100;
+ }
+ }
+ }
+ FreeProws(lpRowAB);
+ }
+
+
+ } while (SUCCEEDED(hr) && cNumRows && lpRowAB && NS_SUCCEEDED(keepGoing)) ;
+
+ hr = lpAB->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
+
+ if(HR_FAILED(hr))
+ goto exit;
+
+ // Read all the rows of the table one by one
+ //
+ keepGoing = NS_OK;
+ do {
+
+ hr = lpAB->QueryRows(1, 0, &lpRowAB);
+
+ if(HR_FAILED(hr))
+ break;
+
+ if(lpRowAB)
+ {
+ cNumRows = lpRowAB->cRows;
+
+ if (cNumRows)
+ {
+ LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
+ LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
+ ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
+
+ // There are 2 kinds of objects - the MAPI_MAILUSER contact object
+ // and the MAPI_DISTLIST contact object
+ // For the purposes of this sample, we will only consider MAILUSER
+ // objects
+ //
+ if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST)
+ {
+ LPABCONT distListContainer = NULL;
+ // We will now take the entry-id of each object and cache it
+ // on the listview item representing that object. This enables
+ // us to uniquely identify the object later if we need to
+ //
+ hr = m_lpAdrBook->OpenEntry(cbEID, lpEID, NULL,
+ 0,&ulObjType,(LPUNKNOWN *)&distListContainer);
+
+ LPMAPITABLE distListTable = NULL;
+
+
+ // Get a contents table of the dist list
+ //
+ hr = distListContainer->GetContentsTable(0, &distListTable);
+ if (lpAB)
+ {
+ hr = distListTable->GetRowCount(0, &rowCount);
+ if (HR_FAILED(hr))
+ rowCount = 100;
+ if (rowCount == 0)
+ rowCount = 1;
+
+ // Order the columns in the ContentsTable to conform to the
+ // ones we want - which are mainly DisplayName, EntryID and
+ // ObjectType
+ // The table is gauranteed to set the columns in the order
+ // requested
+ //
+ hr = distListTable->SetColumns((LPSPropTagArray)&ptaEid, 0);
+ CStrToUnicode(lpsz, uniStr);
+ keepGoing = pIter->EnumList(uniStr.get(), lpEID, cbEID, distListTable);
+ curCount++;
+ if (pDone) {
+ *pDone = (curCount * 100) / rowCount;
+ if (*pDone > 100)
+ *pDone = 100;
+ }
+ }
+ if (distListContainer)
+ distListContainer->Release();
+ if (distListTable)
+ distListTable->Release();
+ }
+ }
+ FreeProws(lpRowAB);
+ }
+
+ } while (SUCCEEDED(hr) && cNumRows && lpRowAB && NS_SUCCEEDED(keepGoing)) ;
+
+
+exit:
+
+ if (lpContainer)
+ lpContainer->Release();
+
+ if (lpAB)
+ lpAB->Release();
+
+ return hr;
+}
+
+
+
+
+
+
+void CWAB::FreeProws(LPSRowSet prows)
+{
+ ULONG irow;
+ if (!prows)
+ return;
+ for (irow = 0; irow < prows->cRows; ++irow)
+ m_lpWABObject->FreeBuffer(prows->aRow[irow].lpProps);
+ m_lpWABObject->FreeBuffer(prows);
+}
+
+
+LPDISTLIST CWAB::GetDistList(ULONG cbEid, LPENTRYID pEid)
+{
+ if (!m_bInitialized || !m_lpAdrBook)
+ return NULL;
+
+ LPDISTLIST lpDistList = NULL;
+ ULONG ulObjType;
+
+ m_lpAdrBook->OpenEntry(cbEid, pEid, NULL, 0, &ulObjType, (LPUNKNOWN *)&lpDistList);
+ return lpDistList;
+}
+
+LPSPropValue CWAB::GetListProperty(LPDISTLIST pUser, ULONG tag)
+{
+ if (!pUser)
+ return NULL;
+
+ int sz = CbNewSPropTagArray(1);
+ SPropTagArray *pTag = (SPropTagArray *) new char[sz];
+ pTag->cValues = 1;
+ pTag->aulPropTag[0] = tag;
+ LPSPropValue lpProp = NULL;
+ ULONG cValues = 0;
+ HRESULT hr = pUser->GetProps(pTag, 0, &cValues, &lpProp);
+ delete [] pTag;
+ if (HR_FAILED(hr) || (cValues != 1)) {
+ if (lpProp)
+ m_lpWABObject->FreeBuffer(lpProp);
+ return NULL;
+ }
+ return lpProp;
+}
+
+LPMAILUSER CWAB::GetUser(ULONG cbEid, LPENTRYID pEid)
+{
+ if (!m_bInitialized || !m_lpAdrBook)
+ return NULL;
+
+ LPMAILUSER lpMailUser = NULL;
+ ULONG ulObjType;
+
+ m_lpAdrBook->OpenEntry(cbEid, pEid, NULL, 0, &ulObjType, (LPUNKNOWN *)&lpMailUser);
+ return lpMailUser;
+}
+
+LPSPropValue CWAB::GetUserProperty(LPMAILUSER pUser, ULONG tag)
+{
+ if (!pUser)
+ return NULL;
+
+ ULONG uTag = tag;
+ /*
+ Getting Unicode does not help with getting the right
+ international charset. Windoze bloze.
+ */
+ /*
+ if (PROP_TYPE(uTag) == PT_STRING8) {
+ uTag = CHANGE_PROP_TYPE(tag, PT_UNICODE);
+ }
+ */
+
+ int sz = CbNewSPropTagArray(1);
+ SPropTagArray *pTag = (SPropTagArray *) new char[sz];
+ pTag->cValues = 1;
+ pTag->aulPropTag[0] = uTag;
+ LPSPropValue lpProp = NULL;
+ ULONG cValues = 0;
+ HRESULT hr = pUser->GetProps(pTag, 0, &cValues, &lpProp);
+ if (HR_FAILED(hr) || (cValues != 1)) {
+ if (lpProp)
+ m_lpWABObject->FreeBuffer(lpProp);
+ lpProp = NULL;
+ if (uTag != tag) {
+ pTag->cValues = 1;
+ pTag->aulPropTag[0] = tag;
+ cValues = 0;
+ hr = pUser->GetProps(pTag, 0, &cValues, &lpProp);
+ if (HR_FAILED(hr) || (cValues != 1)) {
+ if (lpProp)
+ m_lpWABObject->FreeBuffer(lpProp);
+ lpProp = NULL;
+ }
+ }
+ }
+ delete [] pTag;
+ return lpProp;
+}
+
+void CWAB::CStrToUnicode(const char *pStr, nsString& result)
+{
+ result.Truncate();
+ int wLen = MultiByteToWideChar(CP_ACP, 0, pStr, -1, wwc(m_pUniBuff), 0);
+ if (wLen >= m_uniBuffLen) {
+ if (m_pUniBuff)
+ delete [] m_pUniBuff;
+ m_pUniBuff = new char16_t[wLen + 64];
+ m_uniBuffLen = wLen + 64;
+ }
+ if (wLen) {
+ MultiByteToWideChar(CP_ACP, 0, pStr, -1, wwc(m_pUniBuff), m_uniBuffLen);
+ result = m_pUniBuff;
+ }
+}
+
+// If the value is a string, get it...
+void CWAB::GetValueString(LPSPropValue pVal, nsString& val)
+{
+ val.Truncate();
+
+ if (!pVal)
+ return;
+
+ switch(PROP_TYPE(pVal->ulPropTag)) {
+ case PT_STRING8:
+ CStrToUnicode((const char *) (pVal->Value.lpszA), val);
+ break;
+ case PT_UNICODE:
+ val = (char16_t *) (pVal->Value.lpszW);
+ break;
+ case PT_MV_STRING8: {
+ nsString tmp;
+ ULONG j;
+ for(j = 0; j < pVal->Value.MVszA.cValues; j++) {
+ CStrToUnicode((const char *) (pVal->Value.MVszA.lppszA[j]), tmp);
+ val += tmp;
+ val.Append(NS_ConvertASCIItoUTF16(TR_OUTPUT_EOL));
+ }
+ break;
+ }
+ case PT_MV_UNICODE: {
+ ULONG j;
+ for(j = 0; j < pVal->Value.MVszW.cValues; j++) {
+ val += (char16_t *) (pVal->Value.MVszW.lppszW[j]);
+ val.Append(NS_ConvertASCIItoUTF16(TR_OUTPUT_EOL));
+ }
+ break;
+ }
+ case PT_I2:
+ case PT_LONG:
+ case PT_R4:
+ case PT_DOUBLE:
+ case PT_BOOLEAN: {
+ /*
+ TCHAR sz[256];
+ wsprintf(sz,"%d", pVal->Value.l);
+ val = sz;
+ */
+ break;
+ }
+
+ case PT_BINARY:
+ break;
+
+ default:
+ break;
+ }
+
+ val.Trim(kWhitespace, true, true);
+}
+
+
+void CWAB::GetValueTime(LPSPropValue pVal, PRTime& val)
+{
+ if (!pVal)
+ return;
+
+ if (PROP_TYPE(pVal->ulPropTag) != PT_SYSTIME)
+ return;
+
+ nsOE5File::FileTimeToPRTime(&pVal->Value.ft, &val);
+}
+
+bool CWAB::IsAvailable()
+{
+ if (!m_bInitialized || !m_lpAdrBook)
+ return false;
+
+ ULONG lpcbEID = 0;
+ LPENTRYID lpEID = NULL;
+ HRESULT hr = m_lpAdrBook->GetPAB(&lpcbEID, &lpEID);
+ if (HR_FAILED(hr))
+ return false;
+
+ ULONG ulObjType = 0;
+ LPABCONT lpContainer = NULL;
+ hr = m_lpAdrBook->OpenEntry(lpcbEID,
+ (LPENTRYID)lpEID,
+ NULL,
+ 0,
+ &ulObjType,
+ (LPUNKNOWN *)&lpContainer);
+ m_lpWABObject->FreeBuffer(lpEID);
+
+ LPMAPITABLE lpAB = NULL;
+ hr = lpContainer->GetContentsTable(0, &lpAB);
+ if(HR_FAILED(hr)) {
+ lpContainer->Release();
+ return false;
+ }
+
+ ULONG rowCount = 0;
+ hr = lpAB->GetRowCount(0, &rowCount);
+ lpContainer->Release();
+ lpAB->Release();
+ return (rowCount != 0);
+}
+
+/*
+BOOL CWabIterateProcess::SanitizeMultiLine(CString& val)
+{
+ val.TrimLeft();
+ val.TrimRight();
+ int idx = val.FindOneOf("\x0D\x0A");
+ if (idx == -1)
+ return FALSE;
+
+ // needs encoding
+ U32 bufSz = UMimeEncode::GetBufferSize(val.GetLength());
+ P_U8 pBuf = new U8[bufSz];
+ U32 len = UMimeEncode::ConvertBuffer((PC_U8)((PC_S8)val), val.GetLength(), pBuf, 66, 52, "\x0D\x0A ");
+ pBuf[len] = 0;
+ val = pBuf;
+ delete pBuf;
+ return TRUE;
+}
+
+BOOL CWabIterateProcess::EnumUser(LPCTSTR pName, LPENTRYID pEid, ULONG cbEid)
+{
+ TRACE1("User: %s\n", pName);
+
+ LPMAILUSER pUser = m_pWab->GetUser(cbEid, pEid);
+
+ // Get the "required" strings first
+ CString lastName;
+ CString firstName;
+ CString eMail;
+ CString nickName;
+ CString middleName;
+
+ if (!pUser) {
+ UDialogs::ErrMessage1(IDS_ENTRY_ERROR, pName);
+ return FALSE;
+ }
+
+ LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_GIVEN_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, firstName);
+ SanitizeValue(firstName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_SURNAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, lastName);
+ SanitizeValue(lastName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_MIDDLE_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, middleName);
+ SanitizeValue(middleName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_NICKNAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, nickName);
+ SanitizeValue(nickName);
+ m_pWab->FreeProperty(pProp);
+ }
+ if (nickName.IsEmpty())
+ nickName = pName;
+ if (firstName.IsEmpty()) {
+ firstName = nickName;
+ middleName.Empty();
+ lastName.Empty();
+ }
+ if (lastName.IsEmpty())
+ middleName.Empty();
+
+ if (eMail.IsEmpty())
+ eMail = nickName;
+
+
+ // We now have the required fields
+ // write them out followed by any optional fields!
+ BOOL result = TRUE;
+
+ if (m_recordsDone)
+ result = m_out.WriteEol();
+
+ CString line;
+ CString header;
+ line.LoadString(IDS_LDIF_DN_START);
+ line += firstName;
+ if (!middleName.IsEmpty()) {
+ line += ' ';
+ line += middleName;
+ }
+ if (!lastName.IsEmpty()) {
+ line += ' ';
+ line += lastName;
+ }
+ header.LoadString(IDS_LDIF_DN_MIDDLE);
+ line += header;
+ line += eMail;
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+
+ line.LoadString(IDS_FIELD_LDIF_FULLNAME);
+ line += ' ';
+ line += firstName;
+ if (!middleName.IsEmpty()) {
+ line += ' ';
+ line += middleName;
+ }
+ if (!lastName.IsEmpty()) {
+ line += ' ';
+ line += lastName;
+ }
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+
+
+ line.LoadString(IDS_FIELD_LDIF_GIVENNAME);
+ line += ' ';
+ line += firstName;
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+
+ if (!lastName.IsEmpty()) {
+ line.LoadString(IDS_FIELD_LDIF_LASTNAME);
+ if (!middleName.IsEmpty()) {
+ line += ' ';
+ line += middleName;
+ }
+ line += ' ';
+ line += lastName;
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+ }
+
+ result = result && m_out.WriteStr(kLDIFPerson);
+
+ line.LoadString(IDS_FIELD_LDIF_EMAIL);
+ line += ' ';
+ line += eMail;
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+
+ line.LoadString(IDS_FIELD_LDIF_NICKNAME);
+ line += ' ';
+ line += nickName;
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+
+ // Do all of the extra fields!
+ CString value;
+ BOOL encoded = FALSE;
+ for (int i = 0; i < kExtraUserFields; i++) {
+ value.Empty();
+ pProp = m_pWab->GetUserProperty(pUser, extraUserFields[i].tag);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, value);
+ m_pWab->FreeProperty(pProp);
+ }
+ if (extraUserFields[i].multiLine) {
+ encoded = SanitizeMultiLine(value);
+ }
+ else
+ SanitizeValue(value);
+ if (!value.IsEmpty()) {
+ line = extraUserFields[i].pLDIF;
+ if (encoded) {
+ line += ": ";
+ encoded = FALSE;
+ }
+ else
+ line += ' ';
+ line += value;
+ result = result && m_out.WriteStr(line);
+ result = result && m_out.WriteEol();
+ }
+ }
+
+ m_pWab->ReleaseUser(pUser);
+
+ if (!result) {
+ UDialogs::ErrMessage0(IDS_ADDRESS_SAVE_ERROR);
+ }
+
+ m_totalDone += kValuePerUser;
+ m_recordsDone++;
+
+ return result;
+}
+*/
+
+
+
+
+/*
+BOOL CWabIterateProcess::EnumList(LPCTSTR pName, LPENTRYID pEid, ULONG cbEid)
+{
+ TRACE1("List: %s\n", pName);
+
+ LPDISTLIST pList = m_pWab->GetDistList(cbEid, pEid);
+ if (!pList) {
+ UDialogs::ErrMessage1(IDS_ENTRY_ERROR, pName);
+ return FALSE;
+ }
+
+ // Find out if this is just a regular entry or a true list...
+ CString eMail;
+ LPSPropValue pProp = m_pWab->GetListProperty(pList, PR_EMAIL_ADDRESS);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ m_pWab->FreeProperty(pProp);
+ // Treat this like a regular entry...
+ if (!eMail.IsEmpty()) {
+ m_pWab->ReleaseDistList(pList);
+ return WriteListUserEntry(pName, eMail);
+ }
+ }
+
+ // This may very well be a list, find the entries...
+ m_pListTable = OpenDistList(pList);
+ if (m_pListTable) {
+ m_pList = pList;
+ m_listName = pName;
+ m_listDone = 0;
+ m_listHeaderDone = FALSE;
+ m_state = kEnumListState;
+ }
+ else {
+ m_pWab->ReleaseDistList(pList);
+ m_recordsDone++;
+ m_totalDone += kValuePerUser;
+ }
+
+ return TRUE;
+}
+
+BOOL CWabIterateProcess::EnumNextListUser(BOOL *pDone)
+{
+ HRESULT hr;
+ int cNumRows = 0;
+ LPSRowSet lpRowAB = NULL;
+ BOOL keepGoing = TRUE;
+
+ if (!m_pListTable)
+ return FALSE;
+
+ hr = m_pListTable->QueryRows(1, 0, &lpRowAB);
+
+ if(HR_FAILED(hr)) {
+ UDialogs::ErrMessage0(IDS_ERROR_READING_WAB);
+ return FALSE;
+ }
+
+ if(lpRowAB) {
+ cNumRows = lpRowAB->cRows;
+
+ if (cNumRows) {
+ LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
+ LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
+ ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
+ if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST) {
+ keepGoing = HandleListList(lpsz, lpEID, cbEID);
+ }
+ else if (lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER) {
+ keepGoing = HandleListUser(lpsz, lpEID, cbEID);
+ }
+ }
+ m_pWab->FreeProws(lpRowAB);
+ }
+
+ if (!cNumRows || !lpRowAB) {
+ *pDone = TRUE;
+ m_pListTable->Release();
+ m_pListTable = NULL;
+ if (m_pList)
+ m_pWab->ReleaseDistList(m_pList);
+ m_pList = NULL;
+ if (m_listDone < kValuePerUser)
+ m_totalDone += (kValuePerUser - m_listDone);
+ m_recordsDone++;
+ return keepGoing;
+ }
+
+ if (!keepGoing)
+ return FALSE;
+
+ if (m_listDone < kValuePerUser) {
+ m_listDone++;
+ m_totalDone++;
+ }
+
+ return TRUE;
+}
+
+BOOL CWabIterateProcess::HandleListList(LPCTSTR pName, LPENTRYID lpEid, ULONG cbEid)
+{
+ BOOL result;
+ LPDISTLIST pList = m_pWab->GetDistList(cbEid, lpEid);
+ if (!pList) {
+ UDialogs::ErrMessage1(IDS_ENTRY_ERROR, pName);
+ return FALSE;
+ }
+
+ CString eMail;
+ LPSPropValue pProp = m_pWab->GetListProperty(pList, PR_EMAIL_ADDRESS);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ m_pWab->FreeProperty(pProp);
+ // Treat this like a regular entry...
+ if (!eMail.IsEmpty()) {
+ // write out a member based on pName and eMail
+ result = WriteGroupMember(pName, eMail);
+ m_pWab->ReleaseDistList(pList);
+ return result;
+ }
+ }
+
+ // iterate the list and add each member to the top level list
+ LPMAPITABLE pTable = OpenDistList(pList);
+ if (!pTable) {
+ TRACE0("Error opening table for list\n");
+ m_pWab->ReleaseDistList(pList);
+ UDialogs::ErrMessage1(IDS_ENTRY_ERROR, pName);
+ return FALSE;
+ }
+
+ int cNumRows = 0;
+ LPSRowSet lpRowAB = NULL;
+ HRESULT hr;
+ BOOL keepGoing = TRUE;
+
+ do {
+ hr = pTable->QueryRows(1, 0, &lpRowAB);
+
+ if(HR_FAILED(hr)) {
+ UDialogs::ErrMessage0(IDS_ERROR_READING_WAB);
+ pTable->Release();
+ m_pWab->ReleaseDistList(pList);
+ return FALSE;
+ }
+
+ if(lpRowAB) {
+ cNumRows = lpRowAB->cRows;
+
+ if (cNumRows) {
+ LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
+ LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
+ ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
+ if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST) {
+ keepGoing = HandleListList(lpsz, lpEID, cbEID);
+ }
+ else if (lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER) {
+ keepGoing = HandleListUser(lpsz, lpEID, cbEID);
+ }
+ }
+ m_pWab->FreeProws(lpRowAB);
+ }
+ }
+ while (keepGoing && cNumRows && lpRowAB);
+
+ pTable->Release();
+ m_pWab->ReleaseDistList(pList);
+ return keepGoing;
+}
+
+BOOL CWabIterateProcess::HandleListUser(LPCTSTR pName, LPENTRYID lpEid, ULONG cbEid)
+{
+ // Get the basic properties for building the member line
+ LPMAILUSER pUser = m_pWab->GetUser(cbEid, lpEid);
+
+ // Get the "required" strings first
+ CString lastName;
+ CString firstName;
+ CString eMail;
+ CString nickName;
+ CString middleName;
+
+ if (!pUser) {
+ UDialogs::ErrMessage1(IDS_ENTRY_ERROR, pName);
+ return FALSE;
+ }
+
+ LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_GIVEN_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, firstName);
+ SanitizeValue(firstName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_SURNAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, lastName);
+ SanitizeValue(lastName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_MIDDLE_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, middleName);
+ SanitizeValue(middleName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_NICKNAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, nickName);
+ SanitizeValue(nickName);
+ m_pWab->FreeProperty(pProp);
+ }
+ if (nickName.IsEmpty())
+ nickName = pName;
+ if (firstName.IsEmpty()) {
+ firstName = nickName;
+ middleName.Empty();
+ lastName.Empty();
+ }
+ if (lastName.IsEmpty())
+ middleName.Empty();
+
+ if (eMail.IsEmpty())
+ eMail = nickName;
+
+ m_pWab->ReleaseUser(pUser);
+
+ CString name = firstName;
+ if (!middleName.IsEmpty()) {
+ name += ' ';
+ name += middleName;
+ }
+ if (!lastName.IsEmpty()) {
+ name += ' ';
+ name += lastName;
+ }
+ return WriteGroupMember(name, eMail);
+}
+
+BOOL CWabIterateProcess::WriteGroupMember(const char *pName, const char *pEmail)
+{
+ CString middle;
+ CString line;
+ BOOL result;
+
+ // Check for the header first
+ if (!m_listHeaderDone) {
+ if (m_recordsDone)
+ result = m_out.WriteEol();
+ else
+ result = TRUE;
+ line.LoadString(IDS_LDIF_DN_START);
+ line += m_listName;
+ line += TR_OUTPUT_EOL;
+ middle.LoadString(IDS_FIELD_LDIF_FULLNAME);
+ line += middle;
+ line += m_listName;
+ line += TR_OUTPUT_EOL;
+ if (!result || !m_out.WriteStr(line) || !m_out.WriteStr(kLDIFGroup)) {
+ UDialogs::ErrMessage0(IDS_ADDRESS_SAVE_ERROR);
+ return FALSE;
+ }
+ m_listHeaderDone = TRUE;
+ }
+
+
+ line.LoadString(IDS_FIELD_LDIF_MEMBER_START);
+ line += pName;
+ middle.LoadString(IDS_LDIF_DN_MIDDLE);
+ line += middle;
+ line += pEmail;
+ line += TR_OUTPUT_EOL;
+ if (!m_out.WriteStr(line)) {
+ UDialogs::ErrMessage0(IDS_ADDRESS_SAVE_ERROR);
+ return FALSE;
+ }
+
+ if (m_listDone < kValuePerUser) {
+ m_listDone++;
+ m_totalDone++;
+ }
+
+ return TRUE;
+}
+*/
+
diff --git a/mailnews/import/oexpress/WabObject.h b/mailnews/import/oexpress/WabObject.h
new file mode 100644
index 000000000..482615697
--- /dev/null
+++ b/mailnews/import/oexpress/WabObject.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef WabObject_h___
+#define WabObject_h___
+
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsIFile.h"
+
+#include <windows.h>
+#include <wab.h>
+
+
+class CWabIterator {
+public:
+ virtual nsresult EnumUser(const char16_t *pName, LPENTRYID pEid, ULONG cbEid) = 0;
+ virtual nsresult EnumList(const char16_t *pName, LPENTRYID pEid, ULONG cbEid, LPMAPITABLE lpTable) = 0;
+};
+
+
+class CWAB
+{
+public:
+ CWAB(nsIFile *fileName);
+ ~CWAB();
+
+ bool Loaded(void) { return m_bInitialized;}
+
+ HRESULT IterateWABContents(CWabIterator *pIter, int *pDone);
+
+ // Methods for User entries
+ LPDISTLIST GetDistList(ULONG cbEid, LPENTRYID pEid);
+ void ReleaseDistList(LPDISTLIST pList) { if (pList) pList->Release();}
+ LPMAILUSER GetUser(ULONG cbEid, LPENTRYID pEid);
+ void ReleaseUser(LPMAILUSER pUser) { if (pUser) pUser->Release();}
+ LPSPropValue GetUserProperty(LPMAILUSER pUser, ULONG tag);
+ LPSPropValue GetListProperty(LPDISTLIST pList, ULONG tag);
+ void FreeProperty(LPSPropValue pVal) { if (pVal) m_lpWABObject->FreeBuffer(pVal);}
+ void GetValueString(LPSPropValue pVal, nsString& val);
+ void GetValueTime(LPSPropValue pVal, PRTime& val);
+
+ void CStrToUnicode(const char *pStr, nsString& result);
+
+ // Utility stuff used by iterate
+ void FreeProws(LPSRowSet prows);
+
+ bool IsAvailable();
+
+private:
+ char16_t * m_pUniBuff;
+ int m_uniBuffLen;
+ bool m_bInitialized;
+ HINSTANCE m_hinstWAB;
+ LPWABOPEN m_lpfnWABOpen;
+ LPADRBOOK m_lpAdrBook;
+ LPWABOBJECT m_lpWABObject;
+};
+
+#endif // WABOBJECT_INCLUDED
+
+
diff --git a/mailnews/import/oexpress/moz.build b/mailnews/import/oexpress/moz.build
new file mode 100644
index 000000000..5a34ce8e6
--- /dev/null
+++ b/mailnews/import/oexpress/moz.build
@@ -0,0 +1,19 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+ 'nsOE5File.cpp',
+ 'nsOEAddressIterator.cpp',
+ 'nsOEImport.cpp',
+ 'nsOEMailbox.cpp',
+ 'nsOERegUtil.cpp',
+ 'nsOEScanBoxes.cpp',
+ 'nsOESettings.cpp',
+ 'nsOEStringBundle.cpp',
+ 'WabObject.cpp',
+]
+
+FINAL_LIBRARY = 'import'
+
diff --git a/mailnews/import/oexpress/nsOE5File.cpp b/mailnews/import/oexpress/nsOE5File.cpp
new file mode 100644
index 000000000..fd1fd0e15
--- /dev/null
+++ b/mailnews/import/oexpress/nsOE5File.cpp
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsOE5File.h"
+#include "OEDebugLog.h"
+#include "nsMsgUtils.h"
+#include "msgCore.h"
+#include "prprf.h"
+#include "nsMsgLocalFolderHdrs.h"
+#include "nsIOutputStream.h"
+#include "nsIInputStream.h"
+#include "nsIMsgPluggableStore.h"
+#include "nsIMsgHdr.h"
+#include "nsNetUtil.h"
+#include "nsISeekableStream.h"
+#include "nsMsgMessageFlags.h"
+#include <windows.h>
+
+#define kIndexGrowBy 100
+#define kSignatureSize 12
+#define kDontSeek 0xFFFFFFFF
+#define MARKED 0x20 // 4
+#define READ 0x80 // 1
+#define HASATTACHMENT 0x4000 // 268435456 10000000h
+#define ISANSWERED 0x80000 // 2
+#define ISFORWARDED 0x100000 // 4096
+#define ISWATCHED 0x400000 // 256
+#define ISIGNORED 0x800000 // 262144
+#define XLATFLAGS(s) (((MARKED & s) ? nsMsgMessageFlags::Marked : 0) | \
+ ((READ & s) ? nsMsgMessageFlags::Read : 0) | \
+ ((HASATTACHMENT & s) ? nsMsgMessageFlags::Attachment : 0) | \
+ ((ISANSWERED & s) ? nsMsgMessageFlags::Replied : 0) | \
+ ((ISFORWARDED & s) ? nsMsgMessageFlags::Forwarded : 0) | \
+ ((ISWATCHED & s) ? nsMsgMessageFlags::Watched : 0) | \
+ ((ISIGNORED & s) ? nsMsgMessageFlags::Ignored : 0))
+
+static char *gSig =
+ "\xCF\xAD\x12\xFE\xC5\xFD\x74\x6F\x66\xE3\xD1\x11";
+
+// copied from nsprpub/pr/src/{io/prfile.c | md/windows/w95io.c} :
+// PR_FileTimeToPRTime and _PR_FileTimeToPRTime
+void nsOE5File::FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
+{
+#ifdef __GNUC__
+ const PRTime _pr_filetime_offset = 116444736000000000LL;
+#else
+ const PRTime _pr_filetime_offset = 116444736000000000i64;
+#endif
+
+ PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
+ ::CopyMemory(prtm, filetime, sizeof(PRTime));
+#ifdef __GNUC__
+ *prtm = (*prtm - _pr_filetime_offset) / 10LL;
+#else
+ *prtm = (*prtm - _pr_filetime_offset) / 10i64;
+#endif
+}
+
+bool nsOE5File::VerifyLocalMailFile(nsIFile *pFile)
+{
+ char sig[kSignatureSize];
+
+ nsCOMPtr <nsIInputStream> inputStream;
+
+ if (NS_FAILED(NS_NewLocalFileInputStream(getter_AddRefs(inputStream), pFile)))
+ return false;
+
+ if (!ReadBytes(inputStream, sig, 0, kSignatureSize))
+ return false;
+
+ bool result = true;
+
+ for (int i = 0; (i < kSignatureSize) && result; i++) {
+ if (sig[i] != gSig[i])
+ result = false;
+ }
+
+ char storeName[14];
+ if (!ReadBytes(inputStream, storeName, 0x24C1, 12))
+ result = false;
+
+ storeName[12] = 0;
+
+ if (PL_strcasecmp("LocalStore", storeName))
+ result = false;
+
+ return result;
+}
+
+bool nsOE5File::IsLocalMailFile(nsIFile *pFile)
+{
+ nsresult rv;
+ bool isFile = false;
+
+ rv = pFile->IsFile(&isFile);
+ if (NS_FAILED(rv) || !isFile)
+ return false;
+
+ bool result = VerifyLocalMailFile(pFile);
+
+ return result;
+}
+
+bool nsOE5File::ReadIndex(nsIInputStream *pInputStream, uint32_t **ppIndex, uint32_t *pSize)
+{
+ *ppIndex = nullptr;
+ *pSize = 0;
+
+ char signature[4];
+ if (!ReadBytes(pInputStream, signature, 0, 4))
+ return false;
+
+ for (int i = 0; i < 4; i++) {
+ if (signature[i] != gSig[i]) {
+ IMPORT_LOG0("*** Outlook 5.0 dbx file signature doesn't match\n");
+ return false;
+ }
+ }
+
+ uint32_t offset = 0x00e4;
+ uint32_t indexStart = 0;
+ if (!ReadBytes(pInputStream, &indexStart, offset, 4)) {
+ IMPORT_LOG0("*** Unable to read offset to index start\n");
+ return false;
+ }
+
+ PRUint32Array array;
+ array.count = 0;
+ array.alloc = kIndexGrowBy;
+ array.pIndex = new uint32_t[kIndexGrowBy];
+
+ uint32_t next = ReadMsgIndex(pInputStream, indexStart, &array);
+ while (next) {
+ next = ReadMsgIndex(pInputStream, next, &array);
+ }
+
+ if (array.count) {
+ *pSize = array.count;
+ *ppIndex = array.pIndex;
+ return true;
+ }
+
+ delete [] array.pIndex;
+ return false;
+}
+
+
+uint32_t nsOE5File::ReadMsgIndex(nsIInputStream *pInputStream, uint32_t offset, PRUint32Array *pArray)
+{
+ // Record is:
+ // 4 byte marker
+ // 4 byte unknown
+ // 4 byte nextSubIndex
+ // 4 byte (parentIndex?)
+ // 2 bytes unknown
+ // 1 byte length - # of entries in this record
+ // 1 byte unknown
+ // 4 byte unknown
+ // length records consisting of 3 longs
+ // 1 - pointer to record
+ // 2 - child index pointer
+ // 3 - number of records in child
+
+ uint32_t marker;
+
+ if (!ReadBytes(pInputStream, &marker, offset, 4))
+ return 0;
+
+ if (marker != offset)
+ return 0;
+
+
+ uint32_t vals[3];
+
+ if (!ReadBytes(pInputStream, vals, offset + 4, 12))
+ return 0;
+
+
+ uint8_t len[4];
+ if (!ReadBytes(pInputStream, len, offset + 16, 4))
+ return 0;
+
+
+
+ uint32_t cnt = (uint32_t) len[1];
+ cnt *= 3;
+ uint32_t *pData = new uint32_t[cnt];
+
+ if (!ReadBytes(pInputStream, pData, offset + 24, cnt * 4)) {
+ delete [] pData;
+ return 0;
+ }
+
+ uint32_t next;
+ uint32_t indexOffset;
+ uint32_t * pRecord = pData;
+ uint32_t * pNewIndex;
+
+ for (uint8_t i = 0; i < (uint8_t)len[1]; i++, pRecord += 3) {
+ indexOffset = pRecord[0];
+
+ if (pArray->count >= pArray->alloc) {
+ pNewIndex = new uint32_t[ pArray->alloc + kIndexGrowBy];
+ memcpy(pNewIndex, pArray->pIndex, (pArray->alloc * 4));
+ (pArray->alloc) += kIndexGrowBy;
+ delete [] pArray->pIndex;
+ pArray->pIndex = pNewIndex;
+ }
+
+ /*
+ We could do some checking here if we wanted -
+ make sure the index is within the file,
+ make sure there isn't a duplicate index, etc.
+ */
+
+ pArray->pIndex[pArray->count] = indexOffset;
+ (pArray->count)++;
+
+
+
+ next = pRecord[1];
+ if (next)
+ while ((next = ReadMsgIndex(pInputStream, next, pArray)) != 0);
+ }
+ delete [] pData;
+
+ // return the pointer to the next subIndex
+ return vals[1];
+}
+
+bool nsOE5File::IsFromLine(char *pLine, uint32_t len)
+{
+ return (len > 5 && (pLine[0] == 'F') && (pLine[1] == 'r') && (pLine[2] == 'o') && (pLine[3] == 'm') && (pLine[4] == ' '));
+}
+
+// Anything over 16K will be assumed BAD, BAD, BAD!
+#define kMailboxBufferSize 0x4000
+#define kMaxAttrCount 0x0030
+const char *nsOE5File::m_pFromLineSep = "From - Mon Jan 1 00:00:00 1965\x0D\x0A";
+
+nsresult nsOE5File::ImportMailbox(uint32_t *pBytesDone, bool *pAbort,
+ nsString& name, nsIFile *inFile,
+ nsIMsgFolder *dstFolder, uint32_t *pCount)
+{
+ int32_t msgCount = 0;
+ if (pCount)
+ *pCount = 0;
+
+ nsCOMPtr<nsIInputStream> inputStream;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), inFile);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIMsgPluggableStore> msgStore;
+ rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t * pIndex;
+ uint32_t indexSize;
+ uint32_t * pFlags;
+ uint64_t * pTime;
+
+ if (!ReadIndex(inputStream, &pIndex, &indexSize)) {
+ IMPORT_LOG1("No messages found in mailbox: %s\n", NS_LossyConvertUTF16toASCII(name.get()));
+ return NS_OK;
+ }
+
+ pTime = new uint64_t[ indexSize];
+ pFlags = new uint32_t[ indexSize];
+ char * pBuffer = new char[kMailboxBufferSize];
+ if (!(*pAbort))
+ ConvertIndex(inputStream, pBuffer, pIndex, indexSize, pFlags, pTime);
+
+ uint32_t block[4];
+ int32_t sepLen = (int32_t) strlen(m_pFromLineSep);
+ uint32_t written;
+
+ /*
+ Each block is:
+ marker - matches file offset
+ block length
+ text length in block
+ pointer to next block. (0 if end)
+
+ Each message is made up of a linked list of block data.
+ So what we do for each message is:
+ 1. Read the first block data.
+ 2. Write out the From message separator if the message doesn't already
+ start with one.
+ 3. If the block of data doesn't end with CRLF then a line is broken into two blocks,
+ so save the incomplete line for later process when we read the next block. Then
+ write out the block excluding the partial line at the end of the block (if exists).
+ 4. If there's next block of data then read next data block. Otherwise we're done.
+ If we found a partial line in step #3 then find the rest of the line from the
+ current block and write out this line separately.
+ 5. Reset some of the control variables and repeat step #3.
+ */
+
+ uint32_t didBytes = 0;
+ uint32_t next, size;
+ char *pStart, *pEnd, *partialLineStart;
+ nsAutoCString partialLine, tempLine;
+ nsCOMPtr<nsIOutputStream> outputStream;
+ rv = NS_OK;
+
+ for (uint32_t i = 0; (i < indexSize) && !(*pAbort); i++)
+ {
+ if (! pIndex[i])
+ continue;
+
+ nsCOMPtr<nsIMsgDBHdr> msgHdr;
+ bool reusable;
+
+ rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
+ getter_AddRefs(outputStream));
+ if (NS_FAILED(rv))
+ {
+ IMPORT_LOG1( "Mbx getting outputstream error: 0x%lx\n", rv);
+ break;
+ }
+
+ if (ReadBytes(inputStream, block, pIndex[i], 16) && (block[0] == pIndex[i]) &&
+ (block[2] < kMailboxBufferSize) && (ReadBytes(inputStream, pBuffer, kDontSeek, block[2])))
+ {
+ // block[2] contains the chars in the buffer (ie, buf content size).
+ // block[3] contains offset to the next block of data (0 means no more data).
+ size = block[2];
+ pStart = pBuffer;
+ pEnd = pStart + size;
+
+ // write out the from separator.
+ rv = NS_ERROR_FAILURE;
+ if (IsFromLine(pBuffer, size))
+ {
+ char *pChar = pStart;
+ while ((pChar < pEnd) && (*pChar != '\r') && (*(pChar+1) != '\n'))
+ pChar++;
+
+ if (pChar < pEnd)
+ {
+ // Get the "From " line so write it out.
+ rv = outputStream->Write(pStart, pChar-pStart+2, &written);
+ if (NS_SUCCEEDED(rv))
+ // Now buffer starts from the 2nd line.
+ pStart = pChar + 2;
+ }
+ }
+ else if (pTime[i])
+ {
+ char result[156] = "";
+ PRExplodedTime xpldTime;
+ char buffer[128] = "";
+ PRTime prt;
+
+ nsOE5File::FileTimeToPRTime((FILETIME *)&pTime[i], &prt);
+ // modeled after nsMsgSend.cpp
+ PR_ExplodeTime(prt, PR_LocalTimeParameters, &xpldTime);
+ PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
+ "%a %b %d %H:%M:%S %Y",
+ &xpldTime);
+ PL_strcpy(result, "From - ");
+ PL_strcpy(result + 7, buffer);
+ PL_strcpy(result + 7 + 24, CRLF);
+
+ rv = outputStream->Write(result, (int32_t) strlen(result), &written);
+ }
+ if (NS_FAILED(rv))
+ {
+ // Write out the default from line since there is none in the msg.
+ rv = outputStream->Write(m_pFromLineSep, sepLen, &written);
+ // FIXME: Do I need to check the return value of written???
+ if (NS_FAILED(rv))
+ break;
+ }
+
+ char statusLine[50];
+ uint32_t msgFlags = XLATFLAGS(pFlags[i]);
+ PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF);
+ rv = outputStream->Write(statusLine, strlen(statusLine), &written);
+ NS_ENSURE_SUCCESS(rv,rv);
+ PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF0000);
+ rv = outputStream->Write(statusLine, strlen(statusLine), &written);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ do
+ {
+ partialLine.Truncate();
+ partialLineStart = pEnd;
+
+ // If the buffer doesn't end with CRLF then a line is broken into two blocks,
+ // so save the incomplete line for later process when we read the next block.
+ if ((size > 1) && !(*(pEnd - 2) == '\r' && *(pEnd - 1) == '\n'))
+ {
+ partialLineStart -= 2;
+ while ((partialLineStart >= pStart) && (*partialLineStart != '\r') && (*(partialLineStart+1) != '\n'))
+ partialLineStart--;
+ if (partialLineStart != (pEnd - 2))
+ partialLineStart += 2; // skip over CRLF if we find them.
+ partialLine.Assign(partialLineStart, pEnd - partialLineStart);
+ }
+
+ // Now process the block of data which ends with CRLF.
+ rv = EscapeFromSpaceLine(outputStream, pStart, partialLineStart);
+ if (NS_FAILED(rv))
+ break;
+
+ didBytes += block[2];
+
+ next = block[3];
+ if (! next)
+ {
+ // OK, we're done so flush out the partial line if it's not empty.
+ if (partialLine.Length())
+ rv = EscapeFromSpaceLine(outputStream, (char *)partialLine.get(), (partialLine.get()+partialLine.Length()));
+ }
+ else
+ if (ReadBytes(inputStream, block, next, 16) && (block[0] == next) &&
+ (block[2] < kMailboxBufferSize) && (ReadBytes(inputStream, pBuffer, kDontSeek, block[2])))
+ {
+ // See if we have a partial line from previous block. If so then build a complete
+ // line (ie, take the remaining chars from this block) and process this line. Need
+ // to adjust where data start and size in this case.
+ size = block[2];
+ pStart = pBuffer;
+ pEnd = pStart + size;
+ if (partialLine.Length())
+ {
+ while ((pStart < pEnd) && (*pStart != '\r') && (*(pStart+1) != '\n'))
+ pStart++;
+ if (pStart < pEnd) // if we found a CRLF ..
+ pStart += 2; // .. then copy that too.
+ tempLine.Assign(pBuffer, pStart - pBuffer);
+ partialLine.Append(tempLine);
+ rv = EscapeFromSpaceLine(outputStream, (char *)partialLine.get(), (partialLine.get()+partialLine.Length()));
+ if (NS_FAILED(rv))
+ break;
+
+ // Adjust where data start and size (since some of the data has been processed).
+ size -= (pStart - pBuffer);
+ }
+ }
+ else
+ {
+ IMPORT_LOG2("Error reading message from %s at 0x%lx\n", NS_LossyConvertUTF16toASCII(name.get()), pIndex[i]);
+ rv = outputStream->Write("\x0D\x0A", 2, &written);
+ next = 0;
+ }
+ } while (next);
+
+ // Always end a msg with CRLF. This will make sure that OE msgs without body is
+ // correctly recognized as msgs. Otherwise, we'll end up with the following in
+ // the msg folder where the 2nd msg starts right after the headers of the 1st msg:
+ //
+ // From - Jan 1965 00:00:00 <<<--- 1st msg starts here
+ // Subject: Test msg
+ // . . . (more headers)
+ // To: <someone@example.com>
+ // From - Jan 1965 00:00:00 <<<--- 2nd msg starts here
+ // Subject: How are you
+ // . . .(more headers)
+ //
+ // In this case, the 1st msg is not recognized as a msg (it's skipped)
+ // when you open the folder.
+ rv = outputStream->Write("\x0D\x0A", 2, &written);
+
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0( "Error writing message during OE import\n");
+ msgStore->DiscardNewMessage(outputStream, msgHdr);
+ break;
+ }
+
+ msgStore->FinishNewMessage(outputStream, msgHdr);
+
+ if (!reusable)
+ outputStream->Close();
+
+ msgCount++;
+ if (pCount)
+ *pCount = msgCount;
+ if (pBytesDone)
+ *pBytesDone = didBytes;
+ }
+ else {
+ // Error reading message, should this be logged???
+ IMPORT_LOG2("Error reading message from %s at 0x%lx\n", NS_LossyConvertUTF16toASCII(name.get()), pIndex[i]);
+ *pAbort = true;
+ }
+ }
+ if (outputStream)
+ outputStream->Close();
+ delete [] pBuffer;
+ delete [] pFlags;
+ delete [] pTime;
+
+ if (NS_FAILED(rv))
+ *pAbort = true;
+
+ return rv;
+}
+
+
+/*
+ A message index record consists of:
+ 4 byte marker - matches record offset
+ 4 bytes size - size of data after this header
+ 2 bytes header length - not dependable
+ 1 bytes - number of attributes
+ 1 byte changes on this object
+ Each attribute is a 4 byte value with the 1st byte being the tag
+ and the remaing 3 bytes being data. The data is either a direct
+ offset of an offset within the message index that points to the
+ data for the tag.
+ attr[0]:
+ -hi bit== 1 means PRUint24 data = attr[1]
+ -hi bit== 0 means (PRUint24) attr[1] = offset into data segment for data
+ -attr[0] & 7f == tag index
+ Header above is 0xC bytes, attr's are number * 4 bytes then follows data segment
+ The data segment length is undefined. The index data is either part of the
+ index structure or the index structure points to address in data that follows
+ index structure table. Use that location to calculate file position of data.
+ MSDN indicates 0x28 attributes possible.
+
+ Current known tags are:
+ 0x01 - flags addressed
+ 0x81 - flags in attr's next 3 bytes
+ 0x02 - a time value - addressed- 8 bytes
+ 0x04 - text offset pointer, the data is the offset after the attribute
+ of a 4 byte pointer to the message text <-- addr into data
+ 0x05 - offset to truncated subject
+ 0x08 - offste to subject
+ 0x0D - offset to from
+ 0x0E - offset to from addresses
+ 0x13 - offset to to name
+ 0x45 - offset to to address <----correct --> 0x14
+ 0x80 - msgId <-correction-> 0x07 addr to msg id
+ 0x84 - direct text offset, direct pointer to message text
+*/
+
+void nsOE5File::ConvertIndex(nsIInputStream *pFile, char *pBuffer,
+ uint32_t *pIndex, uint32_t size,
+ uint32_t *pFlags, uint64_t *pTime)
+{
+ // for each index record, get the actual message offset! If there is a
+ // problem just record the message offset as 0 and the message reading code
+ // can log that error information.
+ // XXXTODO- above error reporting is not done
+
+ uint8_t recordHead[12];
+ uint32_t marker;
+ uint32_t recordSize;
+ uint32_t numAttrs;
+ uint32_t offset;
+ uint32_t attrIndex;
+ uint32_t attrOffset;
+ uint8_t tag;
+ uint32_t tagData;
+ uint32_t flags;
+ uint64_t time;
+ uint32_t dataStart;
+
+ for (uint32_t i = 0; i < size; i++) {
+ offset = 0;
+ flags = 0;
+ time = 0;
+ if (ReadBytes(pFile, recordHead, pIndex[i], 12)) {
+ memcpy(&marker, recordHead, 4);
+ memcpy(&recordSize, recordHead + 4, 4);
+ numAttrs = (uint32_t) recordHead[10];
+ if (marker == pIndex[i] && numAttrs <= kMaxAttrCount) {
+ dataStart = pIndex[i] + 12 + (numAttrs * 4);
+ if (ReadBytes(pFile, pBuffer, kDontSeek, numAttrs * 4)) {
+ attrOffset = 0;
+ for (attrIndex = 0; attrIndex < numAttrs; attrIndex++, attrOffset += 4) {
+ tag = (uint8_t) pBuffer[attrOffset];
+ if (tag == (uint8_t) 0x84) {
+ tagData = 0;
+ memcpy(&tagData, pBuffer + attrOffset + 1, 3);
+ offset = tagData;
+ }
+ else if (tag == (uint8_t) 0x04) {
+ tagData = 0;
+ memcpy(&tagData, pBuffer + attrOffset + 1, 3);
+ ReadBytes(pFile, &offset, dataStart + tagData, 4);
+ }
+ else if (tag == (uint8_t) 0x81) {
+ tagData = 0;
+ memcpy(&tagData, pBuffer + attrOffset +1, 3);
+ flags = tagData;
+ }
+ else if (tag == (uint8_t) 0x01) {
+ tagData = 0;
+ memcpy(&tagData, pBuffer + attrOffset +1, 3);
+ ReadBytes(pFile, &flags, dataStart + tagData, 4);
+ }
+ else if (tag == (uint8_t) 0x02) {
+ tagData = 0;
+ memcpy(&tagData, pBuffer + attrOffset +1, 3);
+ ReadBytes(pFile, &time, dataStart + tagData, 4);
+ }
+ }
+ }
+ }
+ }
+ pIndex[i] = offset;
+ pFlags[i] = flags;
+ pTime[i] = time;
+ }
+}
+
+
+bool nsOE5File::ReadBytes(nsIInputStream *stream, void *pBuffer, uint32_t offset, uint32_t bytes)
+{
+ nsresult rv;
+
+ nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(stream);
+ if (offset != kDontSeek) {
+ rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+ if (NS_FAILED(rv))
+ return false;
+ }
+
+ if (!bytes)
+ return true;
+
+ uint32_t cntRead;
+ char * pReadTo = (char *)pBuffer;
+ rv = stream->Read(pReadTo, bytes, &cntRead);
+ return NS_SUCCEEDED(rv) && cntRead == bytes;
+
+}
+
diff --git a/mailnews/import/oexpress/nsOE5File.h b/mailnews/import/oexpress/nsOE5File.h
new file mode 100644
index 000000000..07498acfd
--- /dev/null
+++ b/mailnews/import/oexpress/nsOE5File.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOE5File_h___
+#define nsOE5File_h___
+
+#include "nsStringGlue.h"
+#include "nsIFile.h"
+#include "nsIMsgFolder.h"
+#include <windows.h>
+
+class nsIInputStream;
+
+class nsOE5File
+{
+public:
+ /* pFile must already be open for reading. */
+ static bool VerifyLocalMailFile(nsIFile *pFile);
+ /* pFile must NOT be open for reading */
+ static bool IsLocalMailFile(nsIFile *pFile);
+
+ static bool ReadIndex(nsIInputStream *pFile, uint32_t **ppIndex, uint32_t *pSize);
+
+ static nsresult ImportMailbox(uint32_t *pBytesDone, bool *pAbort,
+ nsString& name, nsIFile *inFile,
+ nsIMsgFolder *pDstFolder, uint32_t *pCount);
+
+ static void FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm);
+
+private:
+ typedef struct {
+ uint32_t * pIndex;
+ uint32_t count;
+ uint32_t alloc;
+ } PRUint32Array;
+
+ static const char *m_pFromLineSep;
+
+ static bool ReadBytes(nsIInputStream *stream, void *pBuffer, uint32_t offset, uint32_t bytes);
+ static uint32_t ReadMsgIndex(nsIInputStream *file, uint32_t offset, PRUint32Array *pArray);
+ static void ConvertIndex(nsIInputStream *pFile, char *pBuffer, uint32_t *pIndex,
+ uint32_t size, uint32_t *pFlags, uint64_t *pTime);
+ static bool IsFromLine(char *pLine, uint32_t len);
+
+
+};
+
+
+
+#endif /* nsOE5File_h___ */
diff --git a/mailnews/import/oexpress/nsOEAddressIterator.cpp b/mailnews/import/oexpress/nsOEAddressIterator.cpp
new file mode 100644
index 000000000..bc33b45fb
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEAddressIterator.cpp
@@ -0,0 +1,396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/*
+
+ A sample of XPConnect. This file contains an implementation of
+ nsISample.
+
+*/
+#include "nscore.h"
+#include "nsCOMPtr.h"
+#include "nsStringGlue.h"
+#include "nsMsgUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIServiceManager.h"
+#include "nsIImportService.h"
+#include "nsIImportFieldMap.h"
+#include "nsABBaseCID.h"
+#include "nsIAbCard.h"
+#include "prprf.h"
+
+#include "nsOEAddressIterator.h"
+
+#include "OEDebugLog.h"
+
+typedef struct {
+ int32_t mozField;
+ int32_t multiLine;
+ ULONG mapiTag;
+} MAPIFields;
+
+enum {
+ ieidPR_DISPLAY_NAME = 0,
+ ieidPR_ENTRYID,
+ ieidPR_OBJECT_TYPE,
+ ieidMax
+};
+
+/*
+ Fields in MAPI, not in Mozilla
+ PR_OFFICE_LOCATION
+ FIX - PR_BIRTHDAY - stored as PT_SYSTIME - FIX to extract for moz address book birthday
+ PR_DISPLAY_NAME_PREFIX - Mr., Mrs. Dr., etc.
+ PR_SPOUSE_NAME
+ PR_GENDER - integer, not text
+ FIX - PR_CONTACT_EMAIL_ADDRESSES - multiuline strings for email addresses, needs
+ parsing to get secondary email address for mozilla
+*/
+
+#define kIsMultiLine -2
+#define kNoMultiLine -1
+
+static MAPIFields gMapiFields[] = {
+ { 35, kIsMultiLine, PR_COMMENT},
+ { 6, kNoMultiLine, PR_BUSINESS_TELEPHONE_NUMBER},
+ { 7, kNoMultiLine, PR_HOME_TELEPHONE_NUMBER},
+ { 25, kNoMultiLine, PR_COMPANY_NAME},
+ { 23, kNoMultiLine, PR_TITLE},
+ { 10, kNoMultiLine, PR_CELLULAR_TELEPHONE_NUMBER},
+ { 9, kNoMultiLine, PR_PAGER_TELEPHONE_NUMBER},
+ { 8, kNoMultiLine, PR_BUSINESS_FAX_NUMBER},
+ { 8, kNoMultiLine, PR_HOME_FAX_NUMBER},
+ { 22, kNoMultiLine, PR_COUNTRY},
+ { 19, kNoMultiLine, PR_LOCALITY},
+ { 20, kNoMultiLine, PR_STATE_OR_PROVINCE},
+ { 17, 18, PR_STREET_ADDRESS},
+ { 21, kNoMultiLine, PR_POSTAL_CODE},
+ { 27, kNoMultiLine, PR_PERSONAL_HOME_PAGE},
+ { 26, kNoMultiLine, PR_BUSINESS_HOME_PAGE},
+ { 13, kNoMultiLine, PR_HOME_ADDRESS_CITY},
+ { 16, kNoMultiLine, PR_HOME_ADDRESS_COUNTRY},
+ { 15, kNoMultiLine, PR_HOME_ADDRESS_POSTAL_CODE},
+ { 14, kNoMultiLine, PR_HOME_ADDRESS_STATE_OR_PROVINCE},
+ { 11, 12, PR_HOME_ADDRESS_STREET},
+ { 24, kNoMultiLine, PR_DEPARTMENT_NAME}
+};
+
+nsOEAddressIterator::nsOEAddressIterator(CWAB *pWab, nsIAddrDatabase *database)
+{
+ m_pWab = pWab;
+ m_database = database;
+}
+
+nsOEAddressIterator::~nsOEAddressIterator()
+{
+}
+
+nsresult nsOEAddressIterator::EnumUser(const char16_t * pName, LPENTRYID pEid, ULONG cbEid)
+{
+ IMPORT_LOG1("User: %S\n", pName);
+ nsresult rv = NS_OK;
+
+ if (m_database) {
+ LPMAILUSER pUser = m_pWab->GetUser(cbEid, pEid);
+ if (pUser) {
+ // Get a new row from the database!
+ nsCOMPtr <nsIMdbRow> newRow;
+ rv = m_database->GetNewRow(getter_AddRefs(newRow));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (newRow && BuildCard(pName, newRow, pUser))
+ {
+ rv = m_database->AddCardRowToDB(newRow);
+ NS_ENSURE_SUCCESS(rv, rv);
+ IMPORT_LOG0("* Added entry to address book database\n");
+ nsString eMail;
+
+ LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
+ if (pProp)
+ {
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ m_pWab->FreeProperty(pProp);
+ m_listRows.Put(eMail, newRow);
+ }
+ }
+ m_pWab->ReleaseUser(pUser);
+ }
+ }
+
+ return rv;
+}
+
+void nsOEAddressIterator::FindListRow(nsString &eMail, nsIMdbRow **cardRow)
+{
+ m_listRows.Get(eMail,cardRow);
+}
+
+nsresult nsOEAddressIterator::EnumList(const char16_t * pName, LPENTRYID pEid, ULONG cbEid, LPMAPITABLE lpTable)
+{
+ // If no name provided then we're done.
+ if (!pName || !(*pName))
+ return NS_OK;
+
+ nsresult rv = NS_ERROR_FAILURE;
+ HRESULT hr = E_FAIL;
+ // Make sure we have db to work with.
+ if (!m_database)
+ return rv;
+
+ nsCOMPtr <nsIMdbRow> listRow;
+ rv = m_database->GetNewListRow(getter_AddRefs(listRow));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = m_database->AddListName(listRow, NS_ConvertUTF16toUTF8(pName).get());
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = m_database->AddCardRowToDB(listRow);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = m_database->AddListDirNode(listRow);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ LPSRowSet lpRowAB = NULL;
+ ULONG lpcbEID = 0;
+ LPENTRYID lpEID = NULL;
+ ULONG rowCount = 0;
+ int cNumRows = 0;
+ int numListElems = 0;
+ nsAutoString uniStr;
+
+ hr = lpTable->GetRowCount(0, &rowCount);
+ //
+ hr = lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
+
+ if(HR_FAILED(hr))
+ return NS_ERROR_FAILURE;
+
+ // Read all the rows of the table one by one
+ do
+ {
+ hr = lpTable->QueryRows(1, 0, &lpRowAB);
+
+ if(HR_FAILED(hr))
+ break;
+
+ if(lpRowAB)
+ {
+ cNumRows = lpRowAB->cRows;
+ if (cNumRows)
+ {
+ LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
+ LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
+ ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
+
+ // There are 2 kinds of objects - the MAPI_MAILUSER contact object
+ // and the MAPI_DISTLIST contact object
+ // For distribution lists, we will only consider MAILUSER
+ // objects since we can't nest lists yet.
+ if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
+ {
+ LPMAILUSER pUser = m_pWab->GetUser(cbEID, lpEID);
+ LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
+ nsString eMail;
+
+ nsCOMPtr <nsIMdbRow> cardRow;
+
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ FindListRow(eMail, getter_AddRefs(cardRow));
+ if (cardRow)
+ {
+ nsCOMPtr <nsIAbCard> userCard;
+ nsCOMPtr <nsIAbCard> newCard;
+ userCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ m_database->InitCardFromRow(userCard,cardRow);
+
+ m_database->AddListCardColumnsToRow(userCard, listRow, ++numListElems,
+ getter_AddRefs(newCard),
+ true, nullptr, nullptr);
+ }
+ m_pWab->FreeProperty(pProp);
+ m_pWab->ReleaseUser(pUser);
+ }
+ }
+ m_pWab->FreeProws(lpRowAB);
+ }
+ } while (SUCCEEDED(hr) && cNumRows && lpRowAB);
+
+ m_database->SetListAddressTotal(listRow, numListElems);
+ return rv;
+}
+
+void nsOEAddressIterator::SanitizeValue(nsString& val)
+{
+ MsgReplaceSubstring(val, NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING(", "));
+ MsgReplaceChar(val, "\r\n", ',');
+}
+
+void nsOEAddressIterator::SplitString(nsString& val1, nsString& val2)
+{
+ // Find the last line if there is more than one!
+ int32_t idx = val1.RFind("\x0D\x0A");
+ int32_t cnt = 2;
+ if (idx == -1) {
+ cnt = 1;
+ idx = val1.RFindChar(13);
+ }
+ if (idx == -1)
+ idx= val1.RFindChar(10);
+ if (idx != -1) {
+ val2 = Substring(val1, idx + cnt);
+ val1.SetLength(idx);
+ SanitizeValue(val1);
+ }
+}
+
+void nsOEAddressIterator::SetBirthDay(nsIMdbRow *newRow, PRTime& birthDay)
+{
+ PRExplodedTime exploded;
+ PR_ExplodeTime(birthDay, PR_LocalTimeParameters, &exploded);
+
+ char stringValue[5];
+ PR_snprintf(stringValue, sizeof(stringValue), "%04d", exploded.tm_year);
+ m_database->AddBirthYear(newRow, stringValue);
+ PR_snprintf(stringValue, sizeof(stringValue), "%02d", exploded.tm_month + 1);
+ m_database->AddBirthMonth(newRow, stringValue);
+ PR_snprintf(stringValue, sizeof(stringValue), "%02d", exploded.tm_mday);
+ m_database->AddBirthDay(newRow, stringValue);
+}
+
+bool nsOEAddressIterator::BuildCard(const char16_t * pName, nsIMdbRow *newRow, LPMAILUSER pUser)
+{
+
+ nsString lastName;
+ nsString firstName;
+ nsString eMail;
+ nsString nickName;
+ nsString middleName;
+ PRTime birthDay = 0;
+
+ LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, eMail);
+ SanitizeValue(eMail);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_GIVEN_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, firstName);
+ SanitizeValue(firstName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_SURNAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, lastName);
+ SanitizeValue(lastName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_MIDDLE_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, middleName);
+ SanitizeValue(middleName);
+ m_pWab->FreeProperty(pProp);
+ }
+ pProp = m_pWab->GetUserProperty(pUser, PR_NICKNAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, nickName);
+ SanitizeValue(nickName);
+ m_pWab->FreeProperty(pProp);
+ }
+
+ // The idea here is that firstName and lastName cannot both be empty!
+ if (firstName.IsEmpty() && lastName.IsEmpty())
+ firstName = pName;
+
+ nsString displayName;
+ pProp = m_pWab->GetUserProperty(pUser, PR_DISPLAY_NAME);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, displayName);
+ SanitizeValue(displayName);
+ m_pWab->FreeProperty(pProp);
+ }
+ if (displayName.IsEmpty()) {
+ if (firstName.IsEmpty())
+ displayName = pName;
+ else {
+ displayName = firstName;
+ if (!middleName.IsEmpty()) {
+ displayName.Append(char16_t(' '));
+ displayName.Append(middleName);
+ }
+ if (!lastName.IsEmpty()) {
+ displayName.Append(char16_t(' '));
+ displayName.Append(lastName);
+ }
+ }
+ }
+
+ pProp = m_pWab->GetUserProperty(pUser, PR_BIRTHDAY);
+ if (pProp) {
+ m_pWab->GetValueTime(pProp, birthDay);
+ m_pWab->FreeProperty(pProp);
+ }
+
+ // We now have the required fields
+ // write them out followed by any optional fields!
+ if (!displayName.IsEmpty())
+ m_database->AddDisplayName(newRow, NS_ConvertUTF16toUTF8(displayName).get());
+ if (!firstName.IsEmpty())
+ m_database->AddFirstName(newRow, NS_ConvertUTF16toUTF8(firstName).get());
+ if (!lastName.IsEmpty())
+ m_database->AddLastName(newRow, NS_ConvertUTF16toUTF8(lastName).get());
+ if (!nickName.IsEmpty())
+ m_database->AddNickName(newRow, NS_ConvertUTF16toUTF8(nickName).get());
+ if (!eMail.IsEmpty())
+ m_database->AddPrimaryEmail(newRow, NS_ConvertUTF16toUTF8(eMail).get());
+
+ if (birthDay)
+ SetBirthDay(newRow, birthDay);
+
+ // Do all of the extra fields!
+
+ nsString value;
+ nsString line2;
+ nsresult rv;
+ // Create a field map
+
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ nsIImportFieldMap * pFieldMap = nullptr;
+ rv = impSvc->CreateNewFieldMap(&pFieldMap);
+ if (NS_SUCCEEDED(rv) && pFieldMap) {
+ int max = sizeof(gMapiFields) / sizeof(MAPIFields);
+ for (int i = 0; i < max; i++) {
+ pProp = m_pWab->GetUserProperty(pUser, gMapiFields[i].mapiTag);
+ if (pProp) {
+ m_pWab->GetValueString(pProp, value);
+ m_pWab->FreeProperty(pProp);
+ if (!value.IsEmpty()) {
+ if (gMapiFields[i].multiLine == kNoMultiLine) {
+ SanitizeValue(value);
+ pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].mozField, value.get());
+ }
+ else if (gMapiFields[i].multiLine == kIsMultiLine) {
+ pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].mozField, value.get());
+ }
+ else {
+ line2.Truncate();
+ SplitString(value, line2);
+ if (!value.IsEmpty())
+ pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].mozField, value.get());
+ if (!line2.IsEmpty())
+ pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].multiLine, line2.get());
+ }
+ }
+ }
+ }
+ // call fieldMap SetFieldValue based on the table of fields
+
+ NS_RELEASE(pFieldMap);
+ }
+ }
+ return true;
+}
diff --git a/mailnews/import/oexpress/nsOEAddressIterator.h b/mailnews/import/oexpress/nsOEAddressIterator.h
new file mode 100644
index 000000000..fe6082736
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEAddressIterator.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOEAddressIterator_h___
+#define nsOEAddressIterator_h___
+
+#include "mozilla/Attributes.h"
+#include "WabObject.h"
+#include "nsIAddrDatabase.h"
+#include "mdb.h"
+#include "nsStringGlue.h"
+#include "nsInterfaceHashtable.h"
+
+class nsOEAddressIterator : public CWabIterator {
+public:
+ nsOEAddressIterator(CWAB *pWab, nsIAddrDatabase *database);
+ ~nsOEAddressIterator();
+
+ virtual nsresult EnumUser(const char16_t * pName, LPENTRYID pEid, ULONG cbEid) override;
+ virtual nsresult EnumList(const char16_t * pName, LPENTRYID pEid, ULONG cbEid, LPMAPITABLE table) override;
+ void FindListRow(nsString &eMail, nsIMdbRow **cardRow);
+
+private:
+ bool BuildCard(const char16_t * pName, nsIMdbRow *card, LPMAILUSER pUser);
+ void SanitizeValue(nsString& val);
+ void SplitString(nsString& val1, nsString& val2);
+ void SetBirthDay(nsIMdbRow *card, PRTime& birthDay);
+
+ CWAB * m_pWab;
+ nsCOMPtr<nsIAddrDatabase> m_database;
+ nsInterfaceHashtable <nsStringHashKey, nsIMdbRow> m_listRows;
+};
+
+#endif
diff --git a/mailnews/import/oexpress/nsOEImport.cpp b/mailnews/import/oexpress/nsOEImport.cpp
new file mode 100644
index 000000000..21016c59e
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEImport.cpp
@@ -0,0 +1,657 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/*
+
+ Outlook Express (Win32) import mail and addressbook interfaces
+
+*/
+#include "nscore.h"
+#include "nsMsgUtils.h"
+#include "nsStringGlue.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIImportService.h"
+#include "nsOEImport.h"
+#include "nsIMemory.h"
+#include "nsOEScanBoxes.h"
+#include "nsIImportService.h"
+#include "nsIImportMail.h"
+#include "nsIImportMailboxDescriptor.h"
+#include "nsIImportGeneric.h"
+#include "nsOEMailbox.h"
+#include "nsIImportAddressBooks.h"
+#include "nsIImportABDescriptor.h"
+#include "nsIImportFieldMap.h"
+#include "nsIMutableArray.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "WabObject.h"
+#include "nsOEAddressIterator.h"
+#include "nsIOutputStream.h"
+#include "nsOE5File.h"
+#include "nsIAddrDatabase.h"
+#include "nsOESettings.h"
+#include "nsTextFormatter.h"
+#include "nsOEStringBundle.h"
+#include "nsIStringBundle.h"
+#include "nsUnicharUtils.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+
+#include "OEDebugLog.h"
+
+static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
+PRLogModuleInfo *OELOGMODULE = nullptr;
+
+class ImportOEMailImpl : public nsIImportMail
+{
+public:
+ ImportOEMailImpl();
+
+ static nsresult Create(nsIImportMail** aImport);
+
+ // nsISupports interface
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // nsIImportmail interface
+
+ /* void GetDefaultLocation (out nsIFile location, out boolean found, out boolean userVerify); */
+ NS_IMETHOD GetDefaultLocation(nsIFile **location, bool *found, bool *userVerify);
+
+ /* nsIArray FindMailboxes (in nsIFile location); */
+ NS_IMETHOD FindMailboxes(nsIFile *location, nsIArray **_retval);
+
+ NS_IMETHOD ImportMailbox(nsIImportMailboxDescriptor *source,
+ nsIMsgFolder *dstFolder,
+ char16_t **pErrorLog, char16_t **pSuccessLog,
+ bool *fatalError);
+
+ /* unsigned long GetImportProgress (); */
+ NS_IMETHOD GetImportProgress(uint32_t *_retval);
+
+ NS_IMETHOD TranslateFolderName(const nsAString & aFolderName, nsAString & _retval);
+
+public:
+ static void ReportSuccess(nsString& name, int32_t count, nsString *pStream);
+ static void ReportError(int32_t errorNum, nsString& name, nsString *pStream);
+ static void AddLinebreak(nsString *pStream);
+ static void SetLogs(nsString& success, nsString& error, char16_t **pError, char16_t **pSuccess);
+
+private:
+ virtual ~ImportOEMailImpl();
+ uint32_t m_bytesDone;
+};
+
+
+class ImportOEAddressImpl : public nsIImportAddressBooks
+{
+public:
+ ImportOEAddressImpl();
+
+ static nsresult Create(nsIImportAddressBooks** aImport);
+
+ // nsISupports interface
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // nsIImportAddressBooks interface
+
+ NS_IMETHOD GetSupportsMultiple(bool *_retval) { *_retval = false; return NS_OK;}
+
+ NS_IMETHOD GetAutoFind(char16_t **description, bool *_retval);
+
+ NS_IMETHOD GetNeedsFieldMap(nsIFile *pLoc, bool *_retval) { *_retval = false; return NS_OK;}
+
+ NS_IMETHOD GetDefaultLocation(nsIFile **location, bool *found, bool *userVerify);
+
+ NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval);
+
+ NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap)
+ { return NS_ERROR_FAILURE; }
+
+ NS_IMETHOD ImportAddressBook(nsIImportABDescriptor *source,
+ nsIAddrDatabase *destination,
+ nsIImportFieldMap *fieldMap,
+ nsISupports *aSupportService,
+ char16_t **errorLog,
+ char16_t **successLog,
+ bool *fatalError);
+
+ NS_IMETHOD GetImportProgress(uint32_t *_retval);
+
+ NS_IMETHOD GetSampleData(int32_t index, bool *pFound, char16_t **pStr)
+ { return NS_ERROR_FAILURE;}
+
+ NS_IMETHOD SetSampleLocation(nsIFile *) { return NS_OK; }
+
+private:
+ virtual ~ImportOEAddressImpl();
+ static void ReportSuccess(nsString& name, nsString *pStream);
+
+private:
+ CWAB * m_pWab;
+ int m_doneSoFar;
+};
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+
+
+nsOEImport::nsOEImport()
+{
+ // Init logging module.
+ if (!OELOGMODULE)
+ OELOGMODULE = PR_NewLogModule("IMPORT");
+ IMPORT_LOG0("nsOEImport Module Created\n");
+ nsOEStringBundle::GetStringBundle();
+}
+
+
+nsOEImport::~nsOEImport()
+{
+ IMPORT_LOG0("nsOEImport Module Deleted\n");
+}
+
+NS_IMPL_ISUPPORTS(nsOEImport, nsIImportModule)
+
+NS_IMETHODIMP nsOEImport::GetName(char16_t **name)
+{
+ NS_ENSURE_ARG_POINTER(name);
+
+ *name = nsOEStringBundle::GetStringByID(OEIMPORT_NAME);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsOEImport::GetDescription(char16_t **name)
+{
+ NS_ENSURE_ARG_POINTER(name);
+
+ *name = nsOEStringBundle::GetStringByID(OEIMPORT_DESCRIPTION);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsOEImport::GetSupports(char **supports)
+{
+ NS_PRECONDITION(supports != nullptr, "null ptr");
+ if (! supports)
+ return NS_ERROR_NULL_POINTER;
+
+ *supports = strdup(kOESupportsString);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsOEImport::GetSupportsUpgrade(bool *pUpgrade)
+{
+ NS_PRECONDITION(pUpgrade != nullptr, "null ptr");
+ if (! pUpgrade)
+ return NS_ERROR_NULL_POINTER;
+
+ *pUpgrade = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsOEImport::GetImportInterface(const char *pImportType, nsISupports **ppInterface)
+{
+ NS_ENSURE_ARG_POINTER(pImportType);
+ NS_ENSURE_ARG_POINTER(ppInterface);
+
+ *ppInterface = nullptr;
+ nsresult rv;
+ if (!strcmp(pImportType, "mail")) {
+ // create the nsIImportMail interface and return it!
+ nsIImportMail * pMail = nullptr;
+ nsIImportGeneric *pGeneric = nullptr;
+ rv = ImportOEMailImpl::Create(&pMail);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ rv = impSvc->CreateNewGenericMail(&pGeneric);
+ if (NS_SUCCEEDED(rv)) {
+ pGeneric->SetData("mailInterface", pMail);
+ nsString name;
+ nsOEStringBundle::GetStringByID(OEIMPORT_NAME, name);
+ nsCOMPtr<nsISupportsString> nameString (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ nameString->SetData(name);
+ pGeneric->SetData("name", nameString);
+ rv = pGeneric->QueryInterface(kISupportsIID, (void **)ppInterface);
+ }
+ }
+ }
+ }
+ NS_IF_RELEASE(pMail);
+ NS_IF_RELEASE(pGeneric);
+ return rv;
+ }
+
+ if (!strcmp(pImportType, "addressbook")) {
+ // create the nsIImportMail interface and return it!
+ nsIImportAddressBooks * pAddress = nullptr;
+ nsIImportGeneric * pGeneric = nullptr;
+ rv = ImportOEAddressImpl::Create(&pAddress);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ rv = impSvc->CreateNewGenericAddressBooks(&pGeneric);
+ if (NS_SUCCEEDED(rv)) {
+ pGeneric->SetData("addressInterface", pAddress);
+ rv = pGeneric->QueryInterface(kISupportsIID, (void **)ppInterface);
+ }
+ }
+ }
+ NS_IF_RELEASE(pAddress);
+ NS_IF_RELEASE(pGeneric);
+ return rv;
+ }
+
+ if (!strcmp(pImportType, "settings")) {
+ nsIImportSettings *pSettings = nullptr;
+ rv = nsOESettings::Create(&pSettings);
+ if (NS_SUCCEEDED(rv))
+ pSettings->QueryInterface(kISupportsIID, (void **)ppInterface);
+ NS_IF_RELEASE(pSettings);
+ return rv;
+ }
+
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+nsresult ImportOEMailImpl::Create(nsIImportMail** aImport)
+{
+ NS_ENSURE_ARG_POINTER(aImport);
+ *aImport = new ImportOEMailImpl();
+ NS_ENSURE_TRUE(*aImport, NS_ERROR_OUT_OF_MEMORY);
+ NS_ADDREF(*aImport);
+ return NS_OK;
+}
+
+ImportOEMailImpl::ImportOEMailImpl()
+{
+}
+
+
+ImportOEMailImpl::~ImportOEMailImpl()
+{
+}
+
+NS_IMPL_ISUPPORTS(ImportOEMailImpl, nsIImportMail)
+
+NS_IMETHODIMP ImportOEMailImpl::TranslateFolderName(const nsAString & aFolderName, nsAString & _retval)
+{
+ if (aFolderName.LowerCaseEqualsLiteral("deleted items"))
+ _retval = NS_LITERAL_STRING(kDestTrashFolderName);
+ else if (aFolderName.LowerCaseEqualsLiteral("sent items"))
+ _retval = NS_LITERAL_STRING(kDestSentFolderName);
+ else if (aFolderName.LowerCaseEqualsLiteral("outbox"))
+ _retval = NS_LITERAL_STRING(kDestUnsentMessagesFolderName);
+ else
+ _retval = aFolderName;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP ImportOEMailImpl::GetDefaultLocation(nsIFile **ppLoc, bool *found, bool *userVerify)
+{
+ NS_PRECONDITION(ppLoc != nullptr, "null ptr");
+ NS_PRECONDITION(found != nullptr, "null ptr");
+ NS_PRECONDITION(userVerify != nullptr, "null ptr");
+ if (!ppLoc || !found || !userVerify)
+ return NS_ERROR_NULL_POINTER;
+
+ // use scanboxes to find the location.
+ nsresult rv;
+ nsCOMPtr <nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (nsOEScanBoxes::FindMail(file)) {
+ *found = true;
+ NS_IF_ADDREF(*ppLoc = file);
+ }
+ else {
+ *found = false;
+ *ppLoc = nullptr;
+ }
+ *userVerify = true;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP ImportOEMailImpl::FindMailboxes(nsIFile *pLoc, nsIArray **ppArray)
+{
+ NS_PRECONDITION(pLoc != nullptr, "null ptr");
+ NS_PRECONDITION(ppArray != nullptr, "null ptr");
+ if (!pLoc || !ppArray)
+ return NS_ERROR_NULL_POINTER;
+
+ bool exists = false;
+ nsresult rv = pLoc->Exists(&exists);
+ if (NS_FAILED(rv) || !exists)
+ return NS_ERROR_FAILURE;
+
+ nsOEScanBoxes scan;
+
+ if (!scan.GetMailboxes(pLoc, ppArray))
+ *ppArray = nullptr;
+
+ return NS_OK;
+}
+
+void ImportOEMailImpl::AddLinebreak(nsString *pStream)
+{
+ if (pStream)
+ pStream->Append(char16_t('\n'));
+}
+
+void ImportOEMailImpl::ReportSuccess(nsString& name, int32_t count, nsString *pStream)
+{
+ if (!pStream)
+ return;
+ // load the success string
+ char16_t *pFmt = nsOEStringBundle::GetStringByID(OEIMPORT_MAILBOX_SUCCESS);
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get(), count);
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ nsOEStringBundle::FreeString(pFmt);
+ AddLinebreak(pStream);
+}
+
+void ImportOEMailImpl::ReportError(int32_t errorNum, nsString& name, nsString *pStream)
+{
+ if (!pStream)
+ return;
+ // load the error string
+ char16_t *pFmt = nsOEStringBundle::GetStringByID(errorNum);
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get());
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ nsOEStringBundle::FreeString(pFmt);
+ AddLinebreak(pStream);
+}
+
+
+void ImportOEMailImpl::SetLogs(nsString& success, nsString& error, char16_t **pError, char16_t **pSuccess)
+{
+ if (pError)
+ *pError = ToNewUnicode(error);
+ if (pSuccess)
+ *pSuccess = ToNewUnicode(success);
+}
+
+NS_IMETHODIMP ImportOEMailImpl::ImportMailbox(nsIImportMailboxDescriptor *pSource,
+ nsIMsgFolder *dstFolder,
+ char16_t **pErrorLog,
+ char16_t **pSuccessLog,
+ bool *fatalError)
+{
+ NS_ENSURE_ARG_POINTER(pSource);
+ NS_ENSURE_ARG_POINTER(dstFolder);
+ NS_ENSURE_ARG_POINTER(fatalError);
+
+ nsString success;
+ nsString error;
+ bool abort = false;
+ nsString name;
+ nsString pName;
+ if (NS_SUCCEEDED(pSource->GetDisplayName(getter_Copies(pName))))
+ name = pName;
+
+ uint32_t mailSize = 0;
+ pSource->GetSize(&mailSize);
+ if (mailSize == 0) {
+ ReportSuccess(name, 0, &success);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ return NS_OK;
+ }
+
+ nsCOMPtr <nsIFile> inFile;
+ if (NS_FAILED(pSource->GetFile(getter_AddRefs(inFile)))) {
+ ReportError(OEIMPORT_MAILBOX_BADSOURCEFILE, name, &error);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCString pPath;
+ inFile->GetNativePath(pPath);
+ IMPORT_LOG1("Importing Outlook Express mailbox: %s\n", pPath.get());
+
+ m_bytesDone = 0;
+ uint32_t msgCount = 0;
+ nsresult rv;
+ if (nsOE5File::IsLocalMailFile(inFile)) {
+ IMPORT_LOG1("Importing OE5 mailbox: %s!\n", NS_LossyConvertUTF16toASCII(name.get()));
+ rv = nsOE5File::ImportMailbox( &m_bytesDone, &abort, name, inFile, dstFolder, &msgCount);
+ }
+ else {
+ if (CImportMailbox::ImportMailbox( &m_bytesDone, &abort, name, inFile, dstFolder, &msgCount))
+ rv = NS_OK;
+ else
+ rv = NS_ERROR_FAILURE;
+ }
+
+ if (NS_SUCCEEDED(rv))
+ ReportSuccess(name, msgCount, &success);
+ else
+ ReportError(OEIMPORT_MAILBOX_CONVERTERROR, name, &error);
+
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+
+ return rv;
+}
+
+NS_IMETHODIMP ImportOEMailImpl::GetImportProgress(uint32_t *pDoneSoFar)
+{
+ NS_ENSURE_ARG_POINTER(pDoneSoFar);
+ *pDoneSoFar = m_bytesDone;
+ return NS_OK;
+}
+
+nsresult ImportOEAddressImpl::Create(nsIImportAddressBooks** aImport)
+{
+ NS_ENSURE_ARG_POINTER(aImport);
+
+ *aImport = new ImportOEAddressImpl();
+ NS_ENSURE_TRUE(*aImport, NS_ERROR_OUT_OF_MEMORY);
+ NS_ADDREF(*aImport);
+ return NS_OK;
+}
+
+ImportOEAddressImpl::ImportOEAddressImpl()
+{
+ m_pWab = nullptr;
+}
+
+
+ImportOEAddressImpl::~ImportOEAddressImpl()
+{
+ if (m_pWab)
+ delete m_pWab;
+}
+
+NS_IMPL_ISUPPORTS(ImportOEAddressImpl, nsIImportAddressBooks)
+
+NS_IMETHODIMP ImportOEAddressImpl::GetDefaultLocation(nsIFile **aLocation,
+ bool *aFound,
+ bool *aUserVerify)
+{
+ NS_ENSURE_ARG_POINTER(aLocation);
+ NS_ENSURE_ARG_POINTER(aFound);
+ NS_ENSURE_ARG_POINTER(aUserVerify);
+
+ *aLocation = nullptr;
+ *aUserVerify = true;
+
+ CWAB *wab = new CWAB(nullptr);
+ *aFound = wab->IsAvailable();
+ delete wab;
+
+ if (*aFound) {
+ // Unfortunately WAB interface has no function to obtain address book location.
+ // So we set a fake location here.
+ if (NS_SUCCEEDED(NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, aLocation)))
+ *aUserVerify = false;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP ImportOEAddressImpl::GetAutoFind(char16_t **description, bool *_retval)
+{
+ NS_PRECONDITION(description != nullptr, "null ptr");
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (! description || !_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = false;
+ nsString str;
+ str.Append(nsOEStringBundle::GetStringByID(OEIMPORT_AUTOFIND));
+ *description = ToNewUnicode(str);
+ return NS_OK;
+}
+
+
+
+NS_IMETHODIMP ImportOEAddressImpl::FindAddressBooks(nsIFile *location, nsIArray **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ nsresult rv;
+ nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+
+ // Make sure we can load up the windows address book...
+ rv = NS_ERROR_FAILURE;
+
+ if (m_pWab)
+ delete m_pWab;
+
+ nsCOMPtr<nsIFile> currentProcessDir;
+ rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
+ getter_AddRefs(currentProcessDir));
+ bool equals = false;
+ currentProcessDir->Equals(location, &equals);
+ // If the location is not a fake, use it.
+ if (location && !equals) {
+ nsCOMPtr<nsIFile> localFile = do_QueryInterface(location, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ m_pWab = new CWAB(localFile);
+ } else {
+ m_pWab = new CWAB(nullptr);
+ }
+
+ nsIImportABDescriptor * pID;
+ nsISupports * pInterface;
+ nsString str;
+ str.Append(nsOEStringBundle::GetStringByID(OEIMPORT_DEFAULT_NAME));
+
+ if (m_pWab->Loaded()) {
+ // create a new nsIImportABDescriptor and add it to the array
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ rv = impSvc->CreateNewABDescriptor(&pID);
+ if (NS_SUCCEEDED(rv)) {
+ pID->SetIdentifier(0x4F453334);
+ pID->SetRef(1);
+ pID->SetSize(100);
+ pID->SetPreferredName(str);
+ rv = pID->QueryInterface(kISupportsIID, (void **) &pInterface);
+ array->AppendElement(pInterface, false);
+ pInterface->Release();
+ pID->Release();
+ }
+ }
+ }
+
+ if (NS_FAILED(rv)) {
+ delete m_pWab;
+ m_pWab = nullptr;
+ }
+ array.forget(_retval);
+ return NS_OK;
+}
+
+
+
+NS_IMETHODIMP ImportOEAddressImpl::ImportAddressBook(nsIImportABDescriptor *source,
+ nsIAddrDatabase *destination,
+ nsIImportFieldMap *fieldMap,
+ nsISupports *aSupportService,
+ char16_t **errorLog,
+ char16_t **successLog,
+ bool *fatalError)
+{
+ NS_PRECONDITION(source != nullptr, "null ptr");
+ // NS_PRECONDITION(destination != nullptr, "null ptr");
+ // NS_PRECONDITION(fieldMap != nullptr, "null ptr");
+ NS_PRECONDITION(fatalError != nullptr, "null ptr");
+ if (!source || !fatalError)
+ return NS_ERROR_NULL_POINTER;
+
+ // we assume it is our one and only address book.
+ if (!m_pWab) {
+ IMPORT_LOG0("Wab not loaded in ImportAddressBook call\n");
+ return NS_ERROR_FAILURE;
+ }
+
+ IMPORT_LOG0("IMPORTING OUTLOOK EXPRESS ADDRESS BOOK\n");
+
+ nsString success;
+ nsString error;
+ if (!source || !destination || !fatalError)
+ {
+ nsOEStringBundle::GetStringByID(OEIMPORT_ADDRESS_BADPARAM, error);
+ if (fatalError)
+ *fatalError = true;
+ ImportOEMailImpl::SetLogs(success, error, errorLog, successLog);
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ m_doneSoFar = 0;
+ nsOEAddressIterator * pIter = new nsOEAddressIterator(m_pWab, destination);
+ HRESULT hr = m_pWab->IterateWABContents(pIter, &m_doneSoFar);
+ delete pIter;
+
+ nsString name;
+ if (SUCCEEDED(hr) && NS_SUCCEEDED(source->GetPreferredName(name)))
+ ReportSuccess(name, &success);
+ else
+ ImportOEMailImpl::ReportError(OEIMPORT_ADDRESS_CONVERTERROR, name, &error);
+
+ ImportOEMailImpl::SetLogs(success, error, errorLog, successLog);
+
+ nsresult rv = destination->Commit(nsAddrDBCommitType::kLargeCommit);
+ return rv;
+}
+
+
+NS_IMETHODIMP ImportOEAddressImpl::GetImportProgress(uint32_t *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (! _retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = (uint32_t) m_doneSoFar;
+ return NS_OK;
+}
+
+void ImportOEAddressImpl::ReportSuccess(nsString& name, nsString *pStream)
+{
+ if (!pStream)
+ return;
+ // load the success string
+ char16_t *pFmt = nsOEStringBundle::GetStringByID(OEIMPORT_ADDRESS_SUCCESS);
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get());
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ nsOEStringBundle::FreeString(pFmt);
+ ImportOEMailImpl::AddLinebreak(pStream);
+}
diff --git a/mailnews/import/oexpress/nsOEImport.h b/mailnews/import/oexpress/nsOEImport.h
new file mode 100644
index 000000000..c637a7461
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEImport.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOEImport_h___
+#define nsOEImport_h___
+
+#include "nsIImportModule.h"
+#include "nsCOMPtr.h"
+
+#define NS_OEIMPORT_CID \
+{ /* be0bc880-1742-11d3-a206-00a0cc26da63 */ \
+ 0xbe0bc880, 0x1742, 0x11d3, \
+ {0xa2, 0x06, 0x0, 0xa0, 0xcc, 0x26, 0xda, 0x63}}
+
+
+
+#define kOESupportsString NS_IMPORT_MAIL_STR "," NS_IMPORT_ADDRESS_STR "," NS_IMPORT_SETTINGS_STR
+
+class nsOEImport : public nsIImportModule
+{
+public:
+
+ nsOEImport();
+
+ NS_DECL_ISUPPORTS
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // we suppport the nsIImportModule interface
+ ////////////////////////////////////////////////////////////////////////////////////////
+
+
+ NS_DECL_NSIIMPORTMODULE
+
+protected:
+ virtual ~nsOEImport();
+};
+
+
+
+#endif /* nsOEImport_h___ */
diff --git a/mailnews/import/oexpress/nsOEMailbox.cpp b/mailnews/import/oexpress/nsOEMailbox.cpp
new file mode 100644
index 000000000..7a1fb0be7
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEMailbox.cpp
@@ -0,0 +1,673 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsOEMailbox.h"
+
+#include "OEDebugLog.h"
+#include "msgCore.h"
+#include "prprf.h"
+#include "nsMsgLocalFolderHdrs.h"
+#include "nsCRT.h"
+#include "nsNetUtil.h"
+#include "nsIInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsIMsgFolder.h"
+#include "nsIMsgHdr.h"
+#include "nsIMsgPluggableStore.h"
+#include "nsISeekableStream.h"
+#include "nsMsgUtils.h"
+
+class CMbxScanner {
+public:
+ CMbxScanner(nsString& name, nsIFile * mbxFile, nsIMsgFolder *dstFolder);
+ ~CMbxScanner();
+
+ virtual bool Initialize(void);
+ virtual bool DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount);
+
+ bool WasErrorFatal(void) { return m_fatalError;}
+ uint32_t BytesProcessed(void) { return m_didBytes;}
+
+protected:
+ bool WriteMailItem(uint32_t flags, uint32_t offset, uint32_t size, uint32_t *pTotalMsgSize = nullptr);
+ virtual void CleanUp(void);
+
+private:
+ void ReportWriteError(nsIMsgFolder *folder, bool fatal = true);
+ void ReportReadError(nsIFile * file, bool fatal = true);
+ bool CopyMbxFileBytes(uint32_t flags, uint32_t numBytes);
+ bool IsFromLineKey(uint8_t *pBuf, uint32_t max);
+
+public:
+ uint32_t m_msgCount;
+
+protected:
+ uint32_t * m_pDone;
+ nsString m_name;
+ nsCOMPtr<nsIFile> m_mbxFile;
+ nsCOMPtr<nsIMsgFolder> m_dstFolder;
+ nsCOMPtr<nsIInputStream> m_mbxFileInputStream;
+ nsCOMPtr<nsIOutputStream> m_dstOutputStream;
+ nsCOMPtr<nsIMsgPluggableStore> m_msgStore;
+ uint8_t * m_pInBuffer;
+ uint8_t * m_pOutBuffer;
+ uint32_t m_bufSz;
+ uint32_t m_didBytes;
+ bool m_fatalError;
+ int64_t m_mbxFileSize;
+ uint32_t m_mbxOffset;
+
+ static const char * m_pFromLine;
+
+};
+
+
+class CIndexScanner : public CMbxScanner {
+public:
+ CIndexScanner(nsString& name, nsIFile * idxFile, nsIFile * mbxFile, nsIMsgFolder *dstFolder);
+ ~CIndexScanner();
+
+ virtual bool Initialize(void);
+ virtual bool DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount);
+
+protected:
+ virtual void CleanUp(void);
+
+private:
+ bool ValidateIdxFile(void);
+ bool GetMailItem(uint32_t *pFlags, uint32_t *pOffset, uint32_t *pSize);
+
+
+private:
+ nsCOMPtr <nsIFile> m_idxFile;
+ nsCOMPtr <nsIInputStream> m_idxFileInputStream;
+ uint32_t m_numMessages;
+ uint32_t m_idxOffset;
+ uint32_t m_curItemIndex;
+};
+
+
+bool CImportMailbox::ImportMailbox(uint32_t *pDone, bool *pAbort,
+ nsString& name, nsIFile * inFile,
+ nsIMsgFolder *outFolder, uint32_t *pCount)
+{
+ bool done = false;
+ nsresult rv;
+ nsCOMPtr <nsIFile> idxFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ rv = idxFile->InitWithFile(inFile);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("New file spec failed!\n");
+ return false;
+ }
+
+ if (GetIndexFile(idxFile)) {
+
+ IMPORT_LOG1("Using index file for: %S\n", name.get());
+
+ CIndexScanner *pIdxScanner = new CIndexScanner(name, idxFile, inFile, outFolder);
+ if (pIdxScanner->Initialize()) {
+ if (pIdxScanner->DoWork(pAbort, pDone, pCount)) {
+ done = true;
+ }
+ else {
+ IMPORT_LOG0("CIndexScanner::DoWork() failed\n");
+ }
+ }
+ else {
+ IMPORT_LOG0("CIndexScanner::Initialize() failed\n");
+ }
+
+ delete pIdxScanner;
+ }
+
+ if (done)
+ return done;
+
+ /*
+ something went wrong with the index file, just scan the mailbox
+ file itself.
+ */
+ CMbxScanner *pMbx = new CMbxScanner(name, inFile, outFolder);
+ if (pMbx->Initialize()) {
+ if (pMbx->DoWork(pAbort, pDone, pCount)) {
+ done = true;
+ }
+ else {
+ IMPORT_LOG0("CMbxScanner::DoWork() failed\n");
+ }
+ }
+ else {
+ IMPORT_LOG0("CMbxScanner::Initialize() failed\n");
+ }
+
+ delete pMbx;
+ return done;
+}
+
+
+bool CImportMailbox::GetIndexFile(nsIFile* file)
+{
+ nsCString pLeaf;
+ if (NS_FAILED(file->GetNativeLeafName(pLeaf)))
+ return false;
+ int32_t len = pLeaf.Length();
+ if (len < 5)
+ return false;
+
+ pLeaf.Replace(len - 3, 3, NS_LITERAL_CSTRING("idx"));
+
+ IMPORT_LOG1("Looking for index leaf name: %s\n", pLeaf);
+
+ nsresult rv;
+ rv = file->SetNativeLeafName(pLeaf);
+
+ bool isFile = false;
+ bool exists = false;
+ if (NS_SUCCEEDED(rv)) rv = file->IsFile(&isFile);
+ if (NS_SUCCEEDED(rv)) rv = file->Exists(&exists);
+
+ return (isFile && exists);
+}
+
+
+const char *CMbxScanner::m_pFromLine = "From - Mon Jan 1 00:00:00 1965\x0D\x0A";
+// let's try a 16K buffer and see how well that works?
+#define kBufferKB 16
+
+
+CMbxScanner::CMbxScanner(nsString& name, nsIFile* mbxFile,
+ nsIMsgFolder* dstFolder)
+{
+ m_msgCount = 0;
+ m_name = name;
+ m_mbxFile = mbxFile;
+ m_dstFolder = dstFolder;
+ m_pInBuffer = nullptr;
+ m_pOutBuffer = nullptr;
+ m_bufSz = 0;
+ m_fatalError = false;
+ m_didBytes = 0;
+ m_mbxFileSize = 0;
+ m_mbxOffset = 0;
+}
+
+CMbxScanner::~CMbxScanner()
+{
+ CleanUp();
+}
+
+void CMbxScanner::ReportWriteError(nsIMsgFolder * folder, bool fatal)
+{
+ m_fatalError = fatal;
+}
+
+void CMbxScanner::ReportReadError(nsIFile * file, bool fatal)
+{
+ m_fatalError = fatal;
+}
+
+bool CMbxScanner::Initialize(void)
+{
+ m_bufSz = (kBufferKB * 1024);
+ m_pInBuffer = new uint8_t[m_bufSz];
+ m_pOutBuffer = new uint8_t[m_bufSz];
+ if (!m_pInBuffer || !m_pOutBuffer) {
+ return false;
+ }
+
+ m_mbxFile->GetFileSize(&m_mbxFileSize);
+ // open the mailbox file...
+ if (NS_FAILED(NS_NewLocalFileInputStream(getter_AddRefs(m_mbxFileInputStream), m_mbxFile))) {
+ CleanUp();
+ return false;
+ }
+
+ if (NS_FAILED(m_dstFolder->GetMsgStore(getter_AddRefs(m_msgStore)))) {
+ CleanUp();
+ return false;
+ }
+
+ return true;
+}
+
+
+#define kMbxHeaderSize 0x0054
+#define kMbxMessageHeaderSz 16
+
+bool CMbxScanner::DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount)
+{
+ m_mbxOffset = kMbxHeaderSize;
+ m_didBytes = kMbxHeaderSize;
+
+ while (!(*pAbort) && ((m_mbxOffset + kMbxMessageHeaderSz) < m_mbxFileSize)) {
+ uint32_t msgSz;
+ if (!WriteMailItem(0, m_mbxOffset, 0, &msgSz)) {
+ if (!WasErrorFatal())
+ ReportReadError(m_mbxFile);
+ return false;
+ }
+ m_mbxOffset += msgSz;
+ m_didBytes += msgSz;
+ m_msgCount++;
+ if (pDone)
+ *pDone = m_didBytes;
+ if (pCount)
+ *pCount = m_msgCount;
+ }
+
+ CleanUp();
+
+ return true;
+}
+
+
+void CMbxScanner::CleanUp(void)
+{
+ if (m_mbxFileInputStream)
+ m_mbxFileInputStream->Close();
+ if (m_dstOutputStream)
+ m_dstOutputStream->Close();
+
+ delete [] m_pInBuffer;
+ m_pInBuffer = nullptr;
+
+ delete [] m_pOutBuffer;
+ m_pOutBuffer = nullptr;
+}
+
+
+#define kNumMbxLongsToRead 4
+
+bool CMbxScanner::WriteMailItem(uint32_t flags, uint32_t offset, uint32_t size,
+ uint32_t *pTotalMsgSize)
+{
+ uint32_t values[kNumMbxLongsToRead];
+ int32_t cnt = kNumMbxLongsToRead * sizeof(uint32_t);
+ nsresult rv;
+ uint32_t cntRead;
+ int8_t * pChar = (int8_t *) values;
+
+ nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(m_mbxFileInputStream);
+ rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG1("Mbx seek error: 0x%lx\n", offset);
+ return false;
+ }
+ rv = m_mbxFileInputStream->Read((char *) pChar, cnt, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != cnt)) {
+ IMPORT_LOG1("Mbx read error at: 0x%lx\n", offset);
+ return false;
+ }
+ if (values[0] != 0x7F007F00) {
+ IMPORT_LOG2("Mbx tag field doesn't match: 0x%lx, at offset: 0x%lx\n", values[0], offset);
+ return false;
+ }
+ if (size && (values[2] != size)) {
+ IMPORT_LOG3("Mbx size doesn't match idx, mbx: %ld, idx: %ld, at offset: 0x%lx\n", values[2], size, offset);
+ return false;
+ }
+
+ if (pTotalMsgSize != nullptr)
+ *pTotalMsgSize = values[2];
+
+ nsCOMPtr<nsIMsgDBHdr> msgHdr;
+ bool reusable;
+
+ rv = m_msgStore->GetNewMsgOutputStream(m_dstFolder, getter_AddRefs(msgHdr), &reusable,
+ getter_AddRefs(m_dstOutputStream));
+ if (NS_FAILED(rv))
+ {
+ IMPORT_LOG1( "Mbx getting outputstream error: 0x%lx\n", rv);
+ return false;
+ }
+
+ // everything looks kosher...
+ // the actual message text follows and is values[3] bytes long...
+ bool copyOK = CopyMbxFileBytes(flags, values[3]);
+ if (copyOK)
+ m_msgStore->FinishNewMessage(m_dstOutputStream, msgHdr);
+ else {
+ m_msgStore->DiscardNewMessage(m_dstOutputStream, msgHdr);
+ IMPORT_LOG0( "Mbx CopyMbxFileBytes failed\n");
+ }
+ if (!reusable)
+ {
+ m_dstOutputStream->Close();
+ m_dstOutputStream = nullptr;
+ }
+ return copyOK;
+}
+
+bool CMbxScanner::IsFromLineKey(uint8_t * pBuf, uint32_t max)
+{
+ return (max > 5 && (pBuf[0] == 'F') && (pBuf[1] == 'r') && (pBuf[2] == 'o') && (pBuf[3] == 'm') && (pBuf[4] == ' '));
+}
+
+
+#define IS_ANY_SPACE(_ch) ((_ch == ' ') || (_ch == '\t') || (_ch == 10) || (_ch == 13))
+
+
+bool CMbxScanner::CopyMbxFileBytes(uint32_t flags, uint32_t numBytes)
+{
+ if (!numBytes)
+ return true;
+
+ uint32_t cnt;
+ uint8_t last[2] = {0, 0};
+ uint32_t inIdx = 0;
+ bool first = true;
+ uint8_t * pIn;
+ uint8_t * pStart;
+ int32_t fromLen = strlen(m_pFromLine);
+ nsresult rv;
+ uint32_t cntRead;
+ uint8_t * pChar;
+
+ while (numBytes) {
+ if (numBytes > (m_bufSz - inIdx))
+ cnt = m_bufSz - inIdx;
+ else
+ cnt = numBytes;
+ // Read some of the message from the file...
+ pChar = m_pInBuffer + inIdx;
+ rv = m_mbxFileInputStream->Read((char *) pChar, (int32_t)cnt, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != (int32_t)cnt)) {
+ ReportReadError(m_mbxFile);
+ return false;
+ }
+ // Keep track of the last 2 bytes of the message for terminating EOL logic
+ if (cnt < 2) {
+ last[0] = last[1];
+ last[1] = m_pInBuffer[cnt - 1];
+ }
+ else {
+ last[0] = m_pInBuffer[cnt - 2];
+ last[1] = m_pInBuffer[cnt - 1];
+ }
+
+ inIdx = 0;
+ // Handle the beginning line, don't duplicate an existing From separator
+ if (first) {
+ // check the first buffer to see if it already starts with a From line
+ // If it does, throw it away and use our own
+ if (IsFromLineKey(m_pInBuffer, cnt)) {
+ // skip past the first line
+ while ((inIdx < cnt) && (m_pInBuffer[inIdx] != nsCRT::CR))
+ inIdx++;
+ while ((inIdx < cnt) && (IS_ANY_SPACE(m_pInBuffer[inIdx])))
+ inIdx++;
+ if (inIdx >= cnt) {
+ // This should not occurr - it means the message starts
+ // with a From separator line that is longer than our
+ // file buffer! In this bizarre case, just skip this message
+ // since it is probably bogus anyway.
+ return true;
+ }
+
+ }
+ // Begin every message with a From separator
+ rv = m_dstOutputStream->Write(m_pFromLine, fromLen, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != fromLen)) {
+ ReportWriteError(m_dstFolder);
+ return false;
+ }
+ char statusLine[50];
+ uint32_t msgFlags = flags; // need to convert from OE flags to mozilla flags
+ PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF);
+ rv = m_dstOutputStream->Write(statusLine, strlen(statusLine), &cntRead);
+ if (NS_SUCCEEDED(rv) && cntRead == fromLen)
+ {
+ PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF0000);
+ rv = m_dstOutputStream->Write(statusLine, strlen(statusLine), &cntRead);
+ }
+ if (NS_FAILED(rv) || (cntRead != fromLen)) {
+ ReportWriteError(m_dstFolder);
+ return false;
+ }
+ first = false;
+ }
+
+ // Handle generic data, escape any lines that begin with "From "
+ pIn = m_pInBuffer + inIdx;
+ numBytes -= cnt;
+ m_didBytes += cnt;
+ pStart = pIn;
+ cnt -= inIdx;
+ inIdx = 0;
+ while (cnt) {
+ if (*pIn == nsCRT::CR) {
+ // need more in buffer?
+ if ((cnt < 7) && numBytes)
+ break;
+
+ if (cnt > 6) {
+ if ((pIn[1] == nsCRT::LF) && IsFromLineKey(pIn + 2, cnt)) {
+ inIdx += 2;
+ // Match, escape it
+ rv = m_dstOutputStream->Write((const char *)pStart, (int32_t)inIdx, &cntRead);
+ if (NS_SUCCEEDED(rv) && (cntRead == (int32_t)inIdx))
+ rv = m_dstOutputStream->Write(">", 1, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != 1)) {
+ ReportWriteError(m_dstFolder);
+ return false;
+ }
+
+ cnt -= 2;
+ pIn += 2;
+ inIdx = 0;
+ pStart = pIn;
+ continue;
+ }
+ }
+ } // == nsCRT::CR
+
+ cnt--;
+ inIdx++;
+ pIn++;
+ }
+ rv = m_dstOutputStream->Write((const char *)pStart, (int32_t)inIdx, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != (int32_t)inIdx)) {
+ ReportWriteError(m_dstFolder);
+ return false;
+ }
+
+ if (cnt) {
+ inIdx = cnt;
+ memcpy(m_pInBuffer, pIn, cnt);
+ }
+ else
+ inIdx = 0;
+ }
+
+ // I used to check for an eol before writing one but
+ // it turns out that adding a proper EOL before the next
+ // separator never really hurts so better to be safe
+ // and always do it.
+ // if ((last[0] != nsCRT::CR) || (last[1] != nsCRT::LF)) {
+ rv = m_dstOutputStream->Write("\x0D\x0A", 2, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != 2)) {
+ ReportWriteError(m_dstFolder);
+ return false;
+ }
+ // } // != nsCRT::CR || != nsCRT::LF
+
+ return true;
+}
+
+CIndexScanner::CIndexScanner(nsString& name, nsIFile * idxFile,
+ nsIFile * mbxFile, nsIMsgFolder * dstFolder)
+ : CMbxScanner( name, mbxFile, dstFolder)
+{
+ m_idxFile = idxFile;
+ m_curItemIndex = 0;
+ m_idxOffset = 0;
+}
+
+CIndexScanner::~CIndexScanner()
+{
+ CleanUp();
+}
+
+bool CIndexScanner::Initialize(void)
+{
+ if (!CMbxScanner::Initialize())
+ return false;
+
+
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(m_idxFileInputStream), m_idxFile);
+ if (NS_FAILED(rv)) {
+ CleanUp();
+ return false;
+ }
+
+ return true;
+}
+
+bool CIndexScanner::ValidateIdxFile(void)
+{
+ int8_t id[4];
+ int32_t cnt = 4;
+ nsresult rv;
+ uint32_t cntRead;
+ int8_t * pReadTo;
+
+ pReadTo = id;
+ rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != cnt))
+ return false;
+ if ((id[0] != 'J') || (id[1] != 'M') || (id[2] != 'F') || (id[3] != '9'))
+ return false;
+ cnt = 4;
+ uint32_t subId;
+ pReadTo = (int8_t *) &subId;
+ rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != cnt))
+ return false;
+ if (subId != 0x00010004) {
+ IMPORT_LOG1("Idx file subid doesn't match: 0x%lx\n", subId);
+ return false;
+ }
+
+ pReadTo = (int8_t *) &m_numMessages;
+ rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != cnt))
+ return false;
+
+ IMPORT_LOG1("Idx file num messages: %ld\n", m_numMessages);
+
+ m_didBytes += 80;
+ m_idxOffset = 80;
+ return true;
+}
+
+/*
+Idx file...
+Header is 80 bytes, JMF9, subId? 0x00010004, numMessages, fileSize, 1, 0x00010010
+Entries start at byte 80
+4 byte numbers
+Flags? maybe
+?? who knows
+index
+start of this entry in the file
+length of this record
+msg offset in mbx
+msg length in mbx
+
+*/
+
+// #define DEBUG_SUBJECT_AND_FLAGS 1
+#define kNumIdxLongsToRead 7
+
+bool CIndexScanner::GetMailItem(uint32_t *pFlags, uint32_t *pOffset, uint32_t *pSize)
+{
+ uint32_t values[kNumIdxLongsToRead];
+ int32_t cnt = kNumIdxLongsToRead * sizeof(uint32_t);
+ int8_t * pReadTo = (int8_t *) values;
+ uint32_t cntRead;
+ nsresult rv;
+
+ nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(m_idxFileInputStream);
+ rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, m_idxOffset);
+ if (NS_FAILED(rv))
+ return false;
+
+ rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != cnt))
+ return false;
+
+ if (values[3] != m_idxOffset) {
+ IMPORT_LOG2("Self pointer invalid: m_idxOffset=0x%lx, self=0x%lx\n", m_idxOffset, values[3]);
+ return false;
+ }
+
+ // So... what do we have here???
+#ifdef DEBUG_SUBJECT_AND_FLAGS
+ IMPORT_LOG2("Number: %ld, msg offset: 0x%lx, ", values[2], values[5]);
+ IMPORT_LOG2("msg length: %ld, Flags: 0x%lx\n", values[6], values[0]);
+ seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, m_idxOffset + 212);
+ uint32_t subSz = 0;
+ cnt = 4;
+ pReadTo = (int8_t *) &subSz;
+ m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
+ if ((subSz >= 0) && (subSz < 1024)) {
+ char *pSub = new char[subSz + 1];
+ m_idxFileInputStream->Read(pSub, subSz, &cntRead);
+ pSub[subSz] = 0;
+ IMPORT_LOG1(" Subject: %s\n", pSub);
+ delete [] pSub;
+ }
+#endif
+
+ m_idxOffset += values[4];
+ m_didBytes += values[4];
+
+ *pFlags = values[0];
+ *pOffset = values[5];
+ *pSize = values[6];
+ return true;
+}
+
+#define kOEDeletedFlag 0x0001
+
+bool CIndexScanner::DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount)
+{
+ m_didBytes = 0;
+ if (!ValidateIdxFile())
+ return false;
+
+ bool failed = false;
+ while ((m_curItemIndex < m_numMessages) && !failed && !(*pAbort)) {
+ uint32_t flags, offset, size;
+ if (!GetMailItem(&flags, &offset, &size)) {
+ CleanUp();
+ return false;
+ }
+ m_curItemIndex++;
+ if (!(flags & kOEDeletedFlag)) {
+ if (!WriteMailItem(flags, offset, size))
+ failed = true;
+ else {
+ m_msgCount++;
+ }
+ }
+ m_didBytes += size;
+ if (pDone)
+ *pDone = m_didBytes;
+ if (pCount)
+ *pCount = m_msgCount;
+ }
+
+ CleanUp();
+ return !failed;
+}
+
+
+void CIndexScanner::CleanUp(void)
+{
+ CMbxScanner::CleanUp();
+ m_idxFileInputStream->Close();
+}
diff --git a/mailnews/import/oexpress/nsOEMailbox.h b/mailnews/import/oexpress/nsOEMailbox.h
new file mode 100644
index 000000000..656313aad
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEMailbox.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOEMailbox_h___
+#define nsOEMailbox_h___
+
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsIFile.h"
+
+class nsIMsgFolder;
+
+class CImportMailbox {
+public:
+ static bool ImportMailbox(uint32_t *pDone, bool *pAbort, nsString& name,
+ nsIFile * inFile, nsIMsgFolder * outFolder,
+ uint32_t *pCount);
+
+private:
+ static bool GetIndexFile(nsIFile* mbxFile);
+};
+
+
+
+#endif // nsOEMailbox_h__
diff --git a/mailnews/import/oexpress/nsOERegUtil.cpp b/mailnews/import/oexpress/nsOERegUtil.cpp
new file mode 100644
index 000000000..e3aa9d647
--- /dev/null
+++ b/mailnews/import/oexpress/nsOERegUtil.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "nsOERegUtil.h"
+
+#include "OEDebugLog.h"
+#include <windows.h>
+#include "nsIWindowsRegKey.h"
+#include "nsComponentManagerUtils.h"
+
+nsresult nsOERegUtil::GetDefaultUserId(nsAString &aUserId)
+{
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ NS_LITERAL_STRING("Identities"),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ if (NS_FAILED(rv))
+ return rv;
+
+ return key->ReadStringValue(NS_LITERAL_STRING("Default User ID"), aUserId);
+}
+
diff --git a/mailnews/import/oexpress/nsOERegUtil.h b/mailnews/import/oexpress/nsOERegUtil.h
new file mode 100644
index 000000000..9a873d63b
--- /dev/null
+++ b/mailnews/import/oexpress/nsOERegUtil.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOERegUtil_h___
+#define nsOERegUtil_h___
+
+#include <windows.h>
+#include "nsStringGlue.h"
+
+class nsOERegUtil
+{
+public:
+ static nsresult GetDefaultUserId(nsAString &aUserId);
+};
+
+
+
+#endif /* nsOERegUtil_h___ */
diff --git a/mailnews/import/oexpress/nsOEScanBoxes.cpp b/mailnews/import/oexpress/nsOEScanBoxes.cpp
new file mode 100644
index 000000000..7c30aa68d
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEScanBoxes.cpp
@@ -0,0 +1,859 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "nsOEScanBoxes.h"
+#include "nsMsgUtils.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsIImportService.h"
+#include "nsIFile.h"
+#include "nsIImportMailboxDescriptor.h"
+#include "nsOERegUtil.h"
+#include "nsOE5File.h"
+#include "nsNetUtil.h"
+#include "OEDebugLog.h"
+#include "nsIInputStream.h"
+#include "nsISeekableStream.h"
+#include "plstr.h"
+#include <windows.h>
+#include "nsIWindowsRegKey.h"
+
+#ifdef MOZILLA_INTERNAL_API
+#include "nsNativeCharsetUtils.h"
+#else
+#include "nsMsgI18N.h"
+#define NS_CopyNativeToUnicode(source, dest) \
+ nsMsgI18NConvertToUnicode(nsMsgI18NFileSystemCharset(), source, dest)
+#define NS_CopyUnicodeToNative(source, dest) \
+ nsMsgI18NConvertFromUnicode(nsMsgI18NFileSystemCharset(), source, dest)
+#endif
+
+/*
+ .nch file format???
+
+ offset 20 - long = offset to first record
+
+*/
+
+static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
+
+nsOEScanBoxes::nsOEScanBoxes()
+{
+ m_pFirst = nullptr;
+}
+
+nsOEScanBoxes::~nsOEScanBoxes()
+{
+ int i, max;
+ MailboxEntry *pEntry;
+ for (i = 0, max = m_entryArray.Length(); i < max; i++) {
+ pEntry = m_entryArray.ElementAt(i);
+ delete pEntry;
+ }
+ // Now free the unprocessed child entries (ie, those without parents for some reason).
+ for (i = 0, max = m_pendingChildArray.Length(); i < max; i++)
+ {
+ pEntry = m_pendingChildArray.ElementAt(i);
+ if (!pEntry->processed)
+ delete pEntry;
+ }
+}
+
+/*
+ 3.x & 4.x registry
+ Software/Microsoft/Outlook Express/
+
+ 5.0 registry
+ Identies - value of "Default User ID" is {GUID}
+ Identities/{GUID}/Software/Microsoft/Outlook Express/5.0/
+*/
+
+bool nsOEScanBoxes::Find50Mail(nsIFile *pWhere)
+{
+ nsAutoString userId;
+ nsresult rv = nsOERegUtil::GetDefaultUserId(userId);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsAutoString path(NS_LITERAL_STRING("Identities\\"));
+ path.Append(userId);
+ path.AppendLiteral("\\Software\\Microsoft\\Outlook Express\\5.0");
+
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ path,
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsAutoString storeRoot;
+ key->ReadStringValue(NS_LITERAL_STRING("Store Root"), storeRoot);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsCOMPtr<nsIFile> localWhere = do_QueryInterface(pWhere);
+ localWhere->InitWithPath(storeRoot);
+
+ nsAutoCString nativeStoreRoot;
+ NS_CopyUnicodeToNative(storeRoot, nativeStoreRoot);
+ IMPORT_LOG1("Setting native path: %s\n", nativeStoreRoot.get());
+
+ bool isDir = false;
+ rv = localWhere->IsDirectory(&isDir);
+ return isDir;
+}
+
+bool nsOEScanBoxes::FindMail(nsIFile *pWhere)
+{
+ if (Find50Mail(pWhere))
+ return true;
+
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ NS_LITERAL_STRING("Software\\Microsoft\\Outlook Express"),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsAutoString storeRoot;
+ key->ReadStringValue(NS_LITERAL_STRING("Store Root"), storeRoot);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsCOMPtr<nsIFile> localWhere = do_QueryInterface(pWhere);
+ localWhere->InitWithPath(storeRoot);
+ localWhere->AppendNative(NS_LITERAL_CSTRING("Mail"));
+
+ bool isDir = false;
+ localWhere->IsDirectory(&isDir);
+
+ return isDir;
+}
+
+bool nsOEScanBoxes::GetMailboxes(nsIFile *pWhere, nsIArray **pArray)
+{
+ nsCString path;
+ pWhere->GetNativePath(path);
+ if (!path.IsEmpty()) {
+ IMPORT_LOG1("Looking for mail in: %s\n", path.get());
+ }
+ else {
+ pWhere->GetNativeLeafName(path);
+ if (!path.IsEmpty())
+ IMPORT_LOG1("Looking for mail in: %s\n", path.get());
+ else
+ IMPORT_LOG0("Unable to get info about where to look for mail\n");
+ }
+
+ nsCOMPtr <nsIFile> location;
+ pWhere->Clone(getter_AddRefs(location));
+ // 1. Look for 5.0 folders.dbx
+ // 2. Look for 3.x & 4.x folders.nch
+ // 3. Look for 5.0 *.dbx mailboxes
+ // 4. Look for 3.x & 4.x *.mbx mailboxes
+
+ bool result;
+
+ location->AppendNative(NS_LITERAL_CSTRING("folders.dbx"));
+ if (Find50MailBoxes(location)) {
+ result = GetMailboxList(pWhere, pArray);
+ }
+ else {
+ // 2. Look for 4.x mailboxes
+ pWhere->Clone(getter_AddRefs(location));
+ location->AppendNative(NS_LITERAL_CSTRING("folders.nch"));
+
+ if (FindMailBoxes(location)) {
+ result = GetMailboxList(pWhere, pArray);
+ }
+ else {
+ // 3 & 4, look for the specific mailbox files.
+ pWhere->Clone(getter_AddRefs(location));
+ ScanMailboxDir(location);
+ result = GetMailboxList(pWhere, pArray);
+ }
+ }
+
+ return result;
+}
+
+
+
+void nsOEScanBoxes::Reset(void)
+{
+ int max = m_entryArray.Length();
+ for (int i = 0; i < max; i++) {
+ MailboxEntry *pEntry = m_entryArray.ElementAt(i);
+ delete pEntry;
+ }
+ m_entryArray.Clear();
+ m_pFirst = nullptr;
+}
+
+
+bool nsOEScanBoxes::FindMailBoxes(nsIFile* descFile)
+{
+ Reset();
+
+ nsresult rv;
+ bool isFile = false;
+
+ rv = descFile->IsFile(&isFile);
+ if (NS_FAILED(rv) || !isFile)
+ return false;
+
+ nsCOMPtr <nsIInputStream> descInputStream;
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(descInputStream), descFile);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ IMPORT_LOG0("Reading the folders.nch file\n");
+
+ uint32_t curRec;
+ if (!ReadLong(descInputStream, curRec, 20)) {
+ return false;
+ }
+
+ // Now for each record
+ bool done = false;
+ uint32_t equal;
+ uint32_t size;
+ uint32_t previous;
+ uint32_t next;
+ MailboxEntry * pEntry;
+ bool failed;
+
+ while (!done) {
+ if (!ReadLong(descInputStream, equal, curRec)) return false;
+ if (curRec != equal) {
+ IMPORT_LOG1("Record start invalid: %ld\n", curRec);
+ break;
+ }
+ if (!ReadLong(descInputStream, size, curRec + 4)) return false;
+ if (!ReadLong(descInputStream, previous, curRec + 8)) return false;
+ if (!ReadLong(descInputStream, next, curRec + 12)) return false;
+ failed = false;
+ pEntry = new MailboxEntry;
+ if (!ReadLong(descInputStream, pEntry->index, curRec + 16)) failed = true;
+ if (!ReadString(descInputStream, pEntry->mailName, curRec + 20)) failed = true;
+ if (!ReadString(descInputStream, pEntry->fileName, curRec + 279)) failed = true;
+ if (!ReadLong(descInputStream, pEntry->parent, curRec + 539)) failed = true;
+ if (!ReadLong(descInputStream, pEntry->child, curRec + 543)) failed = true;
+ if (!ReadLong(descInputStream, pEntry->sibling, curRec + 547)) failed = true;
+ if (!ReadLong(descInputStream, pEntry->type, curRec + 551)) failed = true;
+ if (failed) {
+ delete pEntry;
+ return false;
+ }
+
+ #ifdef _TRACE_MAILBOX_ENTRIES
+ IMPORT_LOG0("------------\n");
+ IMPORT_LOG2(" Offset: %lx, index: %ld\n", curRec, pEntry->index);
+ IMPORT_LOG2(" previous: %lx, next: %lx\n", previous, next);
+ IMPORT_LOG2(" Name: %S, File: %s\n", (char16_t *) pEntry->mailName, (const char *) pEntry->fileName);
+ IMPORT_LOG3(" Parent: %ld, Child: %ld, Sibling: %ld\n", pEntry->parent, pEntry->child, pEntry->sibling);
+ #endif
+
+ if (!StringEndsWith(pEntry->fileName, NS_LITERAL_CSTRING(".mbx")))
+ pEntry->fileName.Append(".mbx");
+
+ m_entryArray.AppendElement(pEntry);
+
+ curRec = next;
+ if (!next)
+ done = true;
+ }
+
+ MailboxEntry *pZero = GetIndexEntry(0);
+ if (pZero)
+ m_pFirst = GetIndexEntry(pZero->child);
+
+ IMPORT_LOG1("Read the folders.nch file, found %ld mailboxes\n", (long) m_entryArray.Length());
+
+ return true;
+}
+
+bool nsOEScanBoxes::Find50MailBoxes(nsIFile* descFile)
+{
+ Reset();
+
+ nsresult rv;
+ bool isFile = false;
+
+ rv = descFile->IsFile(&isFile);
+ if (NS_FAILED(rv) || !isFile)
+ return false;
+
+ nsCOMPtr <nsIInputStream> descInputStream;
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(descInputStream), descFile);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ IMPORT_LOG0("Reading the folders.dbx file\n");
+
+ uint32_t *pIndex;
+ uint32_t indexSize = 0;
+ if (!nsOE5File::ReadIndex(descInputStream, &pIndex, &indexSize)) {
+ IMPORT_LOG0("*** NOT USING FOLDERS.DBX!!!\n");
+ return false;
+ }
+
+ uint32_t marker;
+ uint32_t size;
+ char *pBytes;
+ uint32_t cntRead;
+ int32_t recordId;
+ int32_t strOffset;
+
+ uint8_t tag;
+ uint32_t data;
+ int32_t dataOffset;
+
+ uint32_t id;
+ uint32_t parent;
+ uint32_t numMessages;
+ char * pFileName;
+ char * pDataSource;
+
+ MailboxEntry * pEntry;
+ MailboxEntry * pLastEntry = nullptr;
+
+ uint32_t localStoreId = 0;
+
+ for (uint32_t i = 0; i < indexSize; i++) {
+ if (!ReadLong(descInputStream, marker, pIndex[i])) continue;
+ if (marker != pIndex[i]) continue;
+ if (!ReadLong(descInputStream, size, pIndex[i] + 4)) continue;
+ size += 4;
+ pBytes = new char[size];
+ rv = descInputStream->Read(pBytes, size, &cntRead);
+ if (NS_FAILED(rv) || ((uint32_t)cntRead != size)) {
+ delete [] pBytes;
+ continue;
+ }
+ recordId = pBytes[2];
+ strOffset = (recordId * 4) + 4;
+ if (recordId == 4)
+ strOffset += 4;
+
+ id = 0;
+ parent = 0;
+ numMessages = 0;
+ pFileName = nullptr;
+ pDataSource = nullptr;
+ dataOffset = 4;
+ while (dataOffset < strOffset) {
+ tag = (uint8_t) pBytes[dataOffset];
+
+ data = 0; // make sure all bytes are 0 before copying 3 bytes over.
+ memcpy(&data, &(pBytes[dataOffset + 1]), 3);
+ switch(tag) {
+ case 0x80: // id record
+ id = data;
+ break;
+ case 0x81: // parent id
+ parent = data;
+ break;
+ case 0x87: // number of messages in this mailbox
+ numMessages = data;
+ break;
+ case 0x03: // file name for this mailbox
+ if (((uint32_t)strOffset + data) < size)
+ pFileName = (char *)(pBytes + strOffset + data);
+ break;
+ case 0x05: // data source for this record (this is not a mailbox!)
+ if (((uint32_t)strOffset + data) < size)
+ pDataSource = (char *) (pBytes + strOffset + data);
+ break;
+ }
+ dataOffset += 4;
+ }
+
+ // now build an entry if necessary!
+ if (pDataSource) {
+ if (!PL_strcasecmp(pDataSource, "LocalStore"))
+ {
+ localStoreId = id;
+ // See if we have any child folders that need to be added/processed for this top level parent.
+ ProcessPendingChildEntries(localStoreId, localStoreId, m_pendingChildArray);
+ // Clean up the pending list.
+ RemoveProcessedChildEntries();
+ }
+ }
+ else if (id && localStoreId && parent) {
+ // veryify that this mailbox is in the local store
+ data = parent;
+ while (data && (data != localStoreId)) {
+ pEntry = GetIndexEntry(data);
+ if (pEntry)
+ data = pEntry->parent;
+ else
+ data = 0;
+ }
+ if (data == localStoreId) {
+ // Create an entry for this bugger
+ pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
+ if (pEntry)
+ {
+ AddChildEntry(pEntry, localStoreId);
+ pEntry->processed = true;
+ // See if we have any child folders that need to be added/processed.
+ ProcessPendingChildEntries(id, localStoreId, m_pendingChildArray);
+ // Clean up the pending list.
+ RemoveProcessedChildEntries();
+ }
+ }
+ else
+ {
+ // Put this folder into child array and process it when its parent shows up.
+ pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
+ if (pEntry)
+ m_pendingChildArray.AppendElement(pEntry);
+ }
+ }
+ else if (pFileName)
+ {
+ // Put this folder into child array and process it when its parent shows up.
+ // For some reason, it's likely that child folders come before their parents.
+ pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
+ if (pEntry)
+ m_pendingChildArray.AppendElement(pEntry);
+ }
+
+ delete [] pBytes;
+ }
+
+
+ delete [] pIndex;
+
+ return m_entryArray.Length();
+}
+
+nsOEScanBoxes::MailboxEntry *nsOEScanBoxes::NewMailboxEntry(uint32_t id, uint32_t parent, const char *prettyName, char *pFileName)
+{
+ MailboxEntry *pEntry = new MailboxEntry();
+ if (!pEntry)
+ return nullptr;
+
+ pEntry->index = id;
+ pEntry->parent = parent;
+ pEntry->child = 0;
+ pEntry->type = 0;
+ pEntry->sibling = -1;
+ pEntry->processed = false;
+ NS_CopyNativeToUnicode(nsDependentCString(prettyName), pEntry->mailName);
+ if (pFileName)
+ pEntry->fileName = pFileName;
+ return pEntry;
+}
+
+void nsOEScanBoxes::ProcessPendingChildEntries(uint32_t parent, uint32_t rootIndex, nsTArray<MailboxEntry*> &childArray)
+{
+ int32_t i, max;
+ MailboxEntry *pEntry;
+ for (i = 0, max = childArray.Length(); i < max; i++)
+ {
+ pEntry = childArray.ElementAt(i);
+ if ((!pEntry->processed) && (pEntry->parent == parent))
+ {
+ AddChildEntry(pEntry, rootIndex);
+ pEntry->processed = true; // indicate it's been processed.
+ // See if there are unprocessed child folders for this child in the
+ // array as well (ie, both child and grand-child are on the list).
+ ProcessPendingChildEntries(pEntry->index, rootIndex, childArray);
+ }
+ }
+}
+
+void nsOEScanBoxes::RemoveProcessedChildEntries()
+{
+ // Remove already processed entries from the pending list. Note that these entries are also
+ // on 'm_entryArray' list so we don't want to deallocate the space for the entries now.
+ MailboxEntry * pEntry;
+ int32_t i;
+ for (i = m_pendingChildArray.Length()-1; i >= 0; i--)
+ {
+ pEntry = m_pendingChildArray.ElementAt(i);
+ if (pEntry->processed)
+ m_pendingChildArray.RemoveElementAt(i);
+ }
+}
+
+void nsOEScanBoxes::AddChildEntry(MailboxEntry *pEntry, uint32_t rootIndex)
+{
+ if (!m_pFirst) {
+ if (pEntry->parent == rootIndex) {
+ m_pFirst = pEntry;
+ m_entryArray.AppendElement(pEntry);
+ }
+ else {
+ delete pEntry;
+ }
+ return;
+ }
+
+ MailboxEntry * pParent = nullptr;
+ MailboxEntry * pSibling = nullptr;
+ if (pEntry->parent == rootIndex) {
+ pSibling = m_pFirst;
+ }
+ else {
+ pParent = GetIndexEntry(pEntry->parent);
+ }
+
+ if (!pParent && !pSibling) {
+ delete pEntry;
+ return;
+ }
+
+ if (pParent && (pParent->child == 0)) {
+ pParent->child = pEntry->index;
+ m_entryArray.AppendElement(pEntry);
+ return;
+ }
+
+ if (!pSibling)
+ pSibling = GetIndexEntry(pParent->child);
+
+ while (pSibling && (pSibling->sibling != -1)) {
+ pSibling = GetIndexEntry(pSibling->sibling);
+ }
+
+ if (!pSibling) {
+ delete pEntry;
+ return;
+ }
+
+ pSibling->sibling = pEntry->index;
+ m_entryArray.AppendElement(pEntry);
+}
+
+bool nsOEScanBoxes::Scan50MailboxDir(nsIFile * srcDir)
+{
+ Reset();
+
+ MailboxEntry *pEntry;
+ int32_t index = 1;
+ char *pLeaf;
+
+ bool hasMore;
+ nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
+ nsresult rv = srcDir->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
+ NS_ENSURE_SUCCESS(rv, false);
+
+ directoryEnumerator->HasMoreElements(&hasMore);
+ bool isFile;
+ nsCOMPtr<nsIFile> entry;
+ nsCString fName;
+
+ while (hasMore && NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsISupports> aSupport;
+ rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
+ nsCOMPtr<nsIFile> entry(do_QueryInterface(aSupport, &rv));
+ directoryEnumerator->HasMoreElements(&hasMore);
+
+ isFile = false;
+ rv = entry->IsFile(&isFile);
+ if (NS_SUCCEEDED(rv) && isFile) {
+ pLeaf = nullptr;
+ rv = entry->GetNativeLeafName(fName);
+ if (NS_SUCCEEDED(rv) &&
+ (StringEndsWith(fName, NS_LITERAL_CSTRING(".dbx")))) {
+ // This is a *.dbx file in the mail directory
+ if (nsOE5File::IsLocalMailFile(entry)) {
+ pEntry = new MailboxEntry;
+ pEntry->index = index;
+ index++;
+ pEntry->parent = 0;
+ pEntry->child = 0;
+ pEntry->sibling = index;
+ pEntry->type = -1;
+ fName.SetLength(fName.Length() - 4);
+ pEntry->fileName = fName.get();
+ NS_CopyNativeToUnicode(fName, pEntry->mailName);
+ m_entryArray.AppendElement(pEntry);
+ }
+ }
+ }
+ }
+
+ if (m_entryArray.Length() > 0) {
+ pEntry = m_entryArray.ElementAt(m_entryArray.Length() - 1);
+ pEntry->sibling = -1;
+ return true;
+ }
+
+ return false;
+}
+
+void nsOEScanBoxes::ScanMailboxDir(nsIFile * srcDir)
+{
+ if (Scan50MailboxDir(srcDir))
+ return;
+
+ Reset();
+
+ MailboxEntry * pEntry;
+ int32_t index = 1;
+ nsAutoCString pLeaf;
+ uint32_t sLen;
+
+ bool hasMore;
+ nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
+ nsresult rv = srcDir->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ directoryEnumerator->HasMoreElements(&hasMore);
+ bool isFile;
+ nsCOMPtr<nsIFile> entry;
+ nsCString fName;
+ nsCString ext;
+ nsCString name;
+
+ while (hasMore && NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsISupports> aSupport;
+ rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
+ nsCOMPtr<nsIFile> entry(do_QueryInterface(aSupport, &rv));
+ directoryEnumerator->HasMoreElements(&hasMore);
+
+ isFile = false;
+ rv = entry->IsFile(&isFile);
+ if (NS_SUCCEEDED(rv) && isFile)
+ {
+ rv = entry->GetNativeLeafName(pLeaf);
+ if (NS_SUCCEEDED(rv) && !pLeaf.IsEmpty() &&
+ ((sLen = pLeaf.Length()) > 4) &&
+ (!PL_strcasecmp(pLeaf.get() + sLen - 3, "mbx")))
+ {
+ // This is a *.mbx file in the mail directory
+ pEntry = new MailboxEntry;
+ pEntry->index = index;
+ index++;
+ pEntry->parent = 0;
+ pEntry->child = 0;
+ pEntry->sibling = index;
+ pEntry->type = -1;
+ pEntry->fileName = pLeaf;
+ pLeaf.SetLength(sLen - 4);
+ NS_CopyNativeToUnicode(pLeaf, pEntry->mailName);
+ m_entryArray.AppendElement(pEntry);
+ }
+ }
+ }
+
+ if (m_entryArray.Length() > 0) {
+ pEntry = m_entryArray.ElementAt(m_entryArray.Length() - 1);
+ pEntry->sibling = -1;
+ }
+}
+
+uint32_t nsOEScanBoxes::CountMailboxes(MailboxEntry *pBox)
+{
+ if (pBox == nullptr) {
+ if (m_pFirst != nullptr)
+ pBox = m_pFirst;
+ else {
+ if (m_entryArray.Length() > 0)
+ pBox = m_entryArray.ElementAt(0);
+ }
+ }
+ uint32_t count = 0;
+
+ MailboxEntry * pChild;
+ while (pBox) {
+ count++;
+ if (pBox->child) {
+ pChild = GetIndexEntry(pBox->child);
+ if (pChild != nullptr)
+ count += CountMailboxes(pChild);
+ }
+ if (pBox->sibling != -1) {
+ pBox = GetIndexEntry(pBox->sibling);
+ }
+ else
+ pBox = nullptr;
+ }
+
+ return count;
+}
+
+bool nsOEScanBoxes::GetMailboxList(nsIFile * root, nsIArray **pArray)
+{
+ nsresult rv;
+ nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("FAILED to allocate the nsIArray\n");
+ return false;
+ }
+
+ BuildMailboxList(nullptr, root, 1, array);
+ array.forget(pArray);
+
+ return true;
+}
+
+void nsOEScanBoxes::BuildMailboxList(MailboxEntry *pBox, nsIFile * root, int32_t depth, nsIMutableArray *pArray)
+{
+ if (pBox == nullptr) {
+ if (m_pFirst != nullptr) {
+ pBox = m_pFirst;
+
+ IMPORT_LOG0("Assigning start of mailbox list to m_pFirst\n");
+ }
+ else {
+ if (m_entryArray.Length() > 0) {
+ pBox = m_entryArray.ElementAt(0);
+
+ IMPORT_LOG0("Assigning start of mailbox list to entry at index 0\n");
+ }
+ }
+
+ if (pBox == nullptr) {
+ IMPORT_LOG0("ERROR ASSIGNING STARTING MAILBOX\n");
+ }
+
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIFile> file;
+ MailboxEntry *pChild;
+ nsIImportMailboxDescriptor *pID;
+ nsISupports *pInterface;
+ int64_t size;
+
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ while (pBox) {
+ rv = impSvc->CreateNewMailboxDescriptor(&pID);
+ if (NS_SUCCEEDED(rv)) {
+ pID->SetDepth(depth);
+ pID->SetIdentifier(pBox->index);
+ pID->SetDisplayName((char16_t *)pBox->mailName.get());
+ if (!pBox->fileName.IsEmpty()) {
+ pID->GetFile(getter_AddRefs(file));
+ file->InitWithFile(root);
+ file->AppendNative(pBox->fileName);
+ size = 0;
+ file->GetFileSize(&size);
+ pID->SetSize(size);
+ }
+ rv = pID->QueryInterface(kISupportsIID, (void **) &pInterface);
+ pArray->AppendElement(pInterface, false);
+ pInterface->Release();
+ pID->Release();
+ }
+
+ if (pBox->child) {
+ pChild = GetIndexEntry(pBox->child);
+ if (pChild != nullptr)
+ BuildMailboxList(pChild, root, depth + 1, pArray);
+ }
+ if (pBox->sibling != -1) {
+ pBox = GetIndexEntry(pBox->sibling);
+ }
+ else
+ pBox = nullptr;
+ }
+
+}
+
+nsOEScanBoxes::MailboxEntry * nsOEScanBoxes::GetIndexEntry(uint32_t index)
+{
+ int32_t max = m_entryArray.Length();
+ for (int32_t i = 0; i < max; i++) {
+ MailboxEntry *pEntry = m_entryArray.ElementAt(i);
+ if (pEntry->index == index)
+ return pEntry;
+ }
+
+ return nullptr;
+}
+
+
+// -------------------------------------------------------
+// File utility routines
+// -------------------------------------------------------
+
+bool nsOEScanBoxes::ReadLong(nsIInputStream * stream, int32_t& val, uint32_t offset)
+{
+ nsresult rv;
+ nsCOMPtr <nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ uint32_t cntRead;
+ char * pReadTo = (char *)&val;
+ rv = stream->Read(pReadTo, sizeof(val), &cntRead);
+
+ return NS_SUCCEEDED(rv) && cntRead == sizeof(val);
+}
+
+bool nsOEScanBoxes::ReadLong(nsIInputStream * stream, uint32_t& val, uint32_t offset)
+{
+ nsresult rv;
+ nsCOMPtr <nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+ rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ uint32_t cntRead;
+ char * pReadTo = (char *)&val;
+ rv = stream->Read(pReadTo, sizeof(val), &cntRead);
+ if (NS_FAILED(rv) || (cntRead != sizeof(val)))
+ return false;
+
+ return true;
+}
+
+// It appears as though the strings for file name and mailbox
+// name are at least 254 chars - verified - they are probably 255
+// but why bother going that far! If a file name is that long then
+// the heck with it.
+#define kOutlookExpressStringLength 252
+bool nsOEScanBoxes::ReadString(nsIInputStream * stream, nsString& str, uint32_t offset)
+{
+ nsresult rv;
+ nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ uint32_t cntRead;
+ char buffer[kOutlookExpressStringLength];
+ char *pReadTo = buffer;
+ rv = stream->Read(pReadTo, kOutlookExpressStringLength, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != kOutlookExpressStringLength))
+ return false;
+
+ buffer[kOutlookExpressStringLength - 1] = 0;
+ str.AssignASCII(buffer);
+ return true;
+}
+
+bool nsOEScanBoxes::ReadString(nsIInputStream * stream, nsCString& str, uint32_t offset)
+{
+ nsresult rv;
+ nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ uint32_t cntRead;
+ char buffer[kOutlookExpressStringLength];
+ char *pReadTo = buffer;
+ rv = stream->Read(pReadTo, kOutlookExpressStringLength, &cntRead);
+ if (NS_FAILED(rv) || (cntRead != kOutlookExpressStringLength))
+ return false;
+
+ buffer[kOutlookExpressStringLength - 1] = 0;
+ str = buffer;
+ return true;
+}
diff --git a/mailnews/import/oexpress/nsOEScanBoxes.h b/mailnews/import/oexpress/nsOEScanBoxes.h
new file mode 100644
index 000000000..e2e62b238
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEScanBoxes.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOEScanBoxes_h___
+#define nsOEScanBoxes_h___
+
+#include "nsStringGlue.h"
+#include "nsIImportModule.h"
+#include "nsTArray.h"
+#include "nsCOMPtr.h"
+#include "nsIArray.h"
+#include "nsIMutableArray.h"
+#include "nsIFile.h"
+#include "nsIImportService.h"
+
+class nsIInputStream;
+
+class nsOEScanBoxes {
+public:
+ nsOEScanBoxes();
+ ~nsOEScanBoxes();
+
+ static bool FindMail(nsIFile *pWhere);
+
+ bool GetMailboxes(nsIFile *pWhere, nsIArray **pArray);
+
+
+private:
+ typedef struct {
+ uint32_t index;
+ uint32_t parent;
+ int32_t child;
+ int32_t sibling;
+ int32_t type;
+ nsString mailName;
+ nsCString fileName;
+ bool processed; // used by entries on m_pendingChildArray list
+ } MailboxEntry;
+
+ static bool Find50Mail(nsIFile *pWhere);
+
+ void Reset(void);
+ bool FindMailBoxes(nsIFile * descFile);
+ bool Find50MailBoxes(nsIFile * descFile);
+
+ // If find mailboxes fails you can use this routine to get the raw mailbox file names
+ void ScanMailboxDir(nsIFile * srcDir);
+ bool Scan50MailboxDir(nsIFile * srcDir);
+
+ MailboxEntry * GetIndexEntry(uint32_t index);
+ void AddChildEntry(MailboxEntry *pEntry, uint32_t rootIndex);
+ MailboxEntry * NewMailboxEntry(uint32_t id, uint32_t parent, const char *prettyName, char *pFileName);
+ void ProcessPendingChildEntries(uint32_t parent, uint32_t rootIndex, nsTArray<MailboxEntry*> &childArray);
+ void RemoveProcessedChildEntries();
+
+
+ bool ReadLong(nsIInputStream * stream, int32_t& val, uint32_t offset);
+ bool ReadLong(nsIInputStream * stream, uint32_t& val, uint32_t offset);
+ bool ReadString(nsIInputStream * stream, nsString& str, uint32_t offset);
+ bool ReadString(nsIInputStream * stream, nsCString& str, uint32_t offset);
+ uint32_t CountMailboxes(MailboxEntry *pBox);
+
+ void BuildMailboxList(MailboxEntry *pBox, nsIFile * root, int32_t depth, nsIMutableArray *pArray);
+ bool GetMailboxList(nsIFile * root, nsIArray **pArray);
+
+private:
+ MailboxEntry * m_pFirst;
+ nsTArray<MailboxEntry*> m_entryArray;
+ nsTArray<MailboxEntry*> m_pendingChildArray; // contains child folders whose parent folders have not showed up.
+
+ nsCOMPtr<nsIImportService> mService;
+};
+
+#endif // nsOEScanBoxes_h__
diff --git a/mailnews/import/oexpress/nsOESettings.cpp b/mailnews/import/oexpress/nsOESettings.cpp
new file mode 100644
index 000000000..600acf74c
--- /dev/null
+++ b/mailnews/import/oexpress/nsOESettings.cpp
@@ -0,0 +1,921 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+
+ Outlook Express (Win32) settings
+
+*/
+
+#include "nsOESettings.h"
+#include "mozilla/WindowsVersion.h"
+#include "nsCOMPtr.h"
+#include "nscore.h"
+#include "nsMsgUtils.h"
+#include "nsOEImport.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsOERegUtil.h"
+#include "nsIMsgAccountManager.h"
+#include "nsIMsgAccount.h"
+#include "nsIImportSettings.h"
+#include "nsMsgBaseCID.h"
+#include "nsMsgCompCID.h"
+#include "nsMsgI18N.h"
+#include "nsISmtpService.h"
+#include "nsISmtpServer.h"
+#include "nsOEStringBundle.h"
+#include "OEDebugLog.h"
+#include "nsIPop3IncomingServer.h"
+#include "nsIImapIncomingServer.h"
+#include "nsINntpIncomingServer.h"
+#include "stdlib.h"
+#include <windows.h>
+#include "nsIWindowsRegKey.h"
+#include "nsComponentManagerUtils.h"
+
+#ifdef MOZILLA_INTERNAL_API
+#include "nsNativeCharsetUtils.h"
+#else
+#include "nsMsgI18N.h"
+#define NS_CopyNativeToUnicode(source, dest) \
+ nsMsgI18NConvertToUnicode(nsMsgI18NFileSystemCharset(), source, dest)
+#define NS_CopyUnicodeToNative(source, dest) \
+ nsMsgI18NConvertFromUnicode(nsMsgI18NFileSystemCharset(), source, dest)
+#endif
+
+class OESettings {
+public:
+ static nsresult GetDefaultMailAccount(nsAString &aMailAccount);
+ static nsresult GetCheckMailInterval(uint32_t *aInterval);
+ static nsresult Find50Key(nsIWindowsRegKey **aKey);
+ static nsresult Find40Key(nsIWindowsRegKey **aKey);
+ static nsresult FindAccountsKey(nsIWindowsRegKey **aKey);
+
+ static bool DoImport(nsIMsgAccount **ppAccount);
+
+ static bool DoIMAPServer(nsIMsgAccountManager *aMgr,
+ nsIWindowsRegKey *aKey,
+ const nsString &aServerName,
+ nsIMsgAccount **ppAccount);
+ static bool DoPOP3Server(nsIMsgAccountManager *aMgr,
+ nsIWindowsRegKey *aKey,
+ const nsString &aServerName,
+ nsIMsgAccount **ppAccount);
+ static bool DoNNTPServer(nsIMsgAccountManager *aMgr,
+ nsIWindowsRegKey *aKey,
+ const nsString &aServerName,
+ nsIMsgAccount **ppAccount);
+
+ static void SetIncomingServerProperties(nsIMsgIncomingServer *aServer,
+ nsIWindowsRegKey *aKey,
+ const nsString &aKeyNamePrefix);
+
+ static void SetIdentities(nsIMsgAccountManager *aMgr,
+ nsIMsgAccount *aAccount,
+ nsIWindowsRegKey *aKey,
+ const nsString &aIncomgUserName,
+ int32_t authMethodIncoming, bool isNNTP);
+ static void SetSmtpServer(const nsString &aSmtpServer,
+ nsIWindowsRegKey *aKey,
+ nsIMsgIdentity *aId,
+ const nsString &aIncomgUserName,
+ int32_t authMethodIncoming);
+ static nsresult GetAccountName(nsIWindowsRegKey *aKey,
+ const nsString &aDefaultName,
+ nsAString &aAccountName);
+ static bool IsKB933612Applied();
+};
+
+static uint32_t checkNewMailTime;// OE global setting, let's default to 30
+static bool checkNewMail; // OE global setting, let's default to false
+ // This won't cause unwanted autodownloads-
+ // user can set prefs after import
+
+////////////////////////////////////////////////////////////////////////
+nsresult nsOESettings::Create(nsIImportSettings** aImport)
+{
+ NS_PRECONDITION(aImport != nullptr, "null ptr");
+ if (! aImport)
+ return NS_ERROR_NULL_POINTER;
+
+ *aImport = new nsOESettings();
+ if (! *aImport)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(*aImport);
+ return NS_OK;
+}
+
+nsOESettings::nsOESettings()
+{
+}
+
+nsOESettings::~nsOESettings()
+{
+}
+
+NS_IMPL_ISUPPORTS(nsOESettings, nsIImportSettings)
+
+NS_IMETHODIMP nsOESettings::AutoLocate(char16_t **description, nsIFile **location, bool *_retval)
+{
+ NS_PRECONDITION(description != nullptr, "null ptr");
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!description || !_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *description = nsOEStringBundle::GetStringByID(OEIMPORT_NAME);
+
+ if (location)
+ *location = nullptr;
+
+ *_retval = false;
+ nsCOMPtr<nsIWindowsRegKey> key;
+ if (NS_FAILED(OESettings::Find50Key(getter_AddRefs(key))) &&
+ NS_FAILED(OESettings::Find40Key(getter_AddRefs(key))))
+ return NS_OK;
+
+ if (NS_SUCCEEDED(OESettings::FindAccountsKey(getter_AddRefs(key))))
+ *_retval = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsOESettings::SetLocation(nsIFile *location)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsOESettings::Import(nsIMsgAccount **localMailAccount, bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+
+ if (OESettings::DoImport(localMailAccount)) {
+ *_retval = true;
+ IMPORT_LOG0("Settings import appears successful\n");
+ }
+ else {
+ *_retval = false;
+ IMPORT_LOG0("Settings import returned FALSE\n");
+ }
+
+ return NS_OK;
+}
+
+nsresult OESettings::GetDefaultMailAccount(nsAString &aMailAccount)
+{
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString userId;
+ rv = nsOERegUtil::GetDefaultUserId(userId);
+ // OE has default mail account here when it has been
+ // set up by transfer or has multiple identities
+ // look below for orig code that looked in new OE installs
+ if (NS_SUCCEEDED(rv)) {
+ nsAutoString path(NS_LITERAL_STRING("Identities\\"));
+ path.Append(userId);
+ path.AppendLiteral("\\Software\\Microsoft\\Internet Account Manager");
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ path,
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ if (NS_SUCCEEDED(rv))
+ key->ReadStringValue(NS_LITERAL_STRING("Default Mail Account"), aMailAccount);
+ }
+
+ if (!aMailAccount.IsEmpty())
+ return NS_OK;
+
+ // else it must be here in original install location from orig code
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ NS_LITERAL_STRING("Software\\Microsoft\\Outlook Express"),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ if (NS_FAILED(rv))
+ return rv;
+
+ return key->ReadStringValue(NS_LITERAL_STRING("Default Mail Account"), aMailAccount);
+}
+
+nsresult OESettings::GetCheckMailInterval(uint32_t *aInterval)
+{
+ nsCOMPtr<nsIWindowsRegKey> key;
+ // 'poll for messages' setting in OE is a global setting
+ // in OE options general tab and in following global OE
+ // registry location.
+ // for all accounts poll interval is a 32 bit value, 0 for
+ // "don't poll", else milliseconds
+ nsresult rv = Find50Key(getter_AddRefs(key));
+ if (NS_FAILED(rv))
+ rv = Find40Key(getter_AddRefs(key));
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIWindowsRegKey> subKey;
+ rv = key->OpenChild(NS_LITERAL_STRING("Mail"),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE,
+ getter_AddRefs(subKey));
+ if (NS_FAILED(rv))
+ return rv;
+
+ uint32_t intValue;
+ rv = subKey->ReadIntValue(NS_LITERAL_STRING("Poll For Mail"), &intValue);
+ if (NS_SUCCEEDED(rv) && intValue != PR_UINT32_MAX)
+ *aInterval = intValue / 60000;
+
+ return rv;
+}
+
+nsresult OESettings::FindAccountsKey(nsIWindowsRegKey **aKey)
+{
+ nsAutoString userId;
+ nsresult rv = nsOERegUtil::GetDefaultUserId(userId);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsAutoString path(NS_LITERAL_STRING("Identities\\"));
+ path.Append(userId);
+ path.AppendLiteral("\\Software\\Microsoft\\Internet Account Manager\\Accounts");
+
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ path,
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE |
+ nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS);
+ if (NS_SUCCEEDED(rv)) {
+ NS_ADDREF(*aKey = key);
+ return rv;
+ }
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ NS_LITERAL_STRING("Software\\Microsoft\\Internet Account Manager\\Accounts"),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE |
+ nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS);
+ NS_IF_ADDREF(*aKey = key);
+ return rv;
+}
+
+nsresult OESettings::Find50Key(nsIWindowsRegKey **aKey)
+{
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString userId;
+ rv = nsOERegUtil::GetDefaultUserId(userId);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsAutoString path(NS_LITERAL_STRING("Identities\\"));
+ path.Append(userId);
+ path.AppendLiteral("\\Software\\Microsoft\\Outlook Express\\5.0");
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ path,
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ NS_IF_ADDREF(*aKey = key);
+
+ return rv;
+}
+
+nsresult OESettings::Find40Key(nsIWindowsRegKey **aKey)
+{
+ nsresult rv;
+ nsCOMPtr<nsIWindowsRegKey> key =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+ NS_LITERAL_STRING("Software\\Microsoft\\Outlook Express"),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ NS_IF_ADDREF(*aKey = key);
+
+ return rv;
+}
+
+bool OESettings::DoImport(nsIMsgAccount **aAccount)
+{
+ nsCOMPtr<nsIWindowsRegKey> key;
+ nsresult rv = FindAccountsKey(getter_AddRefs(key));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0( "*** Error finding Outlook Express registry account keys\n");
+ return false;
+ }
+
+ nsCOMPtr<nsIMsgAccountManager> accMgr =
+ do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Failed to create a account manager!\n");
+ return false;
+ }
+
+ nsAutoString defMailName;
+ rv = GetDefaultMailAccount(defMailName);
+
+ checkNewMail = false;
+ checkNewMailTime = 30;
+ rv = GetCheckMailInterval(&checkNewMailTime);
+ if (NS_SUCCEEDED(rv))
+ checkNewMail = true;
+
+ // Iterate the accounts looking for POP3 & IMAP accounts...
+ // Ignore LDAP for now!
+ uint32_t accounts = 0;
+ nsAutoString keyComp;
+ uint32_t childCount = 0;
+ key->GetChildCount(&childCount);
+ for (uint32_t i = 0; i < childCount; i++) {
+ nsAutoString keyName;
+ key->GetChildName(i, keyName);
+
+ nsCOMPtr<nsIWindowsRegKey> subKey;
+ rv = key->OpenChild(keyName,
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE,
+ getter_AddRefs(subKey));
+ if (NS_FAILED(rv))
+ continue;
+
+ nsAutoCString nativeKeyName;
+ NS_CopyUnicodeToNative(keyName, nativeKeyName);
+ IMPORT_LOG1("Opened Outlook Express account: %s\n",
+ nativeKeyName.get());
+
+ nsIMsgAccount *anAccount = nullptr;
+ nsAutoString value;
+ rv = subKey->ReadStringValue(NS_LITERAL_STRING("IMAP Server"), value);
+ if (NS_SUCCEEDED(rv) && DoIMAPServer(accMgr, subKey, value, &anAccount))
+ accounts++;
+
+ rv = subKey->ReadStringValue(NS_LITERAL_STRING("NNTP Server"), value);
+ if (NS_SUCCEEDED(rv) && DoNNTPServer(accMgr, subKey, value, &anAccount))
+ accounts++;
+
+ rv = subKey->ReadStringValue(NS_LITERAL_STRING("POP3 Server"), value);
+ if (NS_SUCCEEDED(rv) && DoPOP3Server(accMgr, subKey, value, &anAccount))
+ accounts++;
+
+ if (anAccount) {
+ // Is this the default account?
+ keyComp = keyName;
+ if (keyComp.Equals(defMailName))
+ accMgr->SetDefaultAccount(anAccount);
+ NS_RELEASE(anAccount);
+ }
+ }
+
+ // Now save the new acct info to pref file.
+ rv = accMgr->SaveAccountInfo();
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Can't save account info to pref file");
+
+ return accounts != 0;
+}
+
+nsresult OESettings::GetAccountName(nsIWindowsRegKey *aKey,
+ const nsString &aDefaultName,
+ nsAString &aAccountName)
+{
+ nsresult rv;
+ rv = aKey->ReadStringValue(NS_LITERAL_STRING("Account Name"), aAccountName);
+ if (NS_FAILED(rv))
+ aAccountName.Assign(aDefaultName);
+
+ return NS_OK;
+}
+
+bool OESettings::DoIMAPServer(nsIMsgAccountManager *aMgr,
+ nsIWindowsRegKey *aKey,
+ const nsString &aServerName,
+ nsIMsgAccount **ppAccount)
+{
+ if (ppAccount)
+ *ppAccount = nullptr;
+
+ nsAutoString userName;
+ nsresult rv;
+ rv = aKey->ReadStringValue(NS_LITERAL_STRING("IMAP User Name"), userName);
+ if (NS_FAILED(rv))
+ return false;
+
+ nsAutoCString nativeUserName;
+ NS_CopyUnicodeToNative(userName, nativeUserName);
+ nsAutoCString nativeServerName;
+ NS_CopyUnicodeToNative(aServerName, nativeServerName);
+ // I now have a user name/server name pair, find out if it already exists?
+ nsCOMPtr<nsIMsgIncomingServer> in;
+ rv = aMgr->FindServer(nativeUserName,
+ nativeServerName,
+ NS_LITERAL_CSTRING("imap"),
+ getter_AddRefs(in));
+ if (NS_SUCCEEDED(rv)) {
+ // for an existing server we create another identity,
+ // TB lists under 'manage identities'
+ nsCOMPtr<nsIMsgAccount> account;
+ rv = aMgr->FindAccountForServer(in, getter_AddRefs(account));
+ if (NS_FAILED(rv))
+ return false;
+
+ IMPORT_LOG0("Created an identity and added to existing IMAP incoming server\n");
+ // Fiddle with the identities
+ int32_t authMethod;
+ in->GetAuthMethod(&authMethod);
+ SetIdentities(aMgr, account, aKey, userName, authMethod, false);
+ if (ppAccount)
+ account->QueryInterface(NS_GET_IID(nsIMsgAccount),
+ (void **)ppAccount);
+ return true;
+ }
+
+ // Create the incoming server and an account for it?
+ rv = aMgr->CreateIncomingServer(nativeUserName,
+ nativeServerName,
+ NS_LITERAL_CSTRING("imap"),
+ getter_AddRefs(in));
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsAutoString rootFolder;
+ rv = aKey->ReadStringValue(NS_LITERAL_STRING("IMAP Root Folder"), rootFolder);
+ if (NS_SUCCEEDED(rv) && !rootFolder.IsEmpty()) {
+ nsCOMPtr<nsIImapIncomingServer> imapServer = do_QueryInterface(in);
+ nsAutoCString nativeRootFolder;
+ NS_CopyUnicodeToNative(rootFolder, nativeRootFolder);
+ imapServer->SetServerDirectory(nativeRootFolder);
+ }
+
+ SetIncomingServerProperties(in, aKey, NS_LITERAL_STRING("IMAP "));
+
+ IMPORT_LOG2("Created IMAP server named: %s, userName: %s\n",
+ nativeServerName.get(), nativeUserName.get());
+
+ nsAutoString prettyName;
+ if (NS_SUCCEEDED(GetAccountName(aKey, aServerName, prettyName)))
+ rv = in->SetPrettyName(prettyName);
+
+ // We have a server, create an account.
+ nsCOMPtr<nsIMsgAccount> account;
+ rv = aMgr->CreateAccount(getter_AddRefs(account));
+ if (NS_SUCCEEDED(rv) && account) {
+ rv = account->SetIncomingServer(in);
+
+ IMPORT_LOG0("Created an account and set the IMAP server as the incoming server\n");
+
+ // Fiddle with the identities
+ int32_t authMethod;
+ in->GetAuthMethod(&authMethod);
+ SetIdentities(aMgr, account, aKey, userName, authMethod, false);
+ if (ppAccount)
+ account->QueryInterface(NS_GET_IID(nsIMsgAccount), (void **)ppAccount);
+ return true;
+ }
+
+ return false;
+}
+
+bool OESettings::DoPOP3Server(nsIMsgAccountManager *aMgr,
+ nsIWindowsRegKey *aKey,
+ const nsString &aServerName,
+ nsIMsgAccount **ppAccount)
+{
+ if (ppAccount)
+ *ppAccount = nullptr;
+
+ nsAutoString userName;
+ nsresult rv;
+ rv = aKey->ReadStringValue(NS_LITERAL_STRING("POP3 User Name"), userName);
+ if (NS_FAILED(rv))
+ return false;
+
+ nsAutoCString nativeUserName;
+ NS_CopyUnicodeToNative(userName, nativeUserName);
+ nsAutoCString nativeServerName;
+ NS_CopyUnicodeToNative(aServerName, nativeServerName);
+
+ // I now have a user name/server name pair, find out if it already exists?
+ nsCOMPtr<nsIMsgIncomingServer> in;
+ rv = aMgr->FindServer(nativeUserName,
+ nativeServerName,
+ NS_LITERAL_CSTRING("pop3"),
+ getter_AddRefs(in));
+ if (NS_SUCCEEDED(rv)) {
+ IMPORT_LOG2("Existing POP3 server named: %s, userName: %s\n",
+ nativeUserName.get(), nativeServerName.get());
+ // for an existing server we create another identity,
+ // TB listed under 'manage identities'
+ nsCOMPtr<nsIMsgAccount> account;
+ rv = aMgr->FindAccountForServer(in, getter_AddRefs(account));
+ if (NS_SUCCEEDED(rv) && account) {
+ IMPORT_LOG0("Created identity and added to existing POP3 incoming server.\n");
+ // Fiddle with the identities
+ int32_t authMethod;
+ in->GetAuthMethod(&authMethod);
+ SetIdentities(aMgr, account, aKey, userName, authMethod, false);
+ if (ppAccount)
+ account->QueryInterface(NS_GET_IID(nsIMsgAccount), (void **)ppAccount);
+ return true;
+ }
+ return false;
+ }
+
+ // Create the incoming server and an account for it?
+ rv = aMgr->CreateIncomingServer(nativeUserName,
+ nativeServerName,
+ NS_LITERAL_CSTRING("pop3"),
+ getter_AddRefs( in));
+ if (NS_FAILED(rv))
+ return false;
+
+ SetIncomingServerProperties(in, aKey, NS_LITERAL_STRING("POP3 "));
+
+ nsCOMPtr<nsIPop3IncomingServer> pop3Server = do_QueryInterface(in);
+ if (pop3Server) {
+ // set local folders as the Inbox to use for this POP3 server
+ nsCOMPtr<nsIMsgIncomingServer> localFoldersServer;
+ aMgr->GetLocalFoldersServer(getter_AddRefs(localFoldersServer));
+
+ if (!localFoldersServer)
+ {
+ // If Local Folders does not exist already, create it
+
+ if (NS_FAILED(aMgr->CreateLocalMailAccount())) {
+ IMPORT_LOG0("*** Failed to create Local Folders!\n");
+ return false;
+ }
+
+ aMgr->GetLocalFoldersServer(getter_AddRefs(localFoldersServer));
+ }
+
+ // now get the account for this server
+ nsCOMPtr<nsIMsgAccount> localFoldersAccount;
+ aMgr->FindAccountForServer(localFoldersServer, getter_AddRefs(localFoldersAccount));
+ if (localFoldersAccount)
+ {
+ nsCString localFoldersAcctKey;
+ localFoldersAccount->GetKey(localFoldersAcctKey);
+ pop3Server->SetDeferredToAccount(localFoldersAcctKey);
+ }
+
+ uint32_t intValue;
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("POP3 Skip Account"), &intValue);
+ // OE:0=='Include this account when receiving mail or synchronizing'==
+ // TB:1==AM:Server:advanced:Include this server when getting new mail
+ pop3Server->SetDeferGetNewMail(NS_SUCCEEDED(rv) && intValue == 0);
+
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("Leave Mail On Server"),
+ &intValue);
+ pop3Server->SetLeaveMessagesOnServer(NS_SUCCEEDED(rv) && intValue == 1);
+
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("Remove When Deleted"),
+ &intValue);
+ pop3Server->SetDeleteMailLeftOnServer(NS_SUCCEEDED(rv) && intValue == 1);
+
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("Remove When Expired"),
+ &intValue);
+ pop3Server->SetDeleteByAgeFromServer(NS_SUCCEEDED(rv) && intValue == 1);
+
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("Expire Days"),
+ &intValue);
+ if (NS_SUCCEEDED(rv))
+ pop3Server->SetNumDaysToLeaveOnServer(static_cast<int32_t>(intValue));
+ }
+ IMPORT_LOG2("Created POP3 server named: %s, userName: %s\n",
+ nativeServerName.get(), nativeUserName.get());
+ nsString prettyName;
+ if (NS_SUCCEEDED(GetAccountName(aKey, aServerName, prettyName)))
+ rv = in->SetPrettyName(prettyName);
+
+ // We have a server, create an account.
+ nsCOMPtr<nsIMsgAccount> account;
+ rv = aMgr->CreateAccount(getter_AddRefs( account));
+ if (NS_SUCCEEDED( rv) && account) {
+ rv = account->SetIncomingServer(in);
+ IMPORT_LOG0("Created a new account and set the incoming server to the POP3 server.\n");
+
+ int32_t authMethod;
+ in->GetAuthMethod(&authMethod);
+ // Fiddle with the identities
+ SetIdentities(aMgr, account, aKey, userName, authMethod, false);
+ if (ppAccount)
+ account->QueryInterface(NS_GET_IID(nsIMsgAccount),
+ (void **)ppAccount);
+ return true;
+ }
+
+ return false;
+}
+
+bool OESettings::DoNNTPServer(nsIMsgAccountManager *aMgr,
+ nsIWindowsRegKey *aKey,
+ const nsString &aServerName,
+ nsIMsgAccount **ppAccount)
+{
+ if (ppAccount)
+ *ppAccount = nullptr;
+
+ nsAutoString userName;
+ nsresult rv;
+ // this only exists if NNTP server requires it or not anon login
+ rv = aKey->ReadStringValue(NS_LITERAL_STRING("NNTP User Name"), userName);
+
+ bool result = false;
+
+ nsAutoCString nativeServerName;
+ NS_CopyUnicodeToNative(aServerName, nativeServerName);
+ // I now have a user name/server name pair, find out if it already exists?
+ // NNTP can have empty user name. This is wild card in findserver
+ nsCOMPtr<nsIMsgIncomingServer> in;
+ rv = aMgr->FindServer(EmptyCString(),
+ nativeServerName,
+ NS_LITERAL_CSTRING("nntp"),
+ getter_AddRefs(in));
+ if (NS_FAILED(rv) || (in == nullptr)) {
+ // Create the incoming server and an account for it?
+ rv = aMgr->CreateIncomingServer(EmptyCString(),
+ nativeServerName,
+ NS_LITERAL_CSTRING("nntp"),
+ getter_AddRefs(in));
+ if (NS_SUCCEEDED(rv) && in) {
+ uint32_t port = 0;
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("NNTP Port"),
+ &port);
+ if (NS_SUCCEEDED(rv) && port && port != 119)
+ in->SetPort(static_cast<int32_t>(port));
+
+ nsAutoCString nativeUserName;
+ NS_CopyUnicodeToNative(userName, nativeUserName);
+ // do nntpincomingserver stuff
+ nsCOMPtr<nsINntpIncomingServer> nntpServer = do_QueryInterface(in);
+ if (nntpServer && !userName.IsEmpty()) {
+ nntpServer->SetPushAuth(true);
+ in->SetUsername(nativeUserName);
+ }
+
+ IMPORT_LOG2("Created NNTP server named: %s, userName: %s\n",
+ nativeServerName.get(), nativeUserName.get());
+
+ nsString prettyName;
+ if (NS_SUCCEEDED(GetAccountName(aKey, aServerName, prettyName)))
+ rv = in->SetPrettyName(prettyName);
+
+ // We have a server, create an account.
+ nsCOMPtr<nsIMsgAccount> account;
+ rv = aMgr->CreateAccount(getter_AddRefs(account));
+ if (NS_SUCCEEDED(rv) && account) {
+ rv = account->SetIncomingServer(in);
+
+ IMPORT_LOG0("Created an account and set the NNTP server as the incoming server\n");
+
+ // Fiddle with the identities
+ SetIdentities(aMgr, account, aKey, userName, 0, true);
+ result = true;
+ if (ppAccount)
+ account->QueryInterface(NS_GET_IID(nsIMsgAccount), (void **)ppAccount);
+ }
+ }
+ }
+ else if (NS_SUCCEEDED(rv) && in) {
+ // for the existing server...
+ nsCOMPtr<nsIMsgAccount> account;
+ rv = aMgr->FindAccountForServer(in, getter_AddRefs(account));
+ if (NS_SUCCEEDED(rv) && account) {
+ IMPORT_LOG0("Using existing account and set the NNTP server as the incoming server\n");
+ // Fiddle with the identities
+ SetIdentities(aMgr, account, aKey, userName, 0, true);
+ if (ppAccount)
+ account->QueryInterface(NS_GET_IID(nsIMsgAccount),
+ (void **)ppAccount);
+ return true;
+ }
+ }
+ else
+ result = true;
+
+ return result;
+}
+
+void OESettings::SetIncomingServerProperties(nsIMsgIncomingServer *aServer,
+ nsIWindowsRegKey *aKey,
+ const nsString &aKeyNamePrefix)
+{
+ nsresult rv;
+ uint32_t secureConnection = 0;
+ nsString keyName(aKeyNamePrefix);
+ keyName.AppendLiteral("Secure Connection");
+ rv = aKey->ReadIntValue(keyName, &secureConnection);
+ if (NS_SUCCEEDED(rv) && secureConnection == 1)
+ aServer->SetSocketType(nsMsgSocketType::SSL);
+
+ uint32_t port = 0;
+ keyName.SetLength(aKeyNamePrefix.Length());
+ keyName.AppendLiteral("Port");
+ rv = aKey->ReadIntValue(keyName, &port);
+ if (NS_SUCCEEDED(rv) && port)
+ aServer->SetPort(static_cast<int32_t>(port));
+
+ int32_t authMethod;
+ uint32_t useSicily = 0;
+ keyName.SetLength(aKeyNamePrefix.Length());
+ keyName.AppendLiteral("Use Sicily");
+ rv = aKey->ReadIntValue(keyName, &useSicily);
+ if (NS_SUCCEEDED(rv) && useSicily)
+ authMethod = nsMsgAuthMethod::secure;
+ else
+ authMethod = nsMsgAuthMethod::passwordCleartext;
+ aServer->SetAuthMethod(authMethod);
+
+ aServer->SetDoBiff(checkNewMail);
+ aServer->SetBiffMinutes(checkNewMailTime);
+}
+
+void OESettings::SetIdentities(nsIMsgAccountManager *aMgr,
+ nsIMsgAccount *pAcc,
+ nsIWindowsRegKey *aKey,
+ const nsString &aIncomgUserName,
+ int32_t authMethodIncoming,
+ bool isNNTP)
+{
+ // Get the relevant information for an identity
+ nsresult rv;
+ nsAutoString name;
+ rv = aKey->ReadStringValue(isNNTP ?
+ NS_LITERAL_STRING("NNTP Display Name") :
+ NS_LITERAL_STRING("SMTP Display Name"),
+ name);
+ nsAutoString email;
+ rv = aKey->ReadStringValue(isNNTP ?
+ NS_LITERAL_STRING("NNTP Email Address") :
+ NS_LITERAL_STRING("SMTP Email Address"),
+ email);
+ nsAutoString reply;
+ rv = aKey->ReadStringValue(isNNTP ?
+ NS_LITERAL_STRING("NNTP Reply To Email Address") :
+ NS_LITERAL_STRING("SMTP Reply To Email Address"),
+ reply);
+ nsAutoString orgName;
+ rv = aKey->ReadStringValue(isNNTP ?
+ NS_LITERAL_STRING("NNTP Organization Name") :
+ NS_LITERAL_STRING("SMTP Organization Name"),
+ orgName);
+
+ nsCOMPtr<nsIMsgIdentity> id;
+ rv = aMgr->CreateIdentity(getter_AddRefs(id));
+ if (NS_FAILED(rv))
+ return;
+
+ id->SetFullName(name);
+ id->SetOrganization(orgName);
+
+ nsAutoCString nativeEmail;
+ NS_CopyUnicodeToNative(email, nativeEmail);
+ id->SetEmail(nativeEmail);
+ if (!reply.IsEmpty()) {
+ nsAutoCString nativeReply;
+ NS_CopyUnicodeToNative(reply, nativeReply);
+ id->SetReplyTo(nativeReply);
+ }
+
+ // Outlook Express users are used to top style quoting.
+ id->SetReplyOnTop(isNNTP ? 0 : 1);
+ pAcc->AddIdentity(id);
+
+ nsAutoCString nativeName;
+ NS_CopyUnicodeToNative(name, nativeName);
+ IMPORT_LOG0("Created identity and added to the account\n");
+ IMPORT_LOG1("\tname: %s\n", nativeName.get());
+ IMPORT_LOG1("\temail: %s\n", nativeEmail.get());
+
+ if (isNNTP) // NNTP does not use SMTP in OE or TB
+ return;
+ nsAutoString smtpServer;
+ rv = aKey->ReadStringValue(NS_LITERAL_STRING("SMTP Server"), smtpServer);
+ SetSmtpServer(smtpServer, aKey, id, aIncomgUserName, authMethodIncoming);
+}
+
+void OESettings::SetSmtpServer(const nsString &aSmtpServer,
+ nsIWindowsRegKey *aKey,
+ nsIMsgIdentity *aId,
+ const nsString &aIncomgUserName,
+ int32_t authMethodIncoming)
+{
+ // set the id.smtpserver accordingly
+ // first we have to calculate the smtp user name which is based on sicily
+ if (!aKey || !aId || aIncomgUserName.IsEmpty() || aSmtpServer.IsEmpty())
+ return;
+ nsCString smtpServerKey;
+ // smtp user name depends on sicily which may or not exist
+ uint32_t useSicily = 0;
+ nsresult rv = aKey->ReadIntValue(NS_LITERAL_STRING("SMTP Use Sicily"),
+ &useSicily);
+ nsAutoString userName;
+ switch (useSicily) {
+ case 1:
+ case 3:
+ // has to go in whether empty or no
+ // shouldn't be empty but better safe than sorry
+ aKey->ReadStringValue(NS_LITERAL_STRING("SMTP User Name"), userName);
+ break;
+ case 2:
+ userName = aIncomgUserName;
+ break;
+ default:
+ break; // initial userName == ""
+ }
+
+ nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv) && smtpService) {
+ nsCOMPtr<nsISmtpServer> foundServer;
+ // don't try to make another server
+ // regardless if username doesn't match
+ nsAutoCString nativeUserName;
+ NS_CopyUnicodeToNative(userName, nativeUserName);
+ nsAutoCString nativeSmtpServer;
+ NS_CopyUnicodeToNative(aSmtpServer, nativeSmtpServer);
+ rv = smtpService->FindServer(nativeUserName.get(),
+ nativeSmtpServer.get(),
+ getter_AddRefs(foundServer));
+ if (NS_SUCCEEDED(rv) && foundServer) {
+ // set our account keyed to this smptserver key
+ foundServer->GetKey(getter_Copies(smtpServerKey));
+ aId->SetSmtpServerKey(smtpServerKey);
+
+ IMPORT_LOG1("SMTP server already exists: %s\n",
+ nativeSmtpServer.get());
+ }
+ else {
+ nsCOMPtr<nsISmtpServer> smtpServer;
+ rv = smtpService->CreateServer(getter_AddRefs(smtpServer));
+ if (NS_SUCCEEDED(rv) && smtpServer) {
+ uint32_t port = 0;
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("SMTP Port"),
+ &port);
+ if (NS_SUCCEEDED(rv) && port)
+ smtpServer->SetPort(static_cast<int32_t>(port));
+
+ int32_t socketType = nsMsgSocketType::plain;
+ uint32_t secureConnection = 0;
+ rv = aKey->ReadIntValue(NS_LITERAL_STRING("SMTP Secure Connection"),
+ &secureConnection);
+ if (NS_SUCCEEDED(rv) && secureConnection == 1) {
+ // Outlook Express does not support STARTTLS without KB933612 fix.
+ if (IsKB933612Applied() && port != 465)
+ socketType = nsMsgSocketType::alwaysSTARTTLS;
+ else
+ socketType = nsMsgSocketType::SSL;
+ }
+ smtpServer->SetSocketType(socketType);
+ smtpServer->SetUsername(nativeUserName);
+ switch (useSicily) {
+ case 1 :
+ smtpServer->SetAuthMethod(nsMsgAuthMethod::secure);
+ break;
+ case 2 : // requires SMTP authentication to use the incoming server settings
+ smtpServer->SetAuthMethod(authMethodIncoming);
+ break;
+ case 3 :
+ smtpServer->SetAuthMethod(nsMsgAuthMethod::passwordCleartext);
+ break;
+ default:
+ smtpServer->SetAuthMethod(nsMsgAuthMethod::none);
+ }
+
+ smtpServer->SetHostname(nativeSmtpServer);
+
+ smtpServer->GetKey(getter_Copies(smtpServerKey));
+ aId->SetSmtpServerKey(smtpServerKey);
+
+ IMPORT_LOG1("Created new SMTP server: %s\n",
+ nativeSmtpServer.get());
+ }
+ }
+ }
+}
+
+bool OESettings::IsKB933612Applied()
+{
+ // The following versions of Windows include KB933612 fix:
+ // - Windows 7 and future versions of Windows
+ // - Windows Vista, SP1 or later
+ // - Windows Server 2003, SP2 or later
+ // - Windows XP, SP3 or later
+ //
+ // The following versions do not:
+ // - Windows Vista SP0
+ // - Windows Server 2003, SP1 or earlier
+ // - Windows XP, SP2 or earlier
+ //
+ // See http://support.microsoft.com/kb/929123 and
+ // http://support.microsoft.com/kb/933612
+ //
+ // Note that mozilla::IsWin2003SP2OrLater() will return true for
+ // Windows Vista and mozilla::IsXPSP3OrLater() will return true
+ // for Windows Server 2003.
+ return mozilla::IsVistaSP1OrLater() ||
+ !mozilla::IsWin2003OrLater() && mozilla::IsXPSP3OrLater() ||
+ !mozilla::IsVistaOrLater() && mozilla::IsWin2003SP2OrLater();
+}
+
diff --git a/mailnews/import/oexpress/nsOESettings.h b/mailnews/import/oexpress/nsOESettings.h
new file mode 100644
index 000000000..8d2525423
--- /dev/null
+++ b/mailnews/import/oexpress/nsOESettings.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOESettings_h___
+#define nsOESettings_h___
+
+#include "nsIImportSettings.h"
+
+class nsOESettings : public nsIImportSettings {
+public:
+ nsOESettings();
+ static nsresult Create(nsIImportSettings** aImport);
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIIMPORTSETTINGS
+
+private:
+ virtual ~nsOESettings();
+};
+
+#endif /* nsOESettings_h___ */
diff --git a/mailnews/import/oexpress/nsOEStringBundle.cpp b/mailnews/import/oexpress/nsOEStringBundle.cpp
new file mode 100644
index 000000000..3d3b4035a
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEStringBundle.cpp
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "prprf.h"
+#include "prmem.h"
+#include "nsCOMPtr.h"
+#include "nsMsgUtils.h"
+#include "nsIStringBundle.h"
+#include "nsOEStringBundle.h"
+#include "nsIServiceManager.h"
+#include "nsIURI.h"
+#include "mozilla/Services.h"
+
+#define OE_MSGS_URL "chrome://messenger/locale/oeImportMsgs.properties"
+
+nsIStringBundle * nsOEStringBundle::m_pBundle = nullptr;
+
+nsIStringBundle *nsOEStringBundle::GetStringBundle(void)
+{
+ if (m_pBundle)
+ return m_pBundle;
+
+ char* propertyURL = OE_MSGS_URL;
+ nsIStringBundle* sBundle = nullptr;
+
+ nsCOMPtr<nsIStringBundleService> sBundleService =
+ mozilla::services::GetStringBundleService();
+ if (sBundleService) {
+ sBundleService->CreateBundle(propertyURL, &sBundle);
+ }
+
+ m_pBundle = sBundle;
+
+ return sBundle;
+}
+
+
+void nsOEStringBundle::GetStringByID(int32_t stringID, nsString& result)
+{
+ char16_t *ptrv = GetStringByID(stringID);
+ result.Adopt(ptrv);
+}
+
+char16_t *nsOEStringBundle::GetStringByID(int32_t stringID)
+{
+ if (!m_pBundle)
+ m_pBundle = GetStringBundle();
+
+ if (m_pBundle) {
+ char16_t *ptrv = nullptr;
+ nsresult rv = m_pBundle->GetStringFromID(stringID, &ptrv);
+
+ if (NS_SUCCEEDED(rv) && ptrv)
+ return ptrv;
+ }
+
+ nsString resultString;
+ resultString.AppendLiteral("[StringID ");
+ resultString.AppendInt(stringID);
+ resultString.AppendLiteral("?]");
+
+ return ToNewUnicode(resultString);
+}
+
+void nsOEStringBundle::Cleanup(void)
+{
+ if (m_pBundle)
+ m_pBundle->Release();
+ m_pBundle = nullptr;
+}
diff --git a/mailnews/import/oexpress/nsOEStringBundle.h b/mailnews/import/oexpress/nsOEStringBundle.h
new file mode 100644
index 000000000..36829e5e3
--- /dev/null
+++ b/mailnews/import/oexpress/nsOEStringBundle.h
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _nsOEStringBundle_H__
+#define _nsOEStringBundle_H__
+
+#include "nsStringGlue.h"
+
+class nsIStringBundle;
+
+class nsOEStringBundle {
+public:
+ static char16_t * GetStringByID(int32_t stringID);
+ static void GetStringByID(int32_t stringID, nsString& result);
+ static nsIStringBundle * GetStringBundle(void); // don't release
+ static void FreeString(char16_t *pStr) { NS_Free(pStr);}
+ static void Cleanup(void);
+
+private:
+ static nsIStringBundle * m_pBundle;
+};
+
+
+
+#define OEIMPORT_NAME 2000
+#define OEIMPORT_DESCRIPTION 2011
+#define OEIMPORT_MAILBOX_SUCCESS 2002
+#define OEIMPORT_MAILBOX_BADPARAM 2003
+#define OEIMPORT_MAILBOX_BADSOURCEFILE 2004
+#define OEIMPORT_MAILBOX_CONVERTERROR 2005
+#define OEIMPORT_DEFAULT_NAME 2006
+#define OEIMPORT_AUTOFIND 2007
+#define OEIMPORT_ADDRESS_SUCCESS 2008
+#define OEIMPORT_ADDRESS_CONVERTERROR 2009
+#define OEIMPORT_ADDRESS_BADPARAM 2010
+
+#endif /* _nsOEStringBundle_H__ */