summaryrefslogtreecommitdiffstats
path: root/mailnews/import/src
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/src
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/src')
-rw-r--r--mailnews/import/src/ImportCharSet.cpp58
-rw-r--r--mailnews/import/src/ImportCharSet.h175
-rw-r--r--mailnews/import/src/ImportDebug.h22
-rw-r--r--mailnews/import/src/ImportOutFile.cpp299
-rw-r--r--mailnews/import/src/ImportOutFile.h94
-rw-r--r--mailnews/import/src/ImportTranslate.cpp105
-rw-r--r--mailnews/import/src/ImportTranslate.h23
-rw-r--r--mailnews/import/src/moz.build25
-rw-r--r--mailnews/import/src/nsImportABDescriptor.cpp32
-rw-r--r--mailnews/import/src/nsImportABDescriptor.h103
-rw-r--r--mailnews/import/src/nsImportAddressBooks.cpp894
-rw-r--r--mailnews/import/src/nsImportEmbeddedImageData.cpp64
-rw-r--r--mailnews/import/src/nsImportEmbeddedImageData.h32
-rw-r--r--mailnews/import/src/nsImportEncodeScan.cpp374
-rw-r--r--mailnews/import/src/nsImportEncodeScan.h39
-rw-r--r--mailnews/import/src/nsImportFieldMap.cpp384
-rw-r--r--mailnews/import/src/nsImportFieldMap.h46
-rw-r--r--mailnews/import/src/nsImportMail.cpp1208
-rw-r--r--mailnews/import/src/nsImportMailboxDescriptor.cpp39
-rw-r--r--mailnews/import/src/nsImportMailboxDescriptor.h63
-rw-r--r--mailnews/import/src/nsImportMimeEncode.cpp411
-rw-r--r--mailnews/import/src/nsImportMimeEncode.h73
-rw-r--r--mailnews/import/src/nsImportScanFile.cpp172
-rw-r--r--mailnews/import/src/nsImportScanFile.h54
-rw-r--r--mailnews/import/src/nsImportService.cpp583
-rw-r--r--mailnews/import/src/nsImportService.h96
-rw-r--r--mailnews/import/src/nsImportStringBundle.cpp80
-rw-r--r--mailnews/import/src/nsImportStringBundle.h48
-rw-r--r--mailnews/import/src/nsImportTranslator.cpp296
-rw-r--r--mailnews/import/src/nsImportTranslator.h66
30 files changed, 5958 insertions, 0 deletions
diff --git a/mailnews/import/src/ImportCharSet.cpp b/mailnews/import/src/ImportCharSet.cpp
new file mode 100644
index 000000000..a8bc48d19
--- /dev/null
+++ b/mailnews/import/src/ImportCharSet.cpp
@@ -0,0 +1,58 @@
+/* -*- 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/. */
+
+
+#include "ImportCharSet.h"
+
+char ImportCharSet::m_upperCaseMap[256];
+char ImportCharSet::m_Ascii[256] = {0}; // the initialiser makes it strong
+
+class UInitMaps {
+public:
+ UInitMaps();
+};
+
+UInitMaps gInitMaps;
+
+UInitMaps::UInitMaps()
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ ImportCharSet::m_upperCaseMap[i] = i;
+ for (i = 'a'; i <= 'z'; i++)
+ ImportCharSet::m_upperCaseMap[i] = i - 'a' + 'A';
+
+ for (i = 0; i < 256; i++)
+ ImportCharSet::m_Ascii[i] = 0;
+
+ for (i = ImportCharSet::cUpperAChar; i <= ImportCharSet::cUpperZChar; i++)
+ ImportCharSet::m_Ascii[i] |= (ImportCharSet::cAlphaNumChar | ImportCharSet::cAlphaChar);
+ for (i = ImportCharSet::cLowerAChar; i <= ImportCharSet::cLowerZChar; i++)
+ ImportCharSet::m_Ascii[i] |= (ImportCharSet::cAlphaNumChar | ImportCharSet::cAlphaChar);
+ for (i = ImportCharSet::cZeroChar; i <= ImportCharSet::cNineChar; i++)
+ ImportCharSet::m_Ascii[i] |= (ImportCharSet::cAlphaNumChar | ImportCharSet::cDigitChar);
+
+ ImportCharSet::m_Ascii[ImportCharSet::cTabChar] |= ImportCharSet::cWhiteSpaceChar;
+ ImportCharSet::m_Ascii[ImportCharSet::cCRChar] |= ImportCharSet::cWhiteSpaceChar;
+ ImportCharSet::m_Ascii[ImportCharSet::cLinefeedChar] |= ImportCharSet::cWhiteSpaceChar;
+ ImportCharSet::m_Ascii[ImportCharSet::cSpaceChar] |= ImportCharSet::cWhiteSpaceChar;
+
+ ImportCharSet::m_Ascii[uint8_t('(')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t(')')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('<')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('>')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('@')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t(',')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t(';')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t(':')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('\\')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('"')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('.')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t('[')] |= ImportCharSet::c822SpecialChar;
+ ImportCharSet::m_Ascii[uint8_t(']')] |= ImportCharSet::c822SpecialChar;
+
+
+}
diff --git a/mailnews/import/src/ImportCharSet.h b/mailnews/import/src/ImportCharSet.h
new file mode 100644
index 000000000..c1f649ef2
--- /dev/null
+++ b/mailnews/import/src/ImportCharSet.h
@@ -0,0 +1,175 @@
+/* -*- 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/. */
+
+#ifndef ImportCharSet_h___
+#define ImportCharSet_h___
+
+#include "nscore.h"
+
+
+// Some useful ASCII values
+// 'A' = 65, 0x41
+// 'Z' = 90, 0x5a
+// '_' = 95, 0x5f
+// 'a' = 97, 0x61
+// 'z' = 122, 0x7a
+// '0' = 48, 0x30
+// '1' = 49, 0x31
+// '9' = 57, 0x39
+// ' ' = 32, 0x20
+// whitespace, 10, 13, 32, 9 (linefeed, cr, space, tab) - 0x0a, 0x0d, 0x20, 0x09
+// ':' = 58, 0x3a
+
+
+// a typedef enum would be nicer but some compilers still have trouble with treating
+// enum's as plain numbers when needed
+
+class ImportCharSet {
+public:
+ enum {
+ cTabChar = 9,
+ cLinefeedChar = 10,
+ cCRChar = 13,
+ cSpaceChar = 32,
+ cUpperAChar = 65,
+ cUpperZChar = 90,
+ cUnderscoreChar = 95,
+ cLowerAChar = 97,
+ cLowerZChar = 122,
+ cZeroChar = 48,
+ cNineChar = 57,
+
+ cAlphaNumChar = 1,
+ cAlphaChar = 2,
+ cWhiteSpaceChar = 4,
+ cDigitChar = 8,
+ c822SpecialChar = 16
+ };
+
+ static char m_upperCaseMap[256];
+ static char m_Ascii[256];
+
+ inline static bool IsUSAscii(uint8_t ch) { return (((ch & (uint8_t)0x80) == 0));}
+ inline static bool Is822CtlChar(uint8_t ch) { return (ch < 32);}
+ inline static bool Is822SpecialChar(uint8_t ch) { return ((m_Ascii[ch] & c822SpecialChar) == c822SpecialChar);}
+ inline static bool IsWhiteSpace(uint8_t ch) { return ((m_Ascii[ch] & cWhiteSpaceChar) == cWhiteSpaceChar); }
+ inline static bool IsAlphaNum(uint8_t ch) { return ((m_Ascii[ch] & cAlphaNumChar) == cAlphaNumChar); }
+ inline static bool IsDigit(uint8_t ch) { return ((m_Ascii[ch] & cDigitChar) == cDigitChar); }
+
+ inline static uint8_t ToLower(uint8_t ch) { if ((m_Ascii[ch] & cAlphaChar) == cAlphaChar) { return cLowerAChar + (m_upperCaseMap[ch] - cUpperAChar); } else return ch; }
+
+ inline static long AsciiToLong(const uint8_t * pChar, uint32_t len) {
+ long num = 0;
+ while (len) {
+ if ((m_Ascii[*pChar] & cDigitChar) == 0)
+ return num;
+ num *= 10;
+ num += (*pChar - cZeroChar);
+ len--;
+ pChar++;
+ }
+ return num;
+ }
+
+ inline static void ByteToHex(uint8_t byte, uint8_t * pHex) {
+ uint8_t val = byte;
+ val /= 16;
+ if (val < 10)
+ *pHex = '0' + val;
+ else
+ *pHex = 'A' + (val - 10);
+ pHex++;
+ val = byte;
+ val &= 0x0F;
+ if (val < 10)
+ *pHex = '0' + val;
+ else
+ *pHex = 'A' + (val - 10);
+ }
+
+ inline static void LongToHexBytes(uint32_t type, uint8_t * pStr) {
+ ByteToHex((uint8_t) (type >> 24), pStr);
+ pStr += 2;
+ ByteToHex((uint8_t) ((type >> 16) & 0x0FF), pStr);
+ pStr += 2;
+ ByteToHex((uint8_t) ((type >> 8) & 0x0FF), pStr);
+ pStr += 2;
+ ByteToHex((uint8_t) (type & 0x0FF), pStr);
+ }
+
+ inline static void SkipWhiteSpace(const uint8_t * & pChar, uint32_t & pos, uint32_t max) {
+ while ((pos < max) && (IsWhiteSpace(*pChar))) {
+ pos++; pChar++;
+ }
+ }
+
+ inline static void SkipSpaceTab(const uint8_t * & pChar, uint32_t& pos, uint32_t max) {
+ while ((pos < max) && ((*pChar == (uint8_t)cSpaceChar) || (*pChar == (uint8_t)cTabChar))) {
+ pos++; pChar++;
+ }
+ }
+
+ inline static void SkipTilSpaceTab(const uint8_t * & pChar, uint32_t& pos, uint32_t max) {
+ while ((pos < max) && (*pChar != (uint8_t)cSpaceChar) && (*pChar != (uint8_t)cTabChar)) {
+ pos++;
+ pChar++;
+ }
+ }
+
+ inline static bool StrNICmp(const uint8_t * pChar, const uint8_t * pSrc, uint32_t len) {
+ while (len && (m_upperCaseMap[*pChar] == m_upperCaseMap[*pSrc])) {
+ pChar++; pSrc++; len--;
+ }
+ return len == 0;
+ }
+
+ inline static bool StrNCmp(const uint8_t * pChar, const uint8_t *pSrc, uint32_t len) {
+ while (len && (*pChar == *pSrc)) {
+ pChar++; pSrc++; len--;
+ }
+ return len == 0;
+ }
+
+ inline static int FindChar(const uint8_t * pChar, uint8_t ch, uint32_t max) {
+ uint32_t pos = 0;
+ while ((pos < max) && (*pChar != ch)) {
+ pos++; pChar++;
+ }
+ if (pos < max)
+ return (int) pos;
+ else
+ return -1;
+ }
+
+ inline static bool NextChar(const uint8_t * & pChar, uint8_t ch, uint32_t& pos, uint32_t max) {
+ if ((pos < max) && (*pChar == ch)) {
+ pos++;
+ pChar++;
+ return true;
+ }
+ return false;
+ }
+
+ inline static int32_t strcmp(const char * pS1, const char * pS2) {
+ while (*pS1 && *pS2 && (*pS1 == *pS2)) {
+ pS1++;
+ pS2++;
+ }
+ return *pS1 - *pS2;
+ }
+
+ inline static int32_t stricmp(const char * pS1, const char * pS2) {
+ while (*pS1 && *pS2 && (m_upperCaseMap[uint8_t(*pS1)] == m_upperCaseMap[uint8_t(*pS2)])) {
+ pS1++;
+ pS2++;
+ }
+ return m_upperCaseMap[uint8_t(*pS1)] - m_upperCaseMap[uint8_t(*pS2)];
+ }
+
+};
+
+
+#endif /* ImportCharSet_h__ */
+
diff --git a/mailnews/import/src/ImportDebug.h b/mailnews/import/src/ImportDebug.h
new file mode 100644
index 000000000..b905aa4a9
--- /dev/null
+++ b/mailnews/import/src/ImportDebug.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 ImportDebug_h___
+#define ImportDebug_h___
+
+#ifdef NS_DEBUG
+#define IMPORT_DEBUG 1
+#endif
+
+// Use MOZ_LOG for logging.
+#include "mozilla/Logging.h"
+extern PRLogModuleInfo *IMPORTLOGMODULE; // Logging module
+
+#define IMPORT_LOG0(x) MOZ_LOG(IMPORTLOGMODULE, mozilla::LogLevel::Debug, (x))
+#define IMPORT_LOG1(x, y) MOZ_LOG(IMPORTLOGMODULE, mozilla::LogLevel::Debug, (x, y))
+#define IMPORT_LOG2(x, y, z) MOZ_LOG(IMPORTLOGMODULE, mozilla::LogLevel::Debug, (x, y, z))
+#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(IMPORTLOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d))
+
+#endif
diff --git a/mailnews/import/src/ImportOutFile.cpp b/mailnews/import/src/ImportOutFile.cpp
new file mode 100644
index 000000000..beeb8903a
--- /dev/null
+++ b/mailnews/import/src/ImportOutFile.cpp
@@ -0,0 +1,299 @@
+/* -*- 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/. */
+
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "prio.h"
+#include "nsNetUtil.h"
+#include "nsISeekableStream.h"
+#include "nsMsgUtils.h"
+#include "ImportOutFile.h"
+#include "ImportCharSet.h"
+
+#include "ImportDebug.h"
+
+/*
+#ifdef _MAC
+#define kMacNoCreator '????'
+#define kMacTextFile 'TEXT'
+#else
+#define kMacNoCreator 0
+#define kMacTextFile 0
+#endif
+*/
+
+ImportOutFile::ImportOutFile()
+{
+ m_ownsFileAndBuffer = false;
+ m_pos = 0;
+ m_pBuf = nullptr;
+ m_bufSz = 0;
+ m_pTrans = nullptr;
+ m_pTransOut = nullptr;
+ m_pTransBuf = nullptr;
+}
+
+ImportOutFile::ImportOutFile(nsIFile *pFile, uint8_t * pBuf, uint32_t sz)
+{
+ m_pTransBuf = nullptr;
+ m_pTransOut = nullptr;
+ m_pTrans = nullptr;
+ m_ownsFileAndBuffer = false;
+ InitOutFile(pFile, pBuf, sz);
+}
+
+ImportOutFile::~ImportOutFile()
+{
+ if (m_ownsFileAndBuffer)
+ {
+ Flush();
+ delete [] m_pBuf;
+ }
+
+ delete m_pTrans;
+ delete m_pTransOut;
+ delete [] m_pTransBuf;
+}
+
+bool ImportOutFile::Set8bitTranslator(nsImportTranslator *pTrans)
+{
+ if (!Flush())
+ return false;
+
+ m_engaged = false;
+ m_pTrans = pTrans;
+ m_supports8to7 = pTrans->Supports8bitEncoding();
+
+
+ return true;
+}
+
+bool ImportOutFile::End8bitTranslation(bool *pEngaged, nsCString& useCharset, nsCString& encoding)
+{
+ if (!m_pTrans)
+ return false;
+
+
+ bool bResult = Flush();
+ if (m_supports8to7 && m_pTransOut) {
+ if (bResult)
+ bResult = m_pTrans->FinishConvertToFile(m_pTransOut);
+ if (bResult)
+ bResult = Flush();
+ }
+
+ if (m_supports8to7) {
+ m_pTrans->GetCharset(useCharset);
+ m_pTrans->GetEncoding(encoding);
+ }
+ else
+ useCharset.Truncate();
+ *pEngaged = m_engaged;
+ delete m_pTrans;
+ m_pTrans = nullptr;
+ delete m_pTransOut;
+ m_pTransOut = nullptr;
+ delete [] m_pTransBuf;
+ m_pTransBuf = nullptr;
+
+ return bResult;
+}
+
+bool ImportOutFile::InitOutFile(nsIFile *pFile, uint32_t bufSz)
+{
+ if (!bufSz)
+ bufSz = 32 * 1024;
+ if (!m_pBuf)
+ m_pBuf = new uint8_t[ bufSz];
+
+ if (!m_outputStream)
+ {
+ nsresult rv;
+ rv = MsgNewBufferedFileOutputStream(getter_AddRefs(m_outputStream),
+ pFile,
+ PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE,
+ 0644);
+
+ if (NS_FAILED(rv))
+ {
+ IMPORT_LOG0("Couldn't create outfile\n");
+ delete [] m_pBuf;
+ m_pBuf = nullptr;
+ return false;
+ }
+ }
+ m_pFile = pFile;
+ m_ownsFileAndBuffer = true;
+ m_pos = 0;
+ m_bufSz = bufSz;
+ return true;
+}
+
+void ImportOutFile::InitOutFile(nsIFile *pFile, uint8_t * pBuf, uint32_t sz)
+{
+ m_ownsFileAndBuffer = false;
+ m_pFile = pFile;
+ m_pBuf = pBuf;
+ m_bufSz = sz;
+ m_pos = 0;
+}
+
+
+
+bool ImportOutFile::Flush(void)
+{
+ if (!m_pos)
+ return true;
+
+ uint32_t transLen;
+ bool duddleyDoWrite = false;
+
+ // handle translations if appropriate
+ if (m_pTrans) {
+ if (m_engaged && m_supports8to7) {
+ // Markers can get confused by this crap!!!
+ // TLR: FIXME: Need to update the markers based on
+ // the difference between the translated len and untranslated len
+
+ if (!m_pTrans->ConvertToFile( m_pBuf, m_pos, m_pTransOut, &transLen))
+ return false;
+ if (!m_pTransOut->Flush())
+ return false;
+ // now update our buffer...
+ if (transLen < m_pos) {
+ memcpy(m_pBuf, m_pBuf + transLen, m_pos - transLen);
+ }
+ m_pos -= transLen;
+ }
+ else if (m_engaged) {
+ // does not actually support translation!
+ duddleyDoWrite = true;
+ }
+ else {
+ // should we engage?
+ uint8_t * pChar = m_pBuf;
+ uint32_t len = m_pos;
+ while (len) {
+ if (!ImportCharSet::IsUSAscii(*pChar))
+ break;
+ pChar++;
+ len--;
+ }
+ if (len) {
+ m_engaged = true;
+ if (m_supports8to7) {
+ // allocate our translation output buffer and file...
+ m_pTransBuf = new uint8_t[m_bufSz];
+ m_pTransOut = new ImportOutFile(m_pFile, m_pTransBuf, m_bufSz);
+ return Flush();
+ }
+ else
+ duddleyDoWrite = true;
+ }
+ else {
+ duddleyDoWrite = true;
+ }
+ }
+ }
+ else
+ duddleyDoWrite = true;
+
+ if (duddleyDoWrite) {
+ uint32_t written = 0;
+ nsresult rv = m_outputStream->Write((const char *)m_pBuf, (int32_t)m_pos, &written);
+ if (NS_FAILED(rv) || ((uint32_t)written != m_pos))
+ return false;
+ m_pos = 0;
+ }
+
+ return true;
+}
+
+bool ImportOutFile::WriteU8NullTerm(const uint8_t * pSrc, bool includeNull)
+{
+ while (*pSrc) {
+ if (m_pos >= m_bufSz) {
+ if (!Flush())
+ return false;
+ }
+ *(m_pBuf + m_pos) = *pSrc;
+ m_pos++;
+ pSrc++;
+ }
+ if (includeNull) {
+ if (m_pos >= m_bufSz) {
+ if (!Flush())
+ return false;
+ }
+ *(m_pBuf + m_pos) = 0;
+ m_pos++;
+ }
+
+ return true;
+}
+
+bool ImportOutFile::SetMarker(int markerID)
+{
+ if (!Flush()) {
+ return false;
+ }
+
+ if (markerID < kMaxMarkers) {
+ int64_t pos = 0;
+ if (m_outputStream)
+ {
+ // do we need to flush for the seek to give us the right pos?
+ m_outputStream->Flush();
+ nsresult rv;
+ nsCOMPtr <nsISeekableStream> seekStream = do_QueryInterface(m_outputStream, &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+ rv = seekStream->Tell(&pos);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error, Tell failed on output stream\n");
+ return false;
+ }
+ }
+ m_markers[markerID] = (uint32_t)pos + m_pos;
+ }
+
+ return true;
+}
+
+void ImportOutFile::ClearMarker(int markerID)
+{
+ if (markerID < kMaxMarkers)
+ m_markers[markerID] = 0;
+}
+
+bool ImportOutFile::WriteStrAtMarker(int markerID, const char *pStr)
+{
+ if (markerID >= kMaxMarkers)
+ return false;
+
+ if (!Flush())
+ return false;
+ int64_t pos;
+ m_outputStream->Flush();
+ nsresult rv;
+ nsCOMPtr <nsISeekableStream> seekStream = do_QueryInterface(m_outputStream, &rv);
+ NS_ENSURE_SUCCESS(rv, false);
+ rv = seekStream->Tell(&pos);
+ if (NS_FAILED(rv))
+ return false;
+ rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, (int32_t) m_markers[markerID]);
+ if (NS_FAILED(rv))
+ return false;
+ uint32_t written;
+ rv = m_outputStream->Write(pStr, strlen(pStr), &written);
+ if (NS_FAILED(rv))
+ return false;
+
+ rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, pos);
+ if (NS_FAILED(rv))
+ return false;
+
+ return true;
+}
+
diff --git a/mailnews/import/src/ImportOutFile.h b/mailnews/import/src/ImportOutFile.h
new file mode 100644
index 000000000..461728c22
--- /dev/null
+++ b/mailnews/import/src/ImportOutFile.h
@@ -0,0 +1,94 @@
+/* -*- 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/. */
+#ifndef ImportOutFile_h___
+#define ImportOutFile_h___
+
+#include "nsImportTranslator.h"
+#include "nsIOutputStream.h"
+#include "nsIFile.h"
+
+#define kMaxMarkers 10
+
+class ImportOutFile;
+
+class ImportOutFile {
+public:
+ ImportOutFile();
+ ImportOutFile(nsIFile *pFile, uint8_t * pBuf, uint32_t sz);
+ ~ImportOutFile();
+
+ bool InitOutFile(nsIFile *pFile, uint32_t bufSz = 4096);
+ void InitOutFile(nsIFile *pFile, uint8_t * pBuf, uint32_t sz);
+ inline bool WriteData(const uint8_t * pSrc, uint32_t len);
+ inline bool WriteByte(uint8_t byte);
+ bool WriteStr(const char *pStr) {return WriteU8NullTerm((const uint8_t *) pStr, false); }
+ bool WriteU8NullTerm(const uint8_t * pSrc, bool includeNull);
+ bool WriteEol(void) { return WriteStr("\x0D\x0A"); }
+ bool Done(void) {return Flush();}
+
+ // Marker support
+ bool SetMarker(int markerID);
+ void ClearMarker(int markerID);
+ bool WriteStrAtMarker(int markerID, const char *pStr);
+
+ // 8-bit to 7-bit translation
+ bool Set8bitTranslator(nsImportTranslator *pTrans);
+ bool End8bitTranslation(bool *pEngaged, nsCString& useCharset, nsCString& encoding);
+
+protected:
+ bool Flush(void);
+
+protected:
+ nsCOMPtr <nsIFile> m_pFile;
+ nsCOMPtr <nsIOutputStream> m_outputStream;
+ uint8_t * m_pBuf;
+ uint32_t m_bufSz;
+ uint32_t m_pos;
+ bool m_ownsFileAndBuffer;
+
+ // markers
+ uint32_t m_markers[kMaxMarkers];
+
+ // 8 bit to 7 bit translations
+ nsImportTranslator * m_pTrans;
+ bool m_engaged;
+ bool m_supports8to7;
+ ImportOutFile * m_pTransOut;
+ uint8_t * m_pTransBuf;
+};
+
+inline bool ImportOutFile::WriteData(const uint8_t * pSrc, uint32_t len) {
+ while ((len + m_pos) > m_bufSz) {
+ if ((m_bufSz - m_pos)) {
+ memcpy(m_pBuf + m_pos, pSrc, m_bufSz - m_pos);
+ len -= (m_bufSz - m_pos);
+ pSrc += (m_bufSz - m_pos);
+ m_pos = m_bufSz;
+ }
+ if (!Flush())
+ return false;
+ }
+
+ if (len) {
+ memcpy(m_pBuf + m_pos, pSrc, len);
+ m_pos += len;
+ }
+
+ return true;
+}
+
+inline bool ImportOutFile::WriteByte(uint8_t byte) {
+ if (m_pos == m_bufSz) {
+ if (!Flush())
+ return false;
+ }
+ *(m_pBuf + m_pos) = byte;
+ m_pos++;
+ return true;
+}
+
+#endif /* ImportOutFile_h__ */
+
+
diff --git a/mailnews/import/src/ImportTranslate.cpp b/mailnews/import/src/ImportTranslate.cpp
new file mode 100644
index 000000000..f7f32f552
--- /dev/null
+++ b/mailnews/import/src/ImportTranslate.cpp
@@ -0,0 +1,105 @@
+/* -*- 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/. */
+
+#include "ImportTranslate.h"
+
+int ImportTranslate::m_useTranslator = -1;
+
+
+bool ImportTranslate::ConvertString(const nsCString& inStr, nsCString& outStr, bool mimeHeader)
+{
+ if (inStr.IsEmpty()) {
+ outStr = inStr;
+ return true;
+ }
+
+ nsImportTranslator *pTrans = GetTranslator();
+ // int maxLen = (int) pTrans->GetMaxBufferSize(inStr.Length());
+ // int hLen = 0;
+ nsCString set;
+ nsCString lang;
+
+ if (mimeHeader) {
+ // add the charset and language
+ pTrans->GetCharset(set);
+ pTrans->GetLanguage(lang);
+ }
+
+ // Unfortunatly, we didn't implement ConvertBuffer for all translators,
+ // just ConvertToFile. This means that this data will not always
+ // be converted to the charset of pTrans. In that case...
+ // We don't always have the data in the same charset as the current
+ // translator...
+ // It is safer to leave the charset and language field blank
+ set.Truncate();
+ lang.Truncate();
+
+ uint8_t * pBuf;
+ /*
+ pBuf = (P_U8) outStr.GetBuffer(maxLen);
+ if (!pBuf) {
+ delete pTrans;
+ return FALSE;
+ }
+ pTrans->ConvertBuffer((PC_U8)(PC_S8)inStr, inStr.GetLength(), pBuf);
+ outStr.ReleaseBuffer();
+ */
+ outStr = inStr;
+ delete pTrans;
+
+
+ // Now I need to run the string through the mime-header special char
+ // encoder.
+
+ pTrans = new CMHTranslator;
+ pBuf = new uint8_t[pTrans->GetMaxBufferSize(outStr.Length())];
+ pTrans->ConvertBuffer((const uint8_t *)(outStr.get()), outStr.Length(), pBuf);
+ delete pTrans;
+ outStr.Truncate();
+ if (mimeHeader) {
+ outStr = set;
+ outStr += "'";
+ outStr += lang;
+ outStr += "'";
+ }
+ outStr += (const char *)pBuf;
+ delete [] pBuf;
+
+ return true;
+}
+
+
+nsImportTranslator *ImportTranslate::GetTranslator(void)
+{
+ if (m_useTranslator == -1) {
+ // get the translator to use...
+ // CString trans;
+ // trans.LoadString(IDS_LANGUAGE_TRANSLATION);
+ m_useTranslator = 0;
+ // if (!trans.CompareNoCase("iso-2022-jp"))
+ // gWizData.m_useTranslator = 1;
+ }
+
+ switch(m_useTranslator) {
+ case 0:
+ return new nsImportTranslator;
+ //case 1:
+ // return new CSJis2JisTranslator;
+ default:
+ return new nsImportTranslator;
+ }
+}
+
+nsImportTranslator *ImportTranslate::GetMatchingTranslator(const char *pCharSet)
+{
+/*
+ CString jp = "iso-2022-jp";
+ if (!jp.CompareNoCase(pCharSet))
+ return new CSJis2JisTranslator;
+*/
+
+ return nullptr;
+}
+
diff --git a/mailnews/import/src/ImportTranslate.h b/mailnews/import/src/ImportTranslate.h
new file mode 100644
index 000000000..3e6c596d4
--- /dev/null
+++ b/mailnews/import/src/ImportTranslate.h
@@ -0,0 +1,23 @@
+/* -*- 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/. */
+
+#ifndef ImportTranslate_h___
+#define ImportTranslate_h___
+
+#include "nsStringGlue.h"
+#include "nsImportTranslator.h"
+
+class ImportTranslate {
+public:
+ static bool ConvertString(const nsCString& inStr, nsCString& outStr, bool mimeHeader);
+ static nsImportTranslator *GetTranslator(void);
+ static nsImportTranslator *GetMatchingTranslator(const char *pCharSet);
+
+protected:
+ static int m_useTranslator;
+};
+
+
+#endif /* ImportTranslate_h__ */
diff --git a/mailnews/import/src/moz.build b/mailnews/import/src/moz.build
new file mode 100644
index 000000000..2df4926d5
--- /dev/null
+++ b/mailnews/import/src/moz.build
@@ -0,0 +1,25 @@
+# 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 += [
+ 'ImportCharSet.cpp',
+ 'ImportOutFile.cpp',
+ 'ImportTranslate.cpp',
+ 'nsImportABDescriptor.cpp',
+ 'nsImportAddressBooks.cpp',
+ 'nsImportEmbeddedImageData.cpp',
+ 'nsImportEncodeScan.cpp',
+ 'nsImportFieldMap.cpp',
+ 'nsImportMail.cpp',
+ 'nsImportMailboxDescriptor.cpp',
+ 'nsImportMimeEncode.cpp',
+ 'nsImportScanFile.cpp',
+ 'nsImportService.cpp',
+ 'nsImportStringBundle.cpp',
+ 'nsImportTranslator.cpp',
+]
+
+FINAL_LIBRARY = 'import'
+
diff --git a/mailnews/import/src/nsImportABDescriptor.cpp b/mailnews/import/src/nsImportABDescriptor.cpp
new file mode 100644
index 000000000..05605d09e
--- /dev/null
+++ b/mailnews/import/src/nsImportABDescriptor.cpp
@@ -0,0 +1,32 @@
+/* -*- 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 "nscore.h"
+#include "nsImportABDescriptor.h"
+
+////////////////////////////////////////////////////////////////////////
+
+NS_METHOD nsImportABDescriptor::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
+{
+ if (aOuter)
+ return NS_ERROR_NO_AGGREGATION;
+
+ nsImportABDescriptor *it = new nsImportABDescriptor();
+ if (it == nullptr)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(it);
+ nsresult rv = it->QueryInterface(aIID, aResult);
+ NS_RELEASE(it);
+ return rv;
+}
+
+NS_IMPL_ISUPPORTS(nsImportABDescriptor, nsIImportABDescriptor)
+
+nsImportABDescriptor::nsImportABDescriptor()
+ : mId(0), mRef(0), mSize(0), mImport(true)
+{
+}
diff --git a/mailnews/import/src/nsImportABDescriptor.h b/mailnews/import/src/nsImportABDescriptor.h
new file mode 100644
index 000000000..a8fa6fbad
--- /dev/null
+++ b/mailnews/import/src/nsImportABDescriptor.h
@@ -0,0 +1,103 @@
+/* -*- 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/. */
+
+#ifndef nsImportABDescriptor_h___
+#define nsImportABDescriptor_h___
+
+#include "mozilla/Attributes.h"
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsIImportABDescriptor.h"
+#include "nsIFile.h"
+#include "nsCOMPtr.h"
+
+////////////////////////////////////////////////////////////////////////
+
+class nsImportABDescriptor : public nsIImportABDescriptor
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ NS_IMETHOD GetIdentifier(uint32_t *pIdentifier) override {
+ *pIdentifier = mId;
+ return NS_OK;
+ }
+ NS_IMETHOD SetIdentifier(uint32_t ident) override {
+ mId = ident;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetRef(uint32_t *pRef) override {
+ *pRef = mRef;
+ return NS_OK;
+ }
+ NS_IMETHOD SetRef(uint32_t ref) override {
+ mRef = ref;
+ return NS_OK;
+ }
+
+ /* attribute unsigned long size; */
+ NS_IMETHOD GetSize(uint32_t *pSize) override {
+ *pSize = mSize;
+ return NS_OK;
+ }
+ NS_IMETHOD SetSize(uint32_t theSize) override {
+ mSize = theSize;
+ return NS_OK;
+ }
+
+ /* attribute AString displayName; */
+ NS_IMETHOD GetPreferredName(nsAString &aName) override {
+ aName = mDisplayName;
+ return NS_OK;
+ }
+ NS_IMETHOD SetPreferredName(const nsAString &aName) override {
+ mDisplayName = aName;
+ return NS_OK;
+ }
+
+ /* readonly attribute nsIFile fileSpec; */
+ NS_IMETHOD GetAbFile(nsIFile **aFile) override {
+ if (!mFile)
+ return NS_ERROR_NULL_POINTER;
+
+ return mFile->Clone(aFile);
+ }
+
+ NS_IMETHOD SetAbFile(nsIFile *aFile) override {
+ if (!aFile) {
+ mFile = nullptr;
+ return NS_OK;
+ }
+
+ return aFile->Clone(getter_AddRefs(mFile));
+ }
+
+ /* attribute boolean import; */
+ NS_IMETHOD GetImport(bool *pImport) override {
+ *pImport = mImport;
+ return NS_OK;
+ }
+ NS_IMETHOD SetImport(bool doImport) override {
+ mImport = doImport;
+ return NS_OK;
+ }
+
+ nsImportABDescriptor();
+
+ static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
+
+private:
+ virtual ~nsImportABDescriptor() {}
+ uint32_t mId; // used by creator of the structure
+ uint32_t mRef; // depth in the hierarchy
+ nsString mDisplayName; // name of this mailbox
+ nsCOMPtr<nsIFile> mFile; // source file (if applicable)
+ uint32_t mSize; // size
+ bool mImport; // import it or not?
+};
+
+
+#endif
diff --git a/mailnews/import/src/nsImportAddressBooks.cpp b/mailnews/import/src/nsImportAddressBooks.cpp
new file mode 100644
index 000000000..8791efb42
--- /dev/null
+++ b/mailnews/import/src/nsImportAddressBooks.cpp
@@ -0,0 +1,894 @@
+/* -*- 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 "plstr.h"
+#include "nsCOMPtr.h"
+#include "nsMsgUtils.h"
+#include "nsIImportService.h"
+#include "nsIImportAddressBooks.h"
+#include "nsIImportGeneric.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIImportABDescriptor.h"
+#include "nsIImportFieldMap.h"
+#include "nsStringGlue.h"
+#include "nsIFile.h"
+#include "nsIAddrDatabase.h"
+#include "nsIAbManager.h"
+#include "nsIAbLDIFService.h"
+#include "nsAbBaseCID.h"
+#include "nsIStringBundle.h"
+#include "nsImportStringBundle.h"
+#include "nsTextFormatter.h"
+#include "nsServiceManagerUtils.h"
+#include "msgCore.h"
+#include "ImportDebug.h"
+#include "nsIAbMDBDirectory.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIArray.h"
+#include "nsCOMArray.h"
+#include "nsArrayUtils.h"
+
+static void ImportAddressThread(void *stuff);
+
+class AddressThreadData;
+
+class nsImportGenericAddressBooks : public nsIImportGeneric
+{
+public:
+
+ nsImportGenericAddressBooks();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ /* nsISupports GetData (in string dataId); */
+ NS_IMETHOD GetData(const char *dataId, nsISupports **_retval) override;
+
+ NS_IMETHOD SetData(const char *dataId, nsISupports *pData) override;
+
+ NS_IMETHOD GetStatus(const char *statusKind, int32_t *_retval) override;
+
+ NS_IMETHOD WantsProgress(bool *_retval) override;
+
+ NS_IMETHOD BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, bool *_retval) override;
+
+ NS_IMETHOD ContinueImport(bool *_retval) override;
+
+ NS_IMETHOD GetProgress(int32_t *_retval) override;
+
+ NS_IMETHOD CancelImport(void) override;
+
+private:
+ virtual ~nsImportGenericAddressBooks();
+ void GetDefaultLocation(void);
+ void GetDefaultBooks(void);
+ void GetDefaultFieldMap(void);
+
+public:
+ static void SetLogs(nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError);
+ static void ReportError(const char16_t *pName, nsString *pStream,
+ nsIStringBundle *aBundle);
+
+private:
+ nsIImportAddressBooks * m_pInterface;
+ nsCOMPtr<nsIArray> m_Books;
+ nsCOMArray<nsIAddrDatabase> m_DBs;
+ nsCOMPtr <nsIFile> m_pLocation;
+ nsIImportFieldMap * m_pFieldMap;
+ bool m_autoFind;
+ char16_t * m_description;
+ bool m_gotLocation;
+ bool m_found;
+ bool m_userVerify;
+ nsISupportsString * m_pSuccessLog;
+ nsISupportsString * m_pErrorLog;
+ uint32_t m_totalSize;
+ bool m_doImport;
+ AddressThreadData * m_pThreadData;
+ char * m_pDestinationUri;
+ nsCOMPtr<nsIStringBundle> m_stringBundle;
+};
+
+class AddressThreadData {
+public:
+ bool driverAlive;
+ bool threadAlive;
+ bool abort;
+ bool fatalError;
+ uint32_t currentTotal;
+ uint32_t currentSize;
+ nsIArray *books;
+ nsCOMArray<nsIAddrDatabase>* dBs;
+ nsCOMPtr<nsIAbLDIFService> ldifService;
+ nsIImportAddressBooks * addressImport;
+ nsIImportFieldMap * fieldMap;
+ nsISupportsString * successLog;
+ nsISupportsString * errorLog;
+ char * pDestinationUri;
+ nsIStringBundle* stringBundle;
+
+ AddressThreadData();
+ ~AddressThreadData();
+};
+
+
+nsresult NS_NewGenericAddressBooks(nsIImportGeneric** aImportGeneric)
+{
+ NS_PRECONDITION(aImportGeneric != nullptr, "null ptr");
+ if (! aImportGeneric)
+ return NS_ERROR_NULL_POINTER;
+
+ nsImportGenericAddressBooks *pGen = new nsImportGenericAddressBooks();
+
+ if (pGen == nullptr)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(pGen);
+ nsresult rv = pGen->QueryInterface(NS_GET_IID(nsIImportGeneric), (void **)aImportGeneric);
+ NS_RELEASE(pGen);
+
+ return rv;
+}
+
+nsImportGenericAddressBooks::nsImportGenericAddressBooks()
+{
+ m_pInterface = nullptr;
+ m_pSuccessLog = nullptr;
+ m_pErrorLog = nullptr;
+ m_totalSize = 0;
+ m_doImport = false;
+ m_pThreadData = nullptr;
+ m_pDestinationUri = nullptr;
+ m_pFieldMap = nullptr;
+
+ m_autoFind = false;
+ m_description = nullptr;
+ m_gotLocation = false;
+ m_found = false;
+ m_userVerify = false;
+
+ nsImportStringBundle::GetStringBundle(IMPORT_MSGS_URL, getter_AddRefs(m_stringBundle));
+}
+
+
+nsImportGenericAddressBooks::~nsImportGenericAddressBooks()
+{
+ if (m_pDestinationUri)
+ NS_Free(m_pDestinationUri);
+
+ if (m_description)
+ NS_Free(m_description);
+
+ NS_IF_RELEASE(m_pFieldMap);
+ NS_IF_RELEASE(m_pInterface);
+ NS_IF_RELEASE(m_pSuccessLog);
+ NS_IF_RELEASE(m_pErrorLog);
+}
+
+
+
+NS_IMPL_ISUPPORTS(nsImportGenericAddressBooks, nsIImportGeneric)
+
+
+NS_IMETHODIMP nsImportGenericAddressBooks::GetData(const char *dataId, nsISupports **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ nsresult rv;
+ *_retval = nullptr;
+ if (!PL_strcasecmp(dataId, "addressInterface")) {
+ *_retval = m_pInterface;
+ NS_IF_ADDREF(m_pInterface);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressLocation")) {
+ if (!m_pLocation)
+ GetDefaultLocation();
+ NS_IF_ADDREF(*_retval = m_pLocation);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressBooks")) {
+ if (!m_pLocation)
+ GetDefaultLocation();
+ if (!m_Books)
+ GetDefaultBooks();
+ *_retval = m_Books;
+ }
+
+ if (!PL_strcasecmp(dataId, "addressDestination")) {
+ if (m_pDestinationUri) {
+ nsCOMPtr<nsISupportsCString> abString = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ abString->SetData(nsDependentCString(m_pDestinationUri));
+ NS_IF_ADDREF(*_retval = abString);
+ }
+ }
+
+ if (!PL_strcasecmp(dataId, "fieldMap")) {
+ if (m_pFieldMap) {
+ *_retval = m_pFieldMap;
+ m_pFieldMap->AddRef();
+ }
+ else {
+ if (m_pInterface && m_pLocation) {
+ bool needsIt = false;
+ m_pInterface->GetNeedsFieldMap(m_pLocation, &needsIt);
+ if (needsIt) {
+ GetDefaultFieldMap();
+ if (m_pFieldMap) {
+ *_retval = m_pFieldMap;
+ m_pFieldMap->AddRef();
+ }
+ }
+ }
+ }
+ }
+
+ if (!PL_strncasecmp(dataId, "sampleData-", 11)) {
+ // extra the record number
+ const char *pNum = dataId + 11;
+ int32_t rNum = 0;
+ while (*pNum) {
+ rNum *= 10;
+ rNum += (*pNum - '0');
+ pNum++;
+ }
+ IMPORT_LOG1("Requesting sample data #: %ld\n", (long)rNum);
+ if (m_pInterface) {
+ nsCOMPtr<nsISupportsString> data = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+ char16_t * pData = nullptr;
+ bool found = false;
+ rv = m_pInterface->GetSampleData(rNum, &found, &pData);
+ if (NS_FAILED(rv))
+ return rv;
+ if (found) {
+ data->SetData(nsDependentString(pData));
+ *_retval = data;
+ NS_ADDREF(*_retval);
+ }
+ NS_Free(pData);
+ }
+ }
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImportGenericAddressBooks::SetData(const char *dataId, nsISupports *item)
+{
+ NS_PRECONDITION(dataId != nullptr, "null ptr");
+ if (!dataId)
+ return NS_ERROR_NULL_POINTER;
+
+ if (!PL_strcasecmp(dataId, "addressInterface")) {
+ NS_IF_RELEASE(m_pInterface);
+ if (item)
+ item->QueryInterface(NS_GET_IID(nsIImportAddressBooks), (void **) &m_pInterface);
+ }
+ if (!PL_strcasecmp(dataId, "addressBooks")) {
+ if (item)
+ item->QueryInterface(NS_GET_IID(nsIArray), (void **) &m_Books);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressLocation")) {
+ m_pLocation = nullptr;
+
+ if (item) {
+ nsresult rv;
+ m_pLocation = do_QueryInterface(item, &rv);
+ NS_ENSURE_SUCCESS(rv,rv);
+ }
+
+ if (m_pInterface)
+ m_pInterface->SetSampleLocation(m_pLocation);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressDestination")) {
+ if (item) {
+ nsCOMPtr<nsISupportsCString> abString;
+ item->QueryInterface(NS_GET_IID(nsISupportsCString), getter_AddRefs(abString));
+ if (abString) {
+ if (m_pDestinationUri)
+ NS_Free(m_pDestinationUri);
+ m_pDestinationUri = nullptr;
+ nsAutoCString tempUri;
+ abString->GetData(tempUri);
+ m_pDestinationUri = ToNewCString(tempUri);
+ }
+ }
+ }
+
+ if (!PL_strcasecmp(dataId, "fieldMap")) {
+ NS_IF_RELEASE(m_pFieldMap);
+ if (item)
+ item->QueryInterface(NS_GET_IID(nsIImportFieldMap), (void **) &m_pFieldMap);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::GetStatus(const char *statusKind, int32_t *_retval)
+{
+ NS_PRECONDITION(statusKind != nullptr, "null ptr");
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!statusKind || !_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = 0;
+
+ if (!PL_strcasecmp(statusKind, "isInstalled")) {
+ GetDefaultLocation();
+ *_retval = (int32_t) m_found;
+ }
+
+ if (!PL_strcasecmp(statusKind, "canUserSetLocation")) {
+ GetDefaultLocation();
+ *_retval = (int32_t) m_userVerify;
+ }
+
+ if (!PL_strcasecmp(statusKind, "autoFind")) {
+ GetDefaultLocation();
+ *_retval = (int32_t) m_autoFind;
+ }
+
+ if (!PL_strcasecmp(statusKind, "supportsMultiple")) {
+ bool multi = false;
+ if (m_pInterface)
+ m_pInterface->GetSupportsMultiple(&multi);
+ *_retval = (int32_t) multi;
+ }
+
+ if (!PL_strcasecmp(statusKind, "needsFieldMap")) {
+ bool needs = false;
+ if (m_pInterface && m_pLocation)
+ m_pInterface->GetNeedsFieldMap(m_pLocation, &needs);
+ *_retval = (int32_t) needs;
+ }
+
+ return NS_OK;
+}
+
+void nsImportGenericAddressBooks::GetDefaultLocation(void)
+{
+ if (!m_pInterface)
+ return;
+
+ if ((m_pLocation && m_gotLocation) || m_autoFind)
+ return;
+
+ if (m_description)
+ NS_Free(m_description);
+ m_description = nullptr;
+ m_pInterface->GetAutoFind(&m_description, &m_autoFind);
+ m_gotLocation = true;
+ if (m_autoFind) {
+ m_found = true;
+ m_userVerify = false;
+ return;
+ }
+
+ nsCOMPtr <nsIFile> pLoc;
+ m_pInterface->GetDefaultLocation(getter_AddRefs(pLoc), &m_found, &m_userVerify);
+ if (!m_pLocation)
+ m_pLocation = pLoc;
+}
+
+void nsImportGenericAddressBooks::GetDefaultBooks(void)
+{
+ if (!m_pInterface || m_Books)
+ return;
+
+ if (!m_pLocation && !m_autoFind)
+ return;
+
+ nsresult rv = m_pInterface->FindAddressBooks(m_pLocation, getter_AddRefs(m_Books));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error: FindAddressBooks failed\n");
+ }
+}
+
+void nsImportGenericAddressBooks::GetDefaultFieldMap(void)
+{
+ if (!m_pInterface || !m_pLocation)
+ return;
+
+ NS_IF_RELEASE(m_pFieldMap);
+
+ nsresult rv;
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Unable to get nsIImportService.\n");
+ return;
+ }
+
+ rv = impSvc->CreateNewFieldMap(&m_pFieldMap);
+ if (NS_FAILED(rv))
+ return;
+
+ int32_t sz = 0;
+ rv = m_pFieldMap->GetNumMozFields(&sz);
+ if (NS_SUCCEEDED(rv))
+ rv = m_pFieldMap->DefaultFieldMap(sz);
+ if (NS_SUCCEEDED(rv))
+ rv = m_pInterface->InitFieldMap(m_pFieldMap);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error: Unable to initialize field map\n");
+ NS_IF_RELEASE(m_pFieldMap);
+ }
+}
+
+
+NS_IMETHODIMP nsImportGenericAddressBooks::WantsProgress(bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ NS_ENSURE_ARG_POINTER(_retval);
+
+ GetDefaultLocation();
+ GetDefaultBooks();
+
+ bool result = false;
+
+ if (m_Books) {
+ uint32_t count = 0;
+ uint32_t i;
+ bool import;
+ uint32_t size;
+ uint32_t totalSize = 0;
+
+ m_Books->GetLength(&count);
+
+ for (i = 0; i < count; i++) {
+ nsCOMPtr<nsIImportABDescriptor> book = do_QueryElementAt(m_Books, i);
+ if (book) {
+ import = false;
+ size = 0;
+ nsresult rv = book->GetImport(&import);
+ if (NS_SUCCEEDED(rv) && import) {
+ (void) book->GetSize(&size);
+ result = true;
+ }
+ totalSize += size;
+ }
+ }
+
+ m_totalSize = totalSize;
+ }
+
+ m_doImport = result;
+
+ *_retval = result;
+
+ return NS_OK;
+}
+
+void nsImportGenericAddressBooks::SetLogs(nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError)
+{
+ nsAutoString str;
+ if (pSuccess) {
+ pSuccess->GetData(str);
+ str.Append(success);
+ pSuccess->SetData(success);
+ }
+ if (pError) {
+ pError->GetData(str);
+ str.Append(error);
+ pError->SetData(error);
+ }
+}
+
+already_AddRefed<nsIAddrDatabase> GetAddressBookFromUri(const char *pUri)
+{
+ if (!pUri)
+ return nullptr;
+
+ nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID);
+ if (!abManager)
+ return nullptr;
+
+ nsCOMPtr<nsIAbDirectory> directory;
+ abManager->GetDirectory(nsDependentCString(pUri),
+ getter_AddRefs(directory));
+ if (!directory)
+ return nullptr;
+
+ nsCOMPtr<nsIAbMDBDirectory> mdbDirectory = do_QueryInterface(directory);
+ if (!mdbDirectory)
+ return nullptr;
+
+ nsCOMPtr<nsIAddrDatabase> pDatabase;
+ mdbDirectory->GetDatabase(getter_AddRefs(pDatabase));
+ return pDatabase.forget();
+}
+
+already_AddRefed<nsIAddrDatabase> GetAddressBook(const char16_t *name,
+ bool makeNew)
+{
+ if (!makeNew) {
+ // FIXME: How do I get the list of address books and look for a
+ // specific name. Major bogosity!
+ // For now, assume we didn't find anything with that name
+ }
+
+ IMPORT_LOG0("In GetAddressBook\n");
+
+ nsresult rv;
+ nsCOMPtr<nsIAddrDatabase> pDatabase;
+ nsCOMPtr<nsIFile> dbPath;
+ nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ /* Get the profile directory */
+ rv = abManager->GetUserProfileDirectory(getter_AddRefs(dbPath));
+ if (NS_SUCCEEDED(rv))
+ {
+ // Create a new address book file - we don't care what the file
+ // name is, as long as it's unique
+ rv = dbPath->Append(NS_LITERAL_STRING("impab.mab"));
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = dbPath->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
+
+ if (NS_SUCCEEDED(rv))
+ {
+ IMPORT_LOG0("Getting the address database factory\n");
+
+ nsCOMPtr<nsIAddrDatabase> addrDBFactory =
+ do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return nullptr;
+
+ IMPORT_LOG0("Opening the new address book\n");
+ rv = addrDBFactory->Open(dbPath, true, true,
+ getter_AddRefs(pDatabase));
+ }
+ }
+ }
+ }
+ if (NS_FAILED(rv))
+ {
+ IMPORT_LOG0("Failed to get the user profile directory from the address book session\n");
+ }
+
+ if (pDatabase && dbPath)
+ {
+ // We made a database, add it to the UI?!?!?!?!?!?!
+ // This is major bogosity again! Why doesn't the address book
+ // just handle this properly for me? Uggggg...
+
+ nsCOMPtr<nsIAbDirectory> parentDir;
+ abManager->GetDirectory(NS_LITERAL_CSTRING(kAllDirectoryRoot),
+ getter_AddRefs(parentDir));
+ if (parentDir)
+ {
+ nsAutoCString URI("moz-abmdbdirectory://");
+ nsAutoCString leafName;
+ rv = dbPath->GetNativeLeafName(leafName);
+ if (NS_FAILED(rv))
+ IMPORT_LOG0("*** Error: Unable to get name of database file\n");
+ else
+ {
+ URI.Append(leafName);
+ rv = parentDir->CreateDirectoryByURI(nsDependentString(name), URI);
+ if (NS_FAILED(rv))
+ IMPORT_LOG0("*** Error: Unable to create address book directory\n");
+ }
+ }
+
+ if (NS_SUCCEEDED(rv))
+ IMPORT_LOG0("Added new address book to the UI\n");
+ else
+ IMPORT_LOG0("*** Error: An error occurred while adding the address book to the UI\n");
+ }
+
+ return pDatabase.forget();
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ nsString success;
+ nsString error;
+
+ if (!m_doImport) {
+ *_retval = true;
+ nsImportStringBundle::GetStringByID(IMPORT_NO_ADDRBOOKS, m_stringBundle,
+ success);
+ SetLogs(success, error, successLog, errorLog);
+ return NS_OK;
+ }
+
+ if (!m_pInterface || !m_Books) {
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_AB_NOTINITIALIZED,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = false;
+ return NS_OK;
+ }
+
+ bool needsFieldMap = false;
+
+ if (NS_FAILED(m_pInterface->GetNeedsFieldMap(m_pLocation, &needsFieldMap)) ||
+ (needsFieldMap && !m_pFieldMap)) {
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_AB_NOTINITIALIZED,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = false;
+ return NS_OK;
+ }
+
+ NS_IF_RELEASE(m_pSuccessLog);
+ NS_IF_RELEASE(m_pErrorLog);
+ m_pSuccessLog = successLog;
+ m_pErrorLog = errorLog;
+ NS_IF_ADDREF(m_pSuccessLog);
+ NS_IF_ADDREF(m_pErrorLog);
+
+
+ // create the info need to drive address book import. We're
+ // not going to create a new thread for this since address books
+ // don't tend to be large, and import is rare.
+ m_pThreadData = new AddressThreadData();
+ m_pThreadData->books = m_Books;
+ NS_ADDREF(m_Books);
+ m_pThreadData->addressImport = m_pInterface;
+ NS_ADDREF(m_pInterface);
+ m_pThreadData->fieldMap = m_pFieldMap;
+ NS_IF_ADDREF(m_pFieldMap);
+ m_pThreadData->errorLog = m_pErrorLog;
+ NS_IF_ADDREF(m_pErrorLog);
+ m_pThreadData->successLog = m_pSuccessLog;
+ NS_IF_ADDREF(m_pSuccessLog);
+ if (m_pDestinationUri)
+ m_pThreadData->pDestinationUri = strdup(m_pDestinationUri);
+
+ uint32_t count = 0;
+ m_Books->GetLength(&count);
+ // Create/obtain any address books that we need here, so that we don't need
+ // to do so inside the import thread which would just proxy the create
+ // operations back to the main thread anyway.
+ nsCOMPtr<nsIAddrDatabase> db = GetAddressBookFromUri(m_pDestinationUri);
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ nsCOMPtr<nsIImportABDescriptor> book = do_QueryElementAt(m_Books, i);
+ if (book)
+ {
+ if (!db)
+ {
+ nsString name;
+ book->GetPreferredName(name);
+ db = GetAddressBook(name.get(), true);
+ }
+ m_DBs.AppendObject(db);
+ }
+ }
+ m_pThreadData->dBs = &m_DBs;
+
+ NS_IF_ADDREF(m_pThreadData->stringBundle = m_stringBundle);
+
+ nsresult rv;
+ m_pThreadData->ldifService = do_GetService(NS_ABLDIFSERVICE_CONTRACTID, &rv);
+
+ ImportAddressThread(m_pThreadData);
+ delete m_pThreadData;
+ m_pThreadData = nullptr;
+ *_retval = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::ContinueImport(bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = true;
+ if (m_pThreadData) {
+ if (m_pThreadData->fatalError)
+ *_retval = false;
+ }
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImportGenericAddressBooks::GetProgress(int32_t *_retval)
+{
+ // This returns the progress from the the currently
+ // running import mail or import address book thread.
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ if (!m_pThreadData || !(m_pThreadData->threadAlive)) {
+ *_retval = 100;
+ return NS_OK;
+ }
+
+ uint32_t sz = 0;
+ if (m_pThreadData->currentSize && m_pInterface) {
+ if (NS_FAILED(m_pInterface->GetImportProgress(&sz)))
+ sz = 0;
+ }
+
+ if (m_totalSize)
+ *_retval = ((m_pThreadData->currentTotal + sz) * 100) / m_totalSize;
+ else
+ *_retval = 0;
+
+ // never return less than 5 so it looks like we are doing something!
+ if (*_retval < 5)
+ *_retval = 5;
+
+ // as long as the thread is alive don't return completely
+ // done.
+ if (*_retval > 99)
+ *_retval = 99;
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImportGenericAddressBooks::CancelImport(void)
+{
+ if (m_pThreadData) {
+ m_pThreadData->abort = true;
+ m_pThreadData = nullptr;
+ }
+
+ return NS_OK;
+}
+
+
+AddressThreadData::AddressThreadData()
+{
+ fatalError = false;
+ driverAlive = true;
+ threadAlive = true;
+ abort = false;
+ currentTotal = 0;
+ currentSize = 0;
+ books = nullptr;
+ addressImport = nullptr;
+ successLog = nullptr;
+ errorLog = nullptr;
+ pDestinationUri = nullptr;
+ fieldMap = nullptr;
+ stringBundle = nullptr;
+ ldifService = nullptr;
+}
+
+AddressThreadData::~AddressThreadData()
+{
+ if (pDestinationUri)
+ NS_Free(pDestinationUri);
+
+ NS_IF_RELEASE(books);
+ NS_IF_RELEASE(addressImport);
+ NS_IF_RELEASE(errorLog);
+ NS_IF_RELEASE(successLog);
+ NS_IF_RELEASE(fieldMap);
+ NS_IF_RELEASE(stringBundle);
+}
+
+void nsImportGenericAddressBooks::ReportError(const char16_t *pName,
+ nsString *pStream,
+ nsIStringBundle* aBundle)
+{
+ if (!pStream)
+ return;
+ // load the error string
+ char16_t *pFmt = nsImportStringBundle::GetStringByID(IMPORT_ERROR_GETABOOK, aBundle);
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, pName);
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ NS_Free(pFmt);
+ pStream->AppendLiteral(MSG_LINEBREAK);
+}
+
+static void ImportAddressThread(void *stuff)
+{
+ IMPORT_LOG0("In Begin ImportAddressThread\n");
+
+ AddressThreadData *pData = (AddressThreadData *)stuff;
+ uint32_t count = 0;
+ uint32_t i;
+ bool import;
+ uint32_t size;
+
+ nsString success;
+ nsString error;
+
+ (void) pData->books->GetLength(&count);
+
+ for (i = 0; (i < count) && !(pData->abort); i++) {
+ nsCOMPtr<nsIImportABDescriptor> book =
+ do_QueryElementAt(pData->books, i);
+
+ if (book) {
+ import = false;
+ size = 0;
+ nsresult rv = book->GetImport(&import);
+ if (NS_SUCCEEDED(rv) && import)
+ rv = book->GetSize(&size);
+
+ if (NS_SUCCEEDED(rv) && size && import) {
+ nsString name;
+ book->GetPreferredName(name);
+
+ nsCOMPtr<nsIAddrDatabase> db = pData->dBs->ObjectAt(i);
+
+ bool fatalError = false;
+ pData->currentSize = size;
+ if (db) {
+ char16_t *pSuccess = nullptr;
+ char16_t *pError = nullptr;
+
+ /*
+ if (pData->fieldMap) {
+ int32_t sz = 0;
+ int32_t mapIndex;
+ bool active;
+ pData->fieldMap->GetMapSize(&sz);
+ IMPORT_LOG1("**** Field Map Size: %d\n", (int) sz);
+ for (int32_t i = 0; i < sz; i++) {
+ pData->fieldMap->GetFieldMap(i, &mapIndex);
+ pData->fieldMap->GetFieldActive(i, &active);
+ IMPORT_LOG3("Field map #%d: index=%d, active=%d\n", (int) i, (int) mapIndex, (int) active);
+ }
+ }
+ */
+
+ rv = pData->addressImport->ImportAddressBook(book,
+ db,
+ pData->fieldMap,
+ pData->ldifService,
+ &pError,
+ &pSuccess,
+ &fatalError);
+ if (NS_SUCCEEDED(rv) && pSuccess) {
+ success.Append(pSuccess);
+ NS_Free(pSuccess);
+ }
+ if (pError) {
+ error.Append(pError);
+ NS_Free(pError);
+ }
+ }
+ else {
+ nsImportGenericAddressBooks::ReportError(name.get(), &error, pData->stringBundle);
+ }
+
+ pData->currentSize = 0;
+ pData->currentTotal += size;
+
+ if (db)
+ db->Close(true);
+
+ if (fatalError) {
+ pData->fatalError = true;
+ break;
+ }
+ }
+ }
+ }
+
+
+ nsImportGenericAddressBooks::SetLogs(success, error, pData->successLog, pData->errorLog);
+
+ if (pData->abort || pData->fatalError) {
+ // FIXME: do what is necessary to get rid of what has been imported so far.
+ // Nothing if we went into an existing address book! Otherwise, delete
+ // the ones we created?
+ }
+
+}
diff --git a/mailnews/import/src/nsImportEmbeddedImageData.cpp b/mailnews/import/src/nsImportEmbeddedImageData.cpp
new file mode 100644
index 000000000..526f9c21c
--- /dev/null
+++ b/mailnews/import/src/nsImportEmbeddedImageData.cpp
@@ -0,0 +1,64 @@
+/* -*- 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 "nsImportEmbeddedImageData.h"
+
+NS_IMPL_ISUPPORTS(nsImportEmbeddedImageData, nsIMsgEmbeddedImageData)
+
+nsImportEmbeddedImageData::nsImportEmbeddedImageData()
+{
+}
+
+nsImportEmbeddedImageData::nsImportEmbeddedImageData(
+ nsIURI *aUri, const nsACString &aCid) : m_uri(aUri), m_cid(aCid)
+{
+}
+
+nsImportEmbeddedImageData::nsImportEmbeddedImageData(
+ nsIURI *aUri, const nsACString &aCid, const nsACString &aName)
+ : m_uri(aUri), m_cid(aCid), m_name(aName)
+{
+}
+
+nsImportEmbeddedImageData::~nsImportEmbeddedImageData()
+{
+}
+
+NS_IMETHODIMP nsImportEmbeddedImageData::GetUri(nsIURI **aUri)
+{
+ NS_ENSURE_ARG_POINTER(aUri);
+ NS_IF_ADDREF(*aUri = m_uri);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportEmbeddedImageData::SetUri(nsIURI *aUri)
+{
+ m_uri = aUri;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportEmbeddedImageData::GetCid(nsACString &aCid)
+{
+ aCid = m_cid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportEmbeddedImageData::SetCid(const nsACString &aCid)
+{
+ m_cid = aCid;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportEmbeddedImageData::GetName(nsACString &aName)
+{
+ aName = m_name;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportEmbeddedImageData::SetName(const nsACString &aName)
+{
+ m_name = aName;
+ return NS_OK;
+}
diff --git a/mailnews/import/src/nsImportEmbeddedImageData.h b/mailnews/import/src/nsImportEmbeddedImageData.h
new file mode 100644
index 000000000..5635dc512
--- /dev/null
+++ b/mailnews/import/src/nsImportEmbeddedImageData.h
@@ -0,0 +1,32 @@
+/* -*- 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/. */
+
+#ifndef __IMPORTEMBEDDEDIMAGETDATA_H__
+#define __IMPORTEMBEDDEDIMAGETDATA_H__
+
+#include "nsIMsgSend.h"
+#include "nsStringGlue.h"
+#include "nsCOMPtr.h"
+#include "nsIURI.h"
+
+class nsImportEmbeddedImageData final : public nsIMsgEmbeddedImageData
+{
+public:
+ nsImportEmbeddedImageData(nsIURI *aUri, const nsACString &aCID);
+ nsImportEmbeddedImageData(nsIURI *aUri, const nsACString &aCID, const nsACString &aName);
+ nsImportEmbeddedImageData();
+ NS_DECL_NSIMSGEMBEDDEDIMAGEDATA
+ NS_DECL_ISUPPORTS
+
+ nsCOMPtr<nsIURI> m_uri;
+ nsCString m_cid;
+ nsCString m_name;
+
+private:
+ ~nsImportEmbeddedImageData();
+};
+
+
+#endif
diff --git a/mailnews/import/src/nsImportEncodeScan.cpp b/mailnews/import/src/nsImportEncodeScan.cpp
new file mode 100644
index 000000000..77e89198d
--- /dev/null
+++ b/mailnews/import/src/nsImportEncodeScan.cpp
@@ -0,0 +1,374 @@
+/* -*- 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/. */
+
+#include "nscore.h"
+#include "nsImportEncodeScan.h"
+#include "nsNetUtil.h"
+
+#define kBeginAppleSingle 0
+#define kBeginDataFork 1
+#define kBeginResourceFork 2
+#define kAddEntries 3
+#define kScanningDataFork 4
+#define kScanningRsrcFork 5
+#define kDoneWithFile 6
+
+uint32_t gAppleSingleHeader[6] = {0x00051600, 0x00020000, 0, 0, 0, 0};
+#define kAppleSingleHeaderSize (6 * sizeof(uint32_t))
+
+#ifdef _MAC_IMPORT_CODE
+#include "MoreFilesExtras.h"
+#include "MoreDesktopMgr.h"
+
+CInfoPBRec gCatInfoPB;
+U32 g2000Secs = 0;
+long gGMTDelta = 0;
+
+long GetGmtDelta(void);
+U32 Get2000Secs(void);
+
+
+long GetGmtDelta(void)
+{
+ MachineLocation myLocation;
+ ReadLocation(&myLocation);
+ long myDelta = BitAnd(myLocation.u.gmtDelta, 0x00FFFFFF);
+ if (BitTst(&myDelta, 23))
+ myDelta = BitOr(myDelta, 0xFF000000);
+ return myDelta;
+}
+
+U32 Get2000Secs(void)
+{
+ DateTimeRec dr;
+ dr.year = 2000;
+ dr.month = 1;
+ dr.day = 1;
+ dr.hour = 0;
+ dr.minute = 0;
+ dr.second = 0;
+ dr.dayOfWeek = 0;
+ U32 result;
+ DateToSeconds(&dr, &result);
+ return result;
+}
+#endif
+
+nsImportEncodeScan::nsImportEncodeScan()
+{
+ m_isAppleSingle = false;
+ m_encodeScanState = 0;
+ m_resourceForkSize = 0;
+ m_dataForkSize = 0;
+}
+
+nsImportEncodeScan::~nsImportEncodeScan()
+{
+}
+
+bool nsImportEncodeScan::InitEncodeScan(bool appleSingleEncode, nsIFile *fileLoc, const char *pName, uint8_t * pBuf, uint32_t sz)
+{
+ CleanUpEncodeScan();
+ m_isAppleSingle = appleSingleEncode;
+ m_encodeScanState = kBeginAppleSingle;
+ m_pInputFile = do_QueryInterface(fileLoc);
+ m_useFileName = pName;
+ m_pBuf = pBuf;
+ m_bufSz = sz;
+ if (!m_isAppleSingle)
+ {
+ if (!m_inputStream)
+ {
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(m_inputStream), m_pInputFile);
+ NS_ENSURE_SUCCESS(rv, false);
+ }
+
+ InitScan(m_inputStream, pBuf, sz);
+ }
+ else {
+ #ifdef _MAC_IMPORT_CODE
+ // Fill in the file sizes
+ m_resourceForkSize = fileLoc.GetMacFileSize(UFileLocation::eResourceFork);
+ m_dataForkSize = fileLoc.GetMacFileSize(UFileLocation::eDataFork);
+ #endif
+ }
+
+ return true;
+}
+
+void nsImportEncodeScan::CleanUpEncodeScan(void)
+{
+ m_pInputStream->Close();
+ m_pInputStream = nullptr;
+ m_pInputFile = nullptr;
+}
+
+
+// 26 + 12 per entry
+
+void nsImportEncodeScan::FillInEntries(int numEntries)
+{
+#ifdef _MAC_IMPORT_CODE
+ int len = m_useFileName.GetLength();
+ if (len < 32)
+ len = 32;
+ long entry[3];
+ long fileOffset = 26 + (12 * numEntries);
+ entry[0] = 3;
+ entry[1] = fileOffset;
+ entry[2] = m_useFileName.GetLength();
+ fileOffset += len;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+
+
+ Str255 comment;
+ comment[0] = 0;
+ OSErr err = FSpDTGetComment(m_inputFileLoc, comment);
+ if (comment[0] > 200)
+ comment[0] = 200;
+ entry[0] = 4;
+ entry[1] = fileOffset;
+ entry[2] = comment[0];
+ fileOffset += 200;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+
+
+ entry[0] = 8;
+ entry[1] = fileOffset;
+ entry[2] = 16;
+ fileOffset += 16;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+
+ entry[0] = 9;
+ entry[1] = fileOffset;
+ entry[2] = 32;
+ fileOffset += 32;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+
+
+ entry[0] = 10;
+ entry[1] = fileOffset;
+ entry[2] = 4;
+ fileOffset += 4;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+
+ if (m_resourceForkSize) {
+ entry[0] = 2;
+ entry[1] = fileOffset;
+ entry[2] = m_resourceForkSize;
+ fileOffset += m_resourceForkSize;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+ }
+
+ if (m_dataForkSize) {
+ entry[0] = 1;
+ entry[1] = fileOffset;
+ entry[2] = m_dataForkSize;
+ fileOffset += m_dataForkSize;
+ MemCpy(m_pBuf + m_bytesInBuf, entry, 12);
+ m_bytesInBuf += 12;
+ }
+
+#endif
+}
+
+bool nsImportEncodeScan::AddEntries(void)
+{
+#ifdef _MAC_IMPORT_CODE
+ if (!g2000Secs) {
+ g2000Secs = Get2000Secs();
+ gGMTDelta = GetGmtDelta();
+ }
+ MemCpy(m_pBuf + m_bytesInBuf, (PC_S8) m_useFileName, m_useFileName.GetLength());
+ m_bytesInBuf += m_useFileName.GetLength();
+ if (m_useFileName.GetLength() < 32) {
+ int len = m_useFileName.GetLength();
+ while (len < 32) {
+ *((P_S8)m_pBuf + m_bytesInBuf) = 0;
+ m_bytesInBuf++;
+ len++;
+ }
+ }
+
+ Str255 comment;
+ comment[0] = 0;
+ OSErr err = FSpDTGetComment(m_inputFileLoc, comment);
+ comment[0] = 200;
+ MemCpy(m_pBuf + m_bytesInBuf, &(comment[1]), comment[0]);
+ m_bytesInBuf += comment[0];
+
+ long dates[4];
+ dates[0] = gCatInfoPB.hFileInfo.ioFlCrDat;
+ dates[1] = gCatInfoPB.hFileInfo.ioFlMdDat;
+ dates[2] = gCatInfoPB.hFileInfo.ioFlBkDat;
+ dates[3] = 0x80000000;
+ for (short i = 0; i < 3; i++) {
+ dates[i] -= g2000Secs;
+ dates[i] += gGMTDelta;
+ }
+ MemCpy(m_pBuf + m_bytesInBuf, dates, 16);
+ m_bytesInBuf += 16;
+
+
+ FInfo fInfo = gCatInfoPB.hFileInfo.ioFlFndrInfo;
+ FXInfo fxInfo = gCatInfoPB.hFileInfo.ioFlXFndrInfo;
+ fInfo.fdFlags = 0;
+ fInfo.fdLocation.h = 0;
+ fInfo.fdLocation.v = 0;
+ fInfo.fdFldr = 0;
+ MemSet(&fxInfo, 0, sizeof(fxInfo));
+ MemCpy(m_pBuf + m_bytesInBuf, &fInfo, 16);
+ m_bytesInBuf += 16;
+ MemCpy(m_pBuf + m_bytesInBuf, &fxInfo, 16);
+ m_bytesInBuf += 16;
+
+
+ dates[0] = 0;
+ if ((gCatInfoPB.hFileInfo.ioFlAttrib & 1) != 0)
+ dates[0] |= 1;
+ MemCpy(m_pBuf + m_bytesInBuf, dates, 4);
+ m_bytesInBuf += 4;
+
+
+#endif
+ return true;
+}
+
+bool nsImportEncodeScan::Scan(bool *pDone)
+{
+ nsresult rv;
+
+ *pDone = false;
+ if (m_isAppleSingle) {
+ // Stuff the buffer with things needed to encode the file...
+ // then just allow UScanFile to handle each fork, but be careful
+ // when handling eof.
+ switch(m_encodeScanState) {
+ case kBeginAppleSingle: {
+#ifdef _MAC_IMPORT_CODE
+ OSErr err = GetCatInfoNoName(m_inputFileLoc.GetVRefNum(), m_inputFileLoc.GetParID(), m_inputFileLoc.GetFileNamePtr(), &gCatInfoPB);
+ if (err != noErr)
+ return FALSE;
+#endif
+ m_eof = false;
+ m_pos = 0;
+ memcpy(m_pBuf, gAppleSingleHeader, kAppleSingleHeaderSize);
+ m_bytesInBuf = kAppleSingleHeaderSize;
+ int numEntries = 5;
+ if (m_dataForkSize)
+ numEntries++;
+ if (m_resourceForkSize)
+ numEntries++;
+ memcpy(m_pBuf + m_bytesInBuf, &numEntries, sizeof(numEntries));
+ m_bytesInBuf += sizeof(numEntries);
+ FillInEntries(numEntries);
+ m_encodeScanState = kAddEntries;
+ return ScanBuffer(pDone);
+ }
+ break;
+
+ case kBeginDataFork: {
+ if (!m_dataForkSize) {
+ m_encodeScanState = kDoneWithFile;
+ return true;
+ }
+ // Initialize the scan of the data fork...
+ if (!m_inputStream)
+ {
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(m_inputStream), m_pInputFile);
+ NS_ENSURE_SUCCESS(rv, false);
+ }
+ m_encodeScanState = kScanningDataFork;
+ return true;
+ }
+ break;
+
+ case kScanningDataFork: {
+ bool result = FillBufferFromFile();
+ if (!result)
+ return false;
+ if (m_eof) {
+ m_eof = false;
+ result = ScanBuffer(pDone);
+ if (!result)
+ return false;
+ m_inputStream->Close();
+ m_inputStream = nullptr;
+ m_encodeScanState = kDoneWithFile;
+ return true;
+ }
+ else
+ return ScanBuffer(pDone);
+ }
+ break;
+
+ case kScanningRsrcFork: {
+ bool result = FillBufferFromFile();
+ if (!result)
+ return false;
+ if (m_eof) {
+ m_eof = false;
+ result = ScanBuffer(pDone);
+ if (!result)
+ return false;
+ m_inputStream->Close();
+ m_inputStream = nullptr;
+ m_encodeScanState = kBeginDataFork;
+ return true;
+ }
+ else
+ return ScanBuffer(pDone);
+ }
+ break;
+
+ case kBeginResourceFork: {
+ if (!m_resourceForkSize) {
+ m_encodeScanState = kBeginDataFork;
+ return true;
+ }
+ /*
+ // FIXME: Open the resource fork on the Mac!!!
+ m_fH = UFile::OpenRsrcFileRead(m_inputFileLoc);
+ if (m_fH == TR_FILE_ERROR)
+ return FALSE;
+ */
+ m_encodeScanState = kScanningRsrcFork;
+ return true;
+ }
+ break;
+
+ case kAddEntries: {
+ ShiftBuffer();
+ if (!AddEntries())
+ return false;
+ m_encodeScanState = kBeginResourceFork;
+ return ScanBuffer(pDone);
+ }
+ break;
+
+ case kDoneWithFile: {
+ ShiftBuffer();
+ m_eof = true;
+ if (!ScanBuffer(pDone))
+ return false;
+ *pDone = true;
+ return true;
+ }
+ break;
+ }
+
+ }
+ else
+ return nsImportScanFile::Scan(pDone);
+
+ return false;
+}
+
diff --git a/mailnews/import/src/nsImportEncodeScan.h b/mailnews/import/src/nsImportEncodeScan.h
new file mode 100644
index 000000000..3f0e246f1
--- /dev/null
+++ b/mailnews/import/src/nsImportEncodeScan.h
@@ -0,0 +1,39 @@
+/* -*- 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/. */
+
+#ifndef nsImportEncodeScan_h___
+#define nsImportEncodeScan_h___
+
+#include "mozilla/Attributes.h"
+#include "nsIFile.h"
+#include "nsImportScanFile.h"
+#include "nsStringGlue.h"
+
+class nsImportEncodeScan : public nsImportScanFile {
+public:
+ nsImportEncodeScan();
+ ~nsImportEncodeScan();
+
+ bool InitEncodeScan(bool appleSingleEncode, nsIFile *pFile, const char *pName, uint8_t * pBuf, uint32_t sz);
+ void CleanUpEncodeScan(void);
+
+ virtual bool Scan(bool *pDone) override;
+
+protected:
+ void FillInEntries(int numEntries);
+ bool AddEntries(void);
+
+protected:
+ bool m_isAppleSingle;
+ nsCOMPtr<nsIFile> m_pInputFile;
+ nsCOMPtr<nsIInputStream> m_inputStream;
+ int m_encodeScanState;
+ long m_resourceForkSize;
+ long m_dataForkSize;
+ nsCString m_useFileName;
+};
+
+#endif /* nsImportEncodeScan_h__ */
+
diff --git a/mailnews/import/src/nsImportFieldMap.cpp b/mailnews/import/src/nsImportFieldMap.cpp
new file mode 100644
index 000000000..d5e9748dc
--- /dev/null
+++ b/mailnews/import/src/nsImportFieldMap.cpp
@@ -0,0 +1,384 @@
+/* -*- 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 "nscore.h"
+#include "nsIStringBundle.h"
+#include "nsImportFieldMap.h"
+#include "nsImportStringBundle.h"
+#include "nsCRTGlue.h"
+#include "ImportDebug.h"
+#include "nsCOMPtr.h"
+
+////////////////////////////////////////////////////////////////////////
+
+NS_METHOD nsImportFieldMap::Create(nsIStringBundle *aBundle, nsISupports *aOuter, REFNSIID aIID, void **aResult)
+{
+ if (aOuter)
+ return NS_ERROR_NO_AGGREGATION;
+
+ nsImportFieldMap *it = new nsImportFieldMap(aBundle);
+ if (it == nullptr)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(it);
+ nsresult rv = it->QueryInterface(aIID, aResult);
+ NS_RELEASE(it);
+ return rv;
+}
+
+NS_IMPL_ISUPPORTS(nsImportFieldMap, nsIImportFieldMap)
+
+NS_IMETHODIMP nsImportFieldMap::GetSkipFirstRecord(bool *result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ *result = m_skipFirstRecord;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::SetSkipFirstRecord(bool aResult)
+{
+ m_skipFirstRecord = aResult;
+ return NS_OK;
+}
+
+nsImportFieldMap::nsImportFieldMap(nsIStringBundle *aBundle)
+{
+ m_numFields = 0;
+ m_pFields = nullptr;
+ m_pActive = nullptr;
+ m_allocated = 0;
+ // need to init the description array
+ m_mozFieldCount = 0;
+ m_skipFirstRecord = false;
+ nsCOMPtr<nsIStringBundle> pBundle = aBundle;
+
+ nsString *pStr;
+ for (int32_t i = IMPORT_FIELD_DESC_START; i <= IMPORT_FIELD_DESC_END; i++, m_mozFieldCount++) {
+ pStr = new nsString();
+ if (pBundle) {
+ nsImportStringBundle::GetStringByID(i, pBundle, *pStr);
+ }
+ else
+ pStr->AppendInt(i);
+ m_descriptions.AppendElement(pStr);
+ }
+}
+
+nsImportFieldMap::~nsImportFieldMap()
+{
+ if (m_pFields)
+ delete [] m_pFields;
+ if (m_pActive)
+ delete [] m_pActive;
+
+ nsString * pStr;
+ for (int32_t i = 0; i < m_mozFieldCount; i++) {
+ pStr = m_descriptions.ElementAt(i);
+ delete pStr;
+ }
+ m_descriptions.Clear();
+}
+
+
+NS_IMETHODIMP nsImportFieldMap::GetNumMozFields(int32_t *aNumFields)
+{
+ NS_PRECONDITION(aNumFields != nullptr, "null ptr");
+ if (!aNumFields)
+ return NS_ERROR_NULL_POINTER;
+
+ *aNumFields = m_mozFieldCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::GetMapSize(int32_t *aNumFields)
+{
+ NS_PRECONDITION(aNumFields != nullptr, "null ptr");
+ if (!aNumFields)
+ return NS_ERROR_NULL_POINTER;
+
+ *aNumFields = m_numFields;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::GetFieldDescription(int32_t index, char16_t **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = nullptr;
+ if ((index < 0) || ((size_t)index >= m_descriptions.Length()))
+ return NS_ERROR_FAILURE;
+
+ *_retval = ToNewUnicode(*(m_descriptions.ElementAt(index)));
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::SetFieldMapSize(int32_t size)
+{
+ nsresult rv = Allocate(size);
+ if (NS_FAILED(rv))
+ return rv;
+
+ m_numFields = size;
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImportFieldMap::DefaultFieldMap(int32_t size)
+{
+ nsresult rv = SetFieldMapSize(size);
+ if (NS_FAILED(rv))
+ return rv;
+ for (int32_t i = 0; i < size; i++) {
+ m_pFields[i] = i;
+ m_pActive[i] = true;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::GetFieldMap(int32_t index, int32_t *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+
+ if ((index < 0) || (index >= m_numFields))
+ return NS_ERROR_FAILURE;
+
+ *_retval = m_pFields[index];
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::SetFieldMap(int32_t index, int32_t fieldNum)
+{
+ if (index == -1) {
+ nsresult rv = Allocate(m_numFields + 1);
+ if (NS_FAILED(rv))
+ return rv;
+ index = m_numFields;
+ m_numFields++;
+ }
+ else {
+ if ((index < 0) || (index >= m_numFields))
+ return NS_ERROR_FAILURE;
+ }
+
+ if ((fieldNum != -1) && ((fieldNum < 0) || (fieldNum >= m_mozFieldCount)))
+ return NS_ERROR_FAILURE;
+
+ m_pFields[index] = fieldNum;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::GetFieldActive(int32_t index, bool *active)
+{
+ NS_PRECONDITION(active != nullptr, "null ptr");
+ if (!active)
+ return NS_ERROR_NULL_POINTER;
+ if ((index < 0) || (index >= m_numFields))
+ return NS_ERROR_FAILURE;
+
+ *active = m_pActive[index];
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportFieldMap::SetFieldActive(int32_t index, bool active)
+{
+ if ((index < 0) || (index >= m_numFields))
+ return NS_ERROR_FAILURE;
+
+ m_pActive[index] = active;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImportFieldMap::SetFieldValue(nsIAddrDatabase *database, nsIMdbRow *row, int32_t fieldNum, const char16_t *value)
+{
+ NS_PRECONDITION(database != nullptr, "null ptr");
+ NS_PRECONDITION(row != nullptr, "null ptr");
+ NS_PRECONDITION(value != nullptr, "null ptr");
+ if (!database || !row || !value)
+ return NS_ERROR_NULL_POINTER;
+
+ // Allow the special value for a null field
+ if (fieldNum == -1)
+ return NS_OK;
+
+ if ((fieldNum < 0) || (fieldNum >= m_mozFieldCount))
+ return NS_ERROR_FAILURE;
+
+ // UGGG!!!!! lot's of typing here!
+ nsresult rv;
+
+ nsString str(value);
+ char *pVal = ToNewUTF8String(str);
+
+ switch(fieldNum) {
+ case 0:
+ rv = database->AddFirstName(row, pVal);
+ break;
+ case 1:
+ rv = database->AddLastName(row, pVal);
+ break;
+ case 2:
+ rv = database->AddDisplayName(row, pVal);
+ break;
+ case 3:
+ rv = database->AddNickName(row, pVal);
+ break;
+ case 4:
+ rv = database->AddPrimaryEmail(row, pVal);
+ break;
+ case 5:
+ rv = database->Add2ndEmail(row, pVal);
+ break;
+ case 6:
+ rv = database->AddWorkPhone(row, pVal);
+ break;
+ case 7:
+ rv = database->AddHomePhone(row, pVal);
+ break;
+ case 8:
+ rv = database->AddFaxNumber(row, pVal);
+ break;
+ case 9:
+ rv = database->AddPagerNumber(row, pVal);
+ break;
+ case 10:
+ rv = database->AddCellularNumber(row, pVal);
+ break;
+ case 11:
+ rv = database->AddHomeAddress(row, pVal);
+ break;
+ case 12:
+ rv = database->AddHomeAddress2(row, pVal);
+ break;
+ case 13:
+ rv = database->AddHomeCity(row, pVal);
+ break;
+ case 14:
+ rv = database->AddHomeState(row, pVal);
+ break;
+ case 15:
+ rv = database->AddHomeZipCode(row, pVal);
+ break;
+ case 16:
+ rv = database->AddHomeCountry(row, pVal);
+ break;
+ case 17:
+ rv = database->AddWorkAddress(row, pVal);
+ break;
+ case 18:
+ rv = database->AddWorkAddress2(row, pVal);
+ break;
+ case 19:
+ rv = database->AddWorkCity(row, pVal);
+ break;
+ case 20:
+ rv = database->AddWorkState(row, pVal);
+ break;
+ case 21:
+ rv = database->AddWorkZipCode(row, pVal);
+ break;
+ case 22:
+ rv = database->AddWorkCountry(row, pVal);
+ break;
+ case 23:
+ rv = database->AddJobTitle(row, pVal);
+ break;
+ case 24:
+ rv = database->AddDepartment(row, pVal);
+ break;
+ case 25:
+ rv = database->AddCompany(row, pVal);
+ break;
+ case 26:
+ rv = database->AddWebPage1(row, pVal);
+ break;
+ case 27:
+ rv = database->AddWebPage2(row, pVal);
+ break;
+ case 28:
+ rv = database->AddBirthYear(row, pVal);
+ break;
+ case 29:
+ rv = database->AddBirthMonth(row, pVal);
+ break;
+ case 30:
+ rv = database->AddBirthDay(row, pVal);
+ break;
+ case 31:
+ rv = database->AddCustom1(row, pVal);
+ break;
+ case 32:
+ rv = database->AddCustom2(row, pVal);
+ break;
+ case 33:
+ rv = database->AddCustom3(row, pVal);
+ break;
+ case 34:
+ rv = database->AddCustom4(row, pVal);
+ break;
+ case 35:
+ rv = database->AddNotes(row, pVal);
+ break;
+ case 36:
+ rv = database->AddAimScreenName(row, pVal);
+ break;
+ default:
+ /* Get the field description, and add it as an anonymous attr? */
+ /* OR WHAT???? */
+ {
+ rv = NS_ERROR_FAILURE;
+ }
+ }
+
+ NS_Free(pVal);
+
+ return rv;
+}
+
+
+nsresult nsImportFieldMap::Allocate(int32_t newSize)
+{
+ if (newSize <= m_allocated)
+ return NS_OK;
+
+ int32_t sz = m_allocated;
+ while (sz < newSize)
+ sz += 30;
+
+ int32_t *pData = new int32_t[ sz];
+ if (!pData)
+ return NS_ERROR_OUT_OF_MEMORY;
+ bool *pActive = new bool[sz];
+ if (!pActive) {
+ delete [] pData;
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ int32_t i;
+ for (i = 0; i < sz; i++) {
+ pData[i] = -1;
+ pActive[i] = true;
+ }
+ if (m_numFields) {
+ for (i = 0; i < m_numFields; i++) {
+ pData[i] = m_pFields[i];
+ pActive[i] = m_pActive[i];
+ }
+ delete [] m_pFields;
+ delete [] m_pActive;
+ }
+ m_allocated = sz;
+ m_pFields = pData;
+ m_pActive = pActive;
+ return NS_OK;
+}
diff --git a/mailnews/import/src/nsImportFieldMap.h b/mailnews/import/src/nsImportFieldMap.h
new file mode 100644
index 000000000..a25069b1e
--- /dev/null
+++ b/mailnews/import/src/nsImportFieldMap.h
@@ -0,0 +1,46 @@
+/* -*- 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/. */
+
+#ifndef nsImportFieldMap_h___
+#define nsImportFieldMap_h___
+
+#include "nscore.h"
+#include "nsIImportFieldMap.h"
+#include "nsIAddrDatabase.h"
+#include "nsTArray.h"
+#include "nsString.h"
+
+
+////////////////////////////////////////////////////////////////////////
+
+class nsIStringBundle;
+
+class nsImportFieldMap : public nsIImportFieldMap
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ NS_DECL_NSIIMPORTFIELDMAP
+
+ nsImportFieldMap(nsIStringBundle *aBundle);
+
+ static NS_METHOD Create(nsIStringBundle *aBundle, nsISupports *aOuter, REFNSIID aIID, void **aResult);
+
+private:
+ virtual ~nsImportFieldMap();
+ nsresult Allocate(int32_t newSize);
+
+private:
+ int32_t m_numFields;
+ int32_t * m_pFields;
+ bool * m_pActive;
+ int32_t m_allocated;
+ nsTArray<nsString*> m_descriptions;
+ int32_t m_mozFieldCount;
+ bool m_skipFirstRecord;
+};
+
+
+#endif
diff --git a/mailnews/import/src/nsImportMail.cpp b/mailnews/import/src/nsImportMail.cpp
new file mode 100644
index 000000000..ad584b8a6
--- /dev/null
+++ b/mailnews/import/src/nsImportMail.cpp
@@ -0,0 +1,1208 @@
+/* -*- 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 "prthread.h"
+#include "prprf.h"
+#include "nscore.h"
+#include "nsCOMPtr.h"
+#include "nsIArray.h"
+#include "nsArrayUtils.h"
+
+#include "nsIImportMail.h"
+#include "nsIImportGeneric.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIImportMailboxDescriptor.h"
+
+#include "nsStringGlue.h"
+#include "nsUnicharUtils.h"
+
+#include "nsMsgUtils.h"
+#include "nsIMsgAccountManager.h"
+#include "nsMsgBaseCID.h"
+#include "nsIMsgFolder.h"
+#include "nsImportStringBundle.h"
+#include "nsIStringBundle.h"
+#include "nsTextFormatter.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIImportService.h"
+#include "ImportDebug.h"
+#include "plstr.h"
+#include "MailNewsTypes.h"
+#include "nsThreadUtils.h"
+#include "mozilla/Services.h"
+
+#define IMPORT_MSGS_URL "chrome://messenger/locale/importMsgs.properties"
+
+////////////////////////////////////////////////////////////////////////
+
+static void ImportMailThread(void *stuff);
+
+class ImportThreadData;
+
+class nsImportGenericMail : public nsIImportGeneric
+{
+public:
+
+ nsImportGenericMail();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ /* nsISupports GetData (in string dataId); */
+ NS_IMETHOD GetData(const char *dataId, nsISupports **_retval) override;
+
+ NS_IMETHOD SetData(const char *dataId, nsISupports *pData) override;
+
+ NS_IMETHOD GetStatus(const char *statusKind, int32_t *_retval) override;
+
+ NS_IMETHOD WantsProgress(bool *_retval) override;
+
+ NS_IMETHODIMP BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, bool *_retval) override;
+
+ NS_IMETHOD ContinueImport(bool *_retval) override;
+
+ NS_IMETHOD GetProgress(int32_t *_retval) override;
+
+ NS_IMETHOD CancelImport(void) override;
+
+private:
+ virtual ~nsImportGenericMail();
+ bool CreateFolder(nsIMsgFolder **ppFolder);
+ void GetDefaultMailboxes(void);
+ void GetDefaultLocation(void);
+ void GetDefaultDestination(void);
+ void GetMailboxName(uint32_t index, nsISupportsString *pStr);
+
+public:
+ static void SetLogs(nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError);
+ static void ReportError(int32_t id, const char16_t *pName, nsString *pStream, nsIStringBundle* aBundle);
+
+private:
+ nsString m_pName; // module name that created this interface
+ nsIMsgFolder * m_pDestFolder;
+ bool m_deleteDestFolder;
+ bool m_createdFolder;
+ nsCOMPtr <nsIFile> m_pSrcLocation;
+ bool m_gotLocation;
+ bool m_found;
+ bool m_userVerify;
+ nsIImportMail *m_pInterface;
+ nsIArray * m_pMailboxes;
+ nsISupportsString *m_pSuccessLog;
+ nsISupportsString *m_pErrorLog;
+ uint32_t m_totalSize;
+ bool m_doImport;
+ ImportThreadData * m_pThreadData;
+ bool m_performingMigration;
+ nsCOMPtr<nsIStringBundle> m_stringBundle;
+};
+
+class ImportThreadData {
+public:
+ bool driverAlive;
+ bool threadAlive;
+ bool abort;
+ bool fatalError;
+ uint32_t currentTotal;
+ uint32_t currentSize;
+ nsIMsgFolder * destRoot;
+ bool ownsDestRoot;
+ nsIArray *boxes;
+ nsIImportMail * mailImport;
+ nsISupportsString * successLog;
+ nsISupportsString * errorLog;
+ uint32_t currentMailbox;
+ bool performingMigration;
+ nsIStringBundle *stringBundle;
+
+ ImportThreadData();
+ ~ImportThreadData();
+ void DriverDelete();
+ void ThreadDelete();
+ void DriverAbort();
+};
+
+// forward decl for proxy methods
+nsresult ProxyGetSubFolders(nsIMsgFolder *aFolder);
+nsresult ProxyGetChildNamed(nsIMsgFolder *aFolder,const nsAString & aName,
+ nsIMsgFolder **aChild);
+nsresult ProxyGetParent(nsIMsgFolder *aFolder, nsIMsgFolder **aParent);
+nsresult ProxyContainsChildNamed(nsIMsgFolder *aFolder, const nsAString &aName,
+ bool *aResult);
+nsresult ProxyGenerateUniqueSubfolderName(nsIMsgFolder *aFolder,
+ const nsAString& aPrefix,
+ nsIMsgFolder *aOtherFolder,
+ nsAString& aName);
+nsresult ProxyCreateSubfolder(nsIMsgFolder *aFolder, const nsAString &aName);
+nsresult ProxyForceDBClosed(nsIMsgFolder *aFolder);
+
+nsresult NS_NewGenericMail(nsIImportGeneric** aImportGeneric)
+{
+ NS_PRECONDITION(aImportGeneric != nullptr, "null ptr");
+ if (! aImportGeneric)
+ return NS_ERROR_NULL_POINTER;
+
+ nsImportGenericMail *pGen = new nsImportGenericMail();
+
+ if (pGen == nullptr)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(pGen);
+ nsresult rv = pGen->QueryInterface(NS_GET_IID(nsIImportGeneric), (void **)aImportGeneric);
+ NS_RELEASE(pGen);
+
+ return rv;
+}
+
+nsImportGenericMail::nsImportGenericMail()
+{
+ m_found = false;
+ m_userVerify = false;
+ m_gotLocation = false;
+ m_pInterface = nullptr;
+ m_pMailboxes = nullptr;
+ m_pSuccessLog = nullptr;
+ m_pErrorLog = nullptr;
+ m_totalSize = 0;
+ m_doImport = false;
+ m_pThreadData = nullptr;
+
+ m_pDestFolder = nullptr;
+ m_deleteDestFolder = false;
+ m_createdFolder = false;
+ m_performingMigration = false;
+
+ // Init logging module.
+ if (!IMPORTLOGMODULE)
+ IMPORTLOGMODULE = PR_NewLogModule("IMPORT");
+
+ nsresult rv = nsImportStringBundle::GetStringBundle(IMPORT_MSGS_URL, getter_AddRefs(m_stringBundle));
+ if (NS_FAILED(rv))
+ IMPORT_LOG0("Failed to get string bundle for Importing Mail");
+}
+
+
+nsImportGenericMail::~nsImportGenericMail()
+{
+ if (m_pThreadData) {
+ m_pThreadData->DriverAbort();
+ m_pThreadData = nullptr;
+ }
+
+ NS_IF_RELEASE(m_pDestFolder);
+ NS_IF_RELEASE(m_pInterface);
+ NS_IF_RELEASE(m_pMailboxes);
+ NS_IF_RELEASE(m_pSuccessLog);
+ NS_IF_RELEASE(m_pErrorLog);
+}
+
+
+
+NS_IMPL_ISUPPORTS(nsImportGenericMail, nsIImportGeneric)
+
+
+NS_IMETHODIMP nsImportGenericMail::GetData(const char *dataId, nsISupports **_retval)
+{
+ nsresult rv = NS_OK;
+
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = nullptr;
+ if (!PL_strcasecmp(dataId, "mailInterface")) {
+ *_retval = m_pInterface;
+ NS_IF_ADDREF(m_pInterface);
+ }
+
+ if (!PL_strcasecmp(dataId, "mailBoxes")) {
+ if (!m_pMailboxes)
+ GetDefaultMailboxes();
+ *_retval = m_pMailboxes;
+ NS_IF_ADDREF(m_pMailboxes);
+ }
+
+ if (!PL_strcasecmp(dataId, "mailLocation")) {
+ if (!m_pSrcLocation)
+ GetDefaultLocation();
+ NS_IF_ADDREF(*_retval = m_pSrcLocation);
+ }
+
+ if (!PL_strcasecmp(dataId, "mailDestination")) {
+ if (!m_pDestFolder)
+ GetDefaultDestination();
+ NS_IF_ADDREF(*_retval = m_pDestFolder);
+ }
+
+ if (!PL_strcasecmp(dataId, "migration")) {
+ nsCOMPtr<nsISupportsPRBool> migrationString = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ migrationString->SetData(m_performingMigration);
+ NS_IF_ADDREF(*_retval = migrationString);
+ }
+
+ if (!PL_strcasecmp(dataId, "currentMailbox")) {
+ // create an nsISupportsString, get the current mailbox
+ // name being imported and put it in the string
+ nsCOMPtr<nsISupportsString> data = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+ if (m_pThreadData) {
+ GetMailboxName(m_pThreadData->currentMailbox, data);
+ }
+ NS_ADDREF(*_retval = data);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsImportGenericMail::SetData(const char *dataId, nsISupports *item)
+{
+ nsresult rv = NS_OK;
+ NS_PRECONDITION(dataId != nullptr, "null ptr");
+ if (!dataId)
+ return NS_ERROR_NULL_POINTER;
+
+ if (!PL_strcasecmp(dataId, "mailInterface")) {
+ NS_IF_RELEASE(m_pInterface);
+ if (item)
+ item->QueryInterface(NS_GET_IID(nsIImportMail), (void **) &m_pInterface);
+ }
+ if (!PL_strcasecmp(dataId, "mailBoxes")) {
+ NS_IF_RELEASE(m_pMailboxes);
+ if (item)
+ item->QueryInterface(NS_GET_IID(nsIArray), (void **) &m_pMailboxes);
+ }
+
+ if (!PL_strcasecmp(dataId, "mailLocation")) {
+ NS_IF_RELEASE(m_pMailboxes);
+ m_pSrcLocation = nullptr;
+ if (item) {
+ nsresult rv;
+ nsCOMPtr <nsIFile> location = do_QueryInterface(item, &rv);
+ NS_ENSURE_SUCCESS(rv,rv);
+ m_pSrcLocation = location;
+ }
+ }
+
+ if (!PL_strcasecmp(dataId, "mailDestination")) {
+ NS_IF_RELEASE(m_pDestFolder);
+ if (item)
+ item->QueryInterface(NS_GET_IID(nsIMsgFolder), (void **) &m_pDestFolder);
+ m_deleteDestFolder = false;
+ }
+
+ if (!PL_strcasecmp(dataId, "name")) {
+ nsCOMPtr<nsISupportsString> nameString;
+ if (item) {
+ item->QueryInterface(NS_GET_IID(nsISupportsString), getter_AddRefs(nameString));
+ rv = nameString->GetData(m_pName);
+ }
+ }
+
+ if (!PL_strcasecmp(dataId, "migration")) {
+ nsCOMPtr<nsISupportsPRBool> migrationString;
+ if (item) {
+ item->QueryInterface(NS_GET_IID(nsISupportsPRBool), getter_AddRefs(migrationString));
+ rv = migrationString->GetData(&m_performingMigration);
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP nsImportGenericMail::GetStatus(const char *statusKind, int32_t *_retval)
+{
+ NS_PRECONDITION(statusKind != nullptr, "null ptr");
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!statusKind || !_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = 0;
+
+ if (!PL_strcasecmp(statusKind, "isInstalled")) {
+ GetDefaultLocation();
+ *_retval = (int32_t) m_found;
+ }
+
+ if (!PL_strcasecmp(statusKind, "canUserSetLocation")) {
+ GetDefaultLocation();
+ *_retval = (int32_t) m_userVerify;
+ }
+
+ return NS_OK;
+}
+
+
+void nsImportGenericMail::GetDefaultLocation(void)
+{
+ if (!m_pInterface)
+ return;
+
+ if (m_pSrcLocation && m_gotLocation)
+ return;
+
+ m_gotLocation = true;
+
+ nsCOMPtr <nsIFile> pLoc;
+ m_pInterface->GetDefaultLocation(getter_AddRefs(pLoc), &m_found, &m_userVerify);
+ if (!m_pSrcLocation)
+ m_pSrcLocation = pLoc;
+}
+
+void nsImportGenericMail::GetDefaultMailboxes(void)
+{
+ if (!m_pInterface || m_pMailboxes || !m_pSrcLocation)
+ return;
+
+ m_pInterface->FindMailboxes(m_pSrcLocation, &m_pMailboxes);
+}
+
+void nsImportGenericMail::GetDefaultDestination(void)
+{
+ if (m_pDestFolder)
+ return;
+ if (!m_pInterface)
+ return;
+
+ nsIMsgFolder * rootFolder;
+ m_deleteDestFolder = false;
+ m_createdFolder = false;
+ if (CreateFolder(&rootFolder)) {
+ m_pDestFolder = rootFolder;
+ m_deleteDestFolder = true;
+ m_createdFolder = true;
+ return;
+ }
+ IMPORT_LOG0("*** GetDefaultDestination: Failed to create a default import destination folder.");
+}
+
+NS_IMETHODIMP nsImportGenericMail::WantsProgress(bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ NS_ENSURE_ARG_POINTER(_retval);
+
+ if (m_pThreadData) {
+ m_pThreadData->DriverAbort();
+ m_pThreadData = nullptr;
+ }
+
+ if (!m_pMailboxes) {
+ GetDefaultLocation();
+ GetDefaultMailboxes();
+ }
+
+ if (!m_pDestFolder) {
+ GetDefaultDestination();
+ }
+
+ bool result = false;
+
+ if (m_pMailboxes) {
+ uint32_t i;
+ bool import;
+ uint32_t count = 0;
+ uint32_t size;
+ uint32_t totalSize = 0;
+
+ (void) m_pMailboxes->GetLength(&count);
+ for (i = 0; i < count; i++) {
+ nsCOMPtr<nsIImportMailboxDescriptor> box =
+ do_QueryElementAt(m_pMailboxes, i);
+ if (box) {
+ import = false;
+ size = 0;
+ nsresult rv = box->GetImport(&import);
+ if (NS_SUCCEEDED(rv) && import) {
+ (void) box->GetSize(&size);
+ result = true;
+ }
+ totalSize += size;
+ }
+ }
+
+ m_totalSize = totalSize;
+ }
+
+ m_doImport = result;
+
+ *_retval = result;
+
+ return NS_OK;
+}
+
+void nsImportGenericMail::GetMailboxName(uint32_t index, nsISupportsString *pStr)
+{
+ if (m_pMailboxes) {
+ nsCOMPtr<nsIImportMailboxDescriptor> box(do_QueryElementAt(m_pMailboxes, index));
+ if (box) {
+ nsAutoString name;
+ box->GetDisplayName(getter_Copies(name));
+ if (!name.IsEmpty()) {
+ pStr->SetData(name);
+ }
+ }
+ }
+}
+
+NS_IMETHODIMP nsImportGenericMail::BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ nsString success;
+ nsString error;
+
+ if (!m_doImport) {
+ nsImportStringBundle::GetStringByID(IMPORT_NO_MAILBOXES,
+ m_stringBundle, success);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = true;
+ return NS_OK;
+ }
+
+ if (!m_pInterface || !m_pMailboxes) {
+ IMPORT_LOG0("*** BeginImport: Either the interface or source mailbox is not set properly.");
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_MB_NOTINITIALIZED,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = false;
+ return NS_OK;
+ }
+
+ if (!m_pDestFolder) {
+ IMPORT_LOG0("*** BeginImport: The destination mailbox is not set properly.");
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_MB_NODESTFOLDER,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = false;
+ return NS_OK;
+ }
+
+ if (m_pThreadData) {
+ m_pThreadData->DriverAbort();
+ m_pThreadData = nullptr;
+ }
+
+ NS_IF_RELEASE(m_pSuccessLog);
+ NS_IF_RELEASE(m_pErrorLog);
+ m_pSuccessLog = successLog;
+ m_pErrorLog = errorLog;
+ NS_IF_ADDREF(m_pSuccessLog);
+ NS_IF_ADDREF(m_pErrorLog);
+
+
+ // kick off the thread to do the import!!!!
+ m_pThreadData = new ImportThreadData();
+ m_pThreadData->boxes = m_pMailboxes;
+ NS_ADDREF(m_pMailboxes);
+ m_pThreadData->mailImport = m_pInterface;
+ NS_ADDREF(m_pInterface);
+ m_pThreadData->errorLog = m_pErrorLog;
+ NS_IF_ADDREF(m_pErrorLog);
+ m_pThreadData->successLog = m_pSuccessLog;
+ NS_IF_ADDREF(m_pSuccessLog);
+
+ m_pThreadData->ownsDestRoot = m_deleteDestFolder;
+ m_pThreadData->destRoot = m_pDestFolder;
+ m_pThreadData->performingMigration = m_performingMigration;
+ NS_IF_ADDREF(m_pDestFolder);
+
+ NS_IF_ADDREF(m_pThreadData->stringBundle = m_stringBundle);
+
+ PRThread *pThread = PR_CreateThread(PR_USER_THREAD, &ImportMailThread, m_pThreadData,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (!pThread) {
+ m_pThreadData->ThreadDelete();
+ m_pThreadData->abort = true;
+ m_pThreadData->DriverAbort();
+ m_pThreadData = nullptr;
+ *_retval = false;
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_MB_NOTHREAD,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ }
+ else
+ *_retval = true;
+
+ return NS_OK;
+
+}
+
+
+NS_IMETHODIMP nsImportGenericMail::ContinueImport(bool *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = true;
+ if (m_pThreadData) {
+ if (m_pThreadData->fatalError)
+ *_retval = false;
+ }
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImportGenericMail::GetProgress(int32_t *_retval)
+{
+ // This returns the progress from the the currently
+ // running import mail or import address book thread.
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ if (!m_pThreadData || !(m_pThreadData->threadAlive)) {
+ *_retval = 100;
+ return NS_OK;
+ }
+
+ uint32_t sz = 0;
+ if (m_pThreadData->currentSize && m_pInterface) {
+ if (NS_FAILED(m_pInterface->GetImportProgress(&sz)))
+ sz = 0;
+ }
+
+
+ // *_retval = (int32_t) (((uint32_t)(m_pThreadData->currentTotal + sz) * (uint32_t)100) / m_totalSize);
+
+ if (m_totalSize) {
+ double perc;
+ perc = (double) m_pThreadData->currentTotal;
+ perc += sz;
+ perc *= 100;
+ perc /= m_totalSize;
+ *_retval = (int32_t) perc;
+ if (*_retval > 100)
+ *_retval = 100;
+ }
+ else
+ *_retval = 0;
+
+ // never return 100% while the thread is still alive
+ if (*_retval > 99)
+ *_retval = 99;
+
+ return NS_OK;
+}
+
+void nsImportGenericMail::ReportError(int32_t id, const char16_t *pName, nsString *pStream, nsIStringBundle *aBundle)
+{
+ if (!pStream)
+ return;
+
+ // load the error string
+ char16_t *pFmt = nsImportStringBundle::GetStringByID(id, aBundle);
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, pName);
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ NS_Free(pFmt);
+ pStream->Append(NS_ConvertASCIItoUTF16(MSG_LINEBREAK));
+}
+
+
+void nsImportGenericMail::SetLogs(nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError)
+{
+ nsAutoString str;
+ if (pSuccess) {
+ pSuccess->GetData(str);
+ str.Append(success);
+ pSuccess->SetData(str);
+ }
+ if (pError) {
+ pError->GetData(str);
+ str.Append(error);
+ pError->SetData(str);
+ }
+}
+
+NS_IMETHODIMP nsImportGenericMail::CancelImport(void)
+{
+ if (m_pThreadData) {
+ m_pThreadData->abort = true;
+ m_pThreadData->DriverAbort();
+ m_pThreadData = nullptr;
+ }
+
+ return NS_OK;
+}
+
+
+ImportThreadData::ImportThreadData()
+{
+ fatalError = false;
+ driverAlive = true;
+ threadAlive = true;
+ abort = false;
+ currentTotal = 0;
+ currentSize = 0;
+ destRoot = nullptr;
+ ownsDestRoot = false;
+ boxes = nullptr;
+ mailImport = nullptr;
+ successLog = nullptr;
+ errorLog = nullptr;
+ stringBundle = nullptr;
+}
+
+ImportThreadData::~ImportThreadData()
+{
+ NS_IF_RELEASE(destRoot);
+ NS_IF_RELEASE(boxes);
+ NS_IF_RELEASE(mailImport);
+ NS_IF_RELEASE(errorLog);
+ NS_IF_RELEASE(successLog);
+ NS_IF_RELEASE(stringBundle);
+}
+
+void ImportThreadData::DriverDelete(void)
+{
+ driverAlive = false;
+ if (!driverAlive && !threadAlive)
+ delete this;
+}
+
+void ImportThreadData::ThreadDelete()
+{
+ threadAlive = false;
+ if (!driverAlive && !threadAlive)
+ delete this;
+}
+
+void ImportThreadData::DriverAbort()
+{
+ if (abort && !threadAlive && destRoot) {
+ if (ownsDestRoot) {
+ destRoot->RecursiveDelete(true, nullptr);
+ }
+ else {
+ // FIXME: just delete the stuff we created?
+ }
+ }
+ else
+ abort = true;
+ DriverDelete();
+}
+
+
+
+static void
+ImportMailThread(void *stuff)
+{
+ ImportThreadData *pData = (ImportThreadData *)stuff;
+
+ IMPORT_LOG0("ImportMailThread: Starting...");
+
+ nsresult rv = NS_OK;
+
+ nsCOMPtr<nsIMsgFolder> destRoot(pData->destRoot);
+
+ uint32_t count = 0;
+ rv = pData->boxes->GetLength(&count);
+
+ uint32_t i;
+ bool import;
+ uint32_t size;
+ uint32_t depth = 1;
+ uint32_t newDepth;
+ nsString lastName;
+ char16_t * pName;
+
+ nsCOMPtr<nsIMsgFolder> curFolder(destRoot);
+
+ nsCOMPtr<nsIMsgFolder> newFolder;
+ nsCOMPtr<nsIMsgFolder> subFolder;
+
+ bool exists;
+
+ nsString success;
+ nsString error;
+
+ // GetSubFolders() will initialize folders if they are not already initialized.
+ ProxyGetSubFolders(curFolder);
+
+ IMPORT_LOG1("ImportMailThread: Total number of folders to import = %d.", count);
+
+ // Note that the front-end js script only displays one import result string so
+ // we combine both good and bad import status into one string (in var 'success').
+
+ for (i = 0; (i < count) && !(pData->abort); i++) {
+ nsCOMPtr<nsIImportMailboxDescriptor> box =
+ do_QueryElementAt(pData->boxes, i);
+ if (box) {
+ pData->currentMailbox = i;
+
+ import = false;
+ size = 0;
+ rv = box->GetImport(&import);
+ if (import)
+ rv = box->GetSize(&size);
+ rv = box->GetDepth(&newDepth);
+ if (newDepth > depth) {
+ // OK, we are going to add a subfolder under the last/previous folder we processed, so
+ // find this folder (stored in 'lastName') who is going to be the new parent folder.
+ IMPORT_LOG1("ImportMailThread: Processing child folder '%s'.", NS_ConvertUTF16toUTF8(lastName).get());
+ rv = ProxyGetChildNamed(curFolder, lastName, getter_AddRefs(subFolder));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG1("*** ImportMailThread: Failed to get the interface for child folder '%s'.", NS_ConvertUTF16toUTF8(lastName).get());
+ nsImportGenericMail::ReportError(IMPORT_ERROR_MB_FINDCHILD,
+ lastName.get(),
+ &error, pData->stringBundle);
+ pData->fatalError = true;
+ break;
+ }
+ curFolder = subFolder;
+ // Make sure this new parent folder obj has the correct subfolder list so far.
+ rv = ProxyGetSubFolders(curFolder);
+ }
+ else if (newDepth < depth) {
+ rv = NS_OK;
+ while ((newDepth < depth) && NS_SUCCEEDED(rv)) {
+ rv = curFolder->GetParent(getter_AddRefs(curFolder));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG1("*** ImportMailThread: Failed to get the interface for parent folder '%s'.", lastName.get());
+ nsImportGenericMail::ReportError(IMPORT_ERROR_MB_FINDCHILD,
+ lastName.get(), &error,
+ pData->stringBundle);
+ pData->fatalError = true;
+ break;
+ }
+ depth--;
+ }
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG1("*** ImportMailThread: Failed to get the proxy interface for parent folder '%s'.", lastName.get());
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_MB_NOPROXY,
+ pData->stringBundle, error);
+ pData->fatalError = true;
+ break;
+ }
+ }
+ depth = newDepth;
+ pName = nullptr;
+ box->GetDisplayName(&pName);
+ if (pName) {
+ lastName = pName;
+ NS_Free(pName);
+ }
+ else
+ lastName.AssignLiteral("Unknown!");
+
+ // translate the folder name if we are doing migration, but
+ // only for special folders which are at the root level
+ if (pData->performingMigration && depth == 1)
+ pData->mailImport->TranslateFolderName(lastName, lastName);
+
+ exists = false;
+ rv = ProxyContainsChildNamed(curFolder, lastName, &exists);
+
+ // If we are performing profile migration (as opposed to importing) then we are starting
+ // with empty local folders. In that case, always choose to over-write the existing local folder
+ // with this name. Don't create a unique subfolder name. Otherwise you end up with "Inbox, Inbox0"
+ // or "Unsent Folders, UnsentFolders0"
+ if (exists && !pData->performingMigration) {
+ nsString subName;
+ ProxyGenerateUniqueSubfolderName(curFolder, lastName, nullptr, subName);
+ if (!subName.IsEmpty())
+ lastName.Assign(subName);
+ }
+
+ IMPORT_LOG1("ImportMailThread: Creating new import folder '%s'.", NS_ConvertUTF16toUTF8(lastName).get());
+ ProxyCreateSubfolder(curFolder, lastName); // this may fail if the folder already exists..that's ok
+
+ rv = ProxyGetChildNamed(curFolder, lastName, getter_AddRefs(newFolder));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG1("*** ImportMailThread: Failed to locate subfolder '%s' after it's been created.", lastName.get());
+ nsImportGenericMail::ReportError(IMPORT_ERROR_MB_CREATE, lastName.get(),
+ &error, pData->stringBundle);
+ }
+
+ if (size && import && newFolder && NS_SUCCEEDED(rv)) {
+ bool fatalError = false;
+ pData->currentSize = size;
+ char16_t *pSuccess = nullptr;
+ char16_t *pError = nullptr;
+ rv = pData->mailImport->ImportMailbox(box, newFolder, &pError, &pSuccess, &fatalError);
+ if (pError) {
+ error.Append(pError);
+ NS_Free(pError);
+ }
+ if (pSuccess) {
+ success.Append(pSuccess);
+ NS_Free(pSuccess);
+ }
+
+ pData->currentSize = 0;
+ pData->currentTotal += size;
+
+ // commit to the db synchronously, but using a proxy since it doesn't like being used
+ // elsewhere than from the main thread.
+ // OK, we've copied the actual folder/file over if the folder size is not 0
+ // (ie, the msg summary is no longer valid) so close the msg database so that
+ // when the folder is reopened the folder db can be reconstructed (which
+ // validates msg summary and forces folder to be reparsed).
+ rv = ProxyForceDBClosed(newFolder);
+ fatalError = NS_FAILED(rv);
+
+ if (fatalError) {
+ IMPORT_LOG1("*** ImportMailThread: ImportMailbox returned fatalError, mailbox #%d\n", (int) i);
+ pData->fatalError = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Now save the new acct info to pref file.
+ nsCOMPtr <nsIMsgAccountManager> accMgr = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv) && accMgr) {
+ rv = accMgr->SaveAccountInfo();
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Can't save account info to pref file");
+ }
+
+ nsImportGenericMail::SetLogs(success, error, pData->successLog, pData->errorLog);
+
+ if (pData->abort || pData->fatalError) {
+ IMPORT_LOG0("*** ImportMailThread: Abort or fatalError flag was set\n");
+ if (pData->ownsDestRoot) {
+ IMPORT_LOG0("Calling destRoot->RecursiveDelete\n");
+ destRoot->RecursiveDelete(true, nullptr);
+ }
+ else {
+ // FIXME: just delete the stuff we created?
+ }
+ }
+
+ IMPORT_LOG1("Import mailbox thread done: %d\n", (int) pData->currentTotal);
+
+ pData->ThreadDelete();
+
+}
+
+// Creates a folder in Local Folders with the module name + mail
+// for e.g: Outlook Mail
+bool nsImportGenericMail::CreateFolder(nsIMsgFolder **ppFolder)
+{
+ nsresult rv;
+ *ppFolder = nullptr;
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::services::GetStringBundleService();
+ if (!bundleService)
+ return false;
+ rv = bundleService->CreateBundle(IMPORT_MSGS_URL, getter_AddRefs(bundle));
+ if (NS_FAILED(rv))
+ return false;
+ nsString folderName;
+ if (!m_pName.IsEmpty()) {
+ const char16_t *moduleName[] = { m_pName.get() };
+ rv = bundle->FormatStringFromName(u"ImportModuleFolderName",
+ moduleName, 1,
+ getter_Copies(folderName));
+ }
+ else {
+ rv = bundle->GetStringFromName(u"DefaultFolderName",
+ getter_Copies(folderName));
+ }
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Failed to get Folder Name!\n");
+ return false;
+ }
+ nsCOMPtr <nsIMsgAccountManager> accMgr = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Failed to create account manager!\n");
+ return false;
+ }
+
+ nsCOMPtr <nsIMsgIncomingServer> server;
+ rv = accMgr->GetLocalFoldersServer(getter_AddRefs(server));
+ // if Local Folders does not exist already, create it
+ if (NS_FAILED(rv) || !server)
+ {
+ rv = accMgr->CreateLocalMailAccount();
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Failed to create Local Folders!\n");
+ return false;
+ }
+
+ rv = accMgr->GetLocalFoldersServer(getter_AddRefs(server));
+ }
+
+ if (NS_SUCCEEDED(rv) && server) {
+ nsCOMPtr <nsIMsgFolder> localRootFolder;
+ rv = server->GetRootMsgFolder(getter_AddRefs(localRootFolder));
+ if (localRootFolder) {
+ // we need to call GetSubFolders() so that the folders get initialized
+ // if they are not initialized yet.
+ nsCOMPtr<nsISimpleEnumerator> aEnumerator;
+ rv = localRootFolder->GetSubFolders(getter_AddRefs(aEnumerator));
+ if (NS_SUCCEEDED(rv)) {
+ // check if the folder name we picked already exists.
+ bool exists = false;
+ rv = localRootFolder->ContainsChildNamed(folderName, &exists);
+ if (exists) {
+ nsString name;
+ localRootFolder->GenerateUniqueSubfolderName(folderName, nullptr, name);
+ if (!name.IsEmpty())
+ folderName.Assign(name);
+ else {
+ IMPORT_LOG0("*** Failed to find a unique folder name!\n");
+ return false;
+ }
+ }
+ IMPORT_LOG1("Creating folder for importing mail: '%s'\n", NS_ConvertUTF16toUTF8(folderName).get());
+
+ // Bug 564162 identifies a dataloss design flaw.
+ // A working Thunderbird client can have mail in Local Folders and a
+ // subsequent import 'Everything' will trigger a migration which
+ // overwrites existing mailboxes with the imported mailboxes.
+ rv = localRootFolder->CreateSubfolder(folderName, nullptr);
+ if (NS_SUCCEEDED(rv)) {
+ rv = localRootFolder->GetChildNamed(folderName, ppFolder);
+ if (*ppFolder) {
+ IMPORT_LOG1("Folder '%s' created successfully\n", NS_ConvertUTF16toUTF8(folderName).get());
+ return true;
+ }
+ }
+ }
+ } // if localRootFolder
+ } // if server
+ IMPORT_LOG0("****** FAILED TO CREATE FOLDER FOR IMPORT\n");
+ return false;
+}
+
+/**
+ * These are the proxy objects we use to proxy nsIMsgFolder methods back
+ * the the main thread. Since there are only five, we can hand roll them.
+ * A better design might be a co-routine-ish design where the ui thread
+ * hands off each folder to the import thread and when the thread finishes
+ * the folder, the main thread hands it the next folder.
+ */
+
+class GetSubFoldersRunnable : public mozilla::Runnable
+{
+public:
+ GetSubFoldersRunnable(nsIMsgFolder *aFolder);
+ NS_DECL_NSIRUNNABLE
+private:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+};
+
+GetSubFoldersRunnable::GetSubFoldersRunnable(nsIMsgFolder *aFolder) :
+ m_folder(aFolder)
+{
+}
+
+NS_IMETHODIMP GetSubFoldersRunnable::Run()
+{
+ nsCOMPtr<nsISimpleEnumerator> dummy;
+ return m_folder->GetSubFolders(getter_AddRefs(dummy));
+}
+
+
+nsresult ProxyGetSubFolders(nsIMsgFolder *aFolder)
+{
+ RefPtr<GetSubFoldersRunnable> getSubFolders =
+ new GetSubFoldersRunnable(aFolder);
+ return NS_DispatchToMainThread(getSubFolders, NS_DISPATCH_SYNC);
+}
+
+class GetChildNamedRunnable : public mozilla::Runnable
+{
+public:
+ GetChildNamedRunnable(nsIMsgFolder *aFolder, const nsAString& aName, nsIMsgFolder **aChild);
+ NS_DECL_NSIRUNNABLE
+protected:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+ nsString m_name;
+ nsIMsgFolder **m_child;
+};
+
+GetChildNamedRunnable::GetChildNamedRunnable(nsIMsgFolder *aFolder,
+ const nsAString & aName,
+ nsIMsgFolder **aChild) :
+ m_folder(aFolder), m_name(aName), m_child(aChild)
+{
+}
+
+NS_IMETHODIMP GetChildNamedRunnable::Run()
+{
+ return m_folder->GetChildNamed(m_name, m_child);
+}
+
+
+nsresult ProxyGetChildNamed(nsIMsgFolder *aFolder, const nsAString & aName,
+ nsIMsgFolder **aChild)
+{
+ RefPtr<GetChildNamedRunnable> getChildNamed =
+ new GetChildNamedRunnable(aFolder, aName, aChild);
+ return NS_DispatchToMainThread(getChildNamed, NS_DISPATCH_SYNC);
+}
+
+class GetParentRunnable : public mozilla::Runnable
+{
+public:
+ GetParentRunnable(nsIMsgFolder *aFolder, nsIMsgFolder **aParent);
+ NS_DECL_NSIRUNNABLE
+protected:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+ nsIMsgFolder **m_parent;
+};
+
+GetParentRunnable::GetParentRunnable(nsIMsgFolder *aFolder, nsIMsgFolder **aParent) :
+ m_folder(aFolder), m_parent(aParent)
+{
+}
+
+NS_IMETHODIMP GetParentRunnable::Run()
+{
+ return m_folder->GetParent(m_parent);
+}
+
+
+nsresult ProxyGetParent(nsIMsgFolder *aFolder, nsIMsgFolder **aParent)
+{
+ RefPtr<GetParentRunnable> getParent =
+ new GetParentRunnable(aFolder, aParent);
+ return NS_DispatchToMainThread(getParent, NS_DISPATCH_SYNC);
+}
+
+class ContainsChildNamedRunnable : public mozilla::Runnable
+{
+public:
+ ContainsChildNamedRunnable(nsIMsgFolder *aFolder, const nsAString& aName, bool *aResult);
+ NS_DECL_NSIRUNNABLE
+protected:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+ nsString m_name;
+ bool *m_result;
+};
+
+ContainsChildNamedRunnable::ContainsChildNamedRunnable(nsIMsgFolder *aFolder,
+ const nsAString &aName,
+ bool *aResult) :
+ m_folder(aFolder), m_name(aName), m_result(aResult)
+{
+}
+
+NS_IMETHODIMP ContainsChildNamedRunnable::Run()
+{
+ return m_folder->ContainsChildNamed(m_name, m_result);
+}
+
+
+nsresult ProxyContainsChildNamed(nsIMsgFolder *aFolder, const nsAString &aName,
+ bool *aResult)
+{
+ RefPtr<ContainsChildNamedRunnable> containsChildNamed =
+ new ContainsChildNamedRunnable(aFolder, aName, aResult);
+ return NS_DispatchToMainThread(containsChildNamed, NS_DISPATCH_SYNC);
+}
+
+
+class GenerateUniqueSubfolderNameRunnable : public mozilla::Runnable
+{
+public:
+ GenerateUniqueSubfolderNameRunnable(nsIMsgFolder *aFolder,
+ const nsAString& prefix,
+ nsIMsgFolder *otherFolder,
+ nsAString& name);
+ NS_DECL_NSIRUNNABLE
+protected:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+ nsString m_prefix;
+ nsCOMPtr<nsIMsgFolder> m_otherFolder;
+ nsString m_name;
+};
+
+GenerateUniqueSubfolderNameRunnable::GenerateUniqueSubfolderNameRunnable(
+ nsIMsgFolder *aFolder, const nsAString& aPrefix, nsIMsgFolder *aOtherFolder,
+ nsAString& aName)
+ : m_folder(aFolder), m_prefix(aPrefix), m_otherFolder(aOtherFolder), m_name(aName)
+{
+}
+
+NS_IMETHODIMP GenerateUniqueSubfolderNameRunnable::Run()
+{
+ return m_folder->GenerateUniqueSubfolderName(m_prefix, m_otherFolder, m_name);
+}
+
+
+nsresult ProxyGenerateUniqueSubfolderName(nsIMsgFolder *aFolder,
+ const nsAString& aPrefix,
+ nsIMsgFolder *aOtherFolder,
+ nsAString& aName)
+
+{
+ RefPtr<GenerateUniqueSubfolderNameRunnable> generateUniqueSubfolderName =
+ new GenerateUniqueSubfolderNameRunnable(aFolder, aPrefix, aOtherFolder, aName);
+ return NS_DispatchToMainThread(generateUniqueSubfolderName, NS_DISPATCH_SYNC);
+}
+
+class CreateSubfolderRunnable : public mozilla::Runnable
+{
+public:
+ CreateSubfolderRunnable(nsIMsgFolder *aFolder, const nsAString& aName);
+ NS_DECL_NSIRUNNABLE
+protected:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+ nsString m_name;
+};
+
+CreateSubfolderRunnable::CreateSubfolderRunnable(nsIMsgFolder *aFolder,
+ const nsAString &aName) :
+ m_folder(aFolder), m_name(aName)
+{
+}
+
+NS_IMETHODIMP CreateSubfolderRunnable::Run()
+{
+ return m_folder->CreateSubfolder(m_name, nullptr);
+}
+
+
+nsresult ProxyCreateSubfolder(nsIMsgFolder *aFolder, const nsAString &aName)
+{
+ RefPtr<CreateSubfolderRunnable> createSubfolder =
+ new CreateSubfolderRunnable(aFolder, aName);
+ return NS_DispatchToMainThread(createSubfolder, NS_DISPATCH_SYNC);
+}
+
+class ForceDBClosedRunnable : public mozilla::Runnable
+{
+public:
+ ForceDBClosedRunnable(nsIMsgFolder *aFolder);
+ NS_DECL_NSIRUNNABLE
+protected:
+ nsCOMPtr<nsIMsgFolder> m_folder;
+};
+
+ForceDBClosedRunnable::ForceDBClosedRunnable(nsIMsgFolder *aFolder) :
+ m_folder(aFolder)
+{
+}
+
+NS_IMETHODIMP ForceDBClosedRunnable::Run()
+{
+ return m_folder->ForceDBClosed();
+}
+
+nsresult ProxyForceDBClosed(nsIMsgFolder *aFolder)
+{
+ RefPtr<ForceDBClosedRunnable> forceDBClosed =
+ new ForceDBClosedRunnable(aFolder);
+ return NS_DispatchToMainThread(forceDBClosed, NS_DISPATCH_SYNC);
+}
+
+
diff --git a/mailnews/import/src/nsImportMailboxDescriptor.cpp b/mailnews/import/src/nsImportMailboxDescriptor.cpp
new file mode 100644
index 000000000..ab0ea5db4
--- /dev/null
+++ b/mailnews/import/src/nsImportMailboxDescriptor.cpp
@@ -0,0 +1,39 @@
+/* -*- 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/. */
+
+
+#include "nscore.h"
+#include "nsImportMailboxDescriptor.h"
+#include "nsComponentManagerUtils.h"
+
+////////////////////////////////////////////////////////////////////////
+
+
+
+NS_METHOD nsImportMailboxDescriptor::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
+{
+ if (aOuter)
+ return NS_ERROR_NO_AGGREGATION;
+
+ nsImportMailboxDescriptor *it = new nsImportMailboxDescriptor();
+ if (it == nullptr)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(it);
+ nsresult rv = it->QueryInterface(aIID, aResult);
+ NS_RELEASE(it);
+ return rv;
+}
+
+NS_IMPL_ISUPPORTS(nsImportMailboxDescriptor, nsIImportMailboxDescriptor)
+
+nsImportMailboxDescriptor::nsImportMailboxDescriptor()
+{
+ m_import = true;
+ m_size = 0;
+ m_depth = 0;
+ m_id = 0;
+ m_pFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+}
diff --git a/mailnews/import/src/nsImportMailboxDescriptor.h b/mailnews/import/src/nsImportMailboxDescriptor.h
new file mode 100644
index 000000000..1f4c30b31
--- /dev/null
+++ b/mailnews/import/src/nsImportMailboxDescriptor.h
@@ -0,0 +1,63 @@
+/* -*- 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/. */
+
+#ifndef nsImportMailboxDescriptor_h___
+#define nsImportMailboxDescriptor_h___
+
+#include "mozilla/Attributes.h"
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsIImportMailboxDescriptor.h"
+#include "nsIFile.h"
+#include "nsCOMPtr.h"
+
+////////////////////////////////////////////////////////////////////////
+
+
+class nsImportMailboxDescriptor : public nsIImportMailboxDescriptor
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ NS_IMETHOD GetIdentifier(uint32_t *pIdentifier) override { *pIdentifier = m_id; return NS_OK;}
+ NS_IMETHOD SetIdentifier(uint32_t ident) override { m_id = ident; return NS_OK;}
+
+ /* attribute unsigned long depth; */
+ NS_IMETHOD GetDepth(uint32_t *pDepth) override { *pDepth = m_depth; return NS_OK;}
+ NS_IMETHOD SetDepth(uint32_t theDepth) override { m_depth = theDepth; return NS_OK;}
+
+ /* attribute unsigned long size; */
+ NS_IMETHOD GetSize(uint32_t *pSize) override { *pSize = m_size; return NS_OK;}
+ NS_IMETHOD SetSize(uint32_t theSize) override { m_size = theSize; return NS_OK;}
+
+ /* attribute wstring displayName; */
+ NS_IMETHOD GetDisplayName(char16_t **pName) override { *pName = ToNewUnicode(m_displayName); return NS_OK;}
+ NS_IMETHOD SetDisplayName(const char16_t * pName) override { m_displayName = pName; return NS_OK;}
+
+ /* attribute boolean import; */
+ NS_IMETHOD GetImport(bool *pImport) override { *pImport = m_import; return NS_OK;}
+ NS_IMETHOD SetImport(bool doImport) override { m_import = doImport; return NS_OK;}
+
+ /* readonly attribute nsIFile file; */
+ NS_IMETHOD GetFile(nsIFile * *aFile) override { if (m_pFile) { NS_ADDREF(*aFile = m_pFile); return NS_OK;} else return NS_ERROR_FAILURE; }
+
+
+
+ nsImportMailboxDescriptor();
+
+ static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
+
+private:
+ virtual ~nsImportMailboxDescriptor() {}
+ uint32_t m_id; // used by creator of the structure
+ uint32_t m_depth; // depth in the hierarchy
+ nsString m_displayName;// name of this mailbox
+ nsCOMPtr <nsIFile> m_pFile; // source file (if applicable)
+ uint32_t m_size;
+ bool m_import; // import it or not?
+};
+
+
+#endif
diff --git a/mailnews/import/src/nsImportMimeEncode.cpp b/mailnews/import/src/nsImportMimeEncode.cpp
new file mode 100644
index 000000000..e13ea1f94
--- /dev/null
+++ b/mailnews/import/src/nsImportMimeEncode.cpp
@@ -0,0 +1,411 @@
+/* -*- 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/. */
+
+#include "nscore.h"
+#include "nsImportMimeEncode.h"
+
+#include "ImportCharSet.h"
+#include "ImportTranslate.h"
+
+#define kNoState 0
+#define kStartState 1
+#define kEncodeState 2
+#define kDoneState 3
+
+#define kEncodeBufferSz (8192 * 8)
+
+nsImportMimeEncode::nsImportMimeEncode()
+{
+ m_pOut = nullptr;
+ m_state = kNoState;
+ m_bytesProcessed = 0;
+ m_pInputBuf = nullptr;
+}
+
+nsImportMimeEncode::~nsImportMimeEncode()
+{
+ delete [] m_pInputBuf;
+}
+
+void nsImportMimeEncode::EncodeFile(nsIFile *pInFile, ImportOutFile *pOut, const char *pFileName, const char *pMimeType)
+{
+ m_fileName = pFileName;
+ m_mimeType = pMimeType;
+
+ m_pMimeFile = pInFile;
+
+ m_pOut = pOut;
+ m_state = kStartState;
+}
+
+void nsImportMimeEncode::CleanUp(void)
+{
+ CleanUpEncodeScan();
+}
+
+bool nsImportMimeEncode::SetUpEncode(void)
+{
+ nsCString errStr;
+ if (!m_pInputBuf) {
+ m_pInputBuf = new uint8_t[kEncodeBufferSz];
+ }
+
+ m_appleSingle = false;
+
+#ifdef _MAC_IMPORT_CODE
+ // First let's see just what kind of beast we have?
+ // For files with only a data fork and a known mime type
+ // proceed with normal mime encoding just as on the PC.
+ // For unknown mime types and files with both forks,
+ // encode as AppleSingle format.
+ if (m_filePath.GetMacFileSize(UFileLocation::eResourceFork) || !pMimeType) {
+ m_appleSingle = TRUE;
+ m_mimeType = "application/applefile";
+ }
+#endif
+
+ if (!InitEncodeScan(m_appleSingle, m_pMimeFile, m_fileName.get(), m_pInputBuf, kEncodeBufferSz)) {
+ return false;
+ }
+
+ m_state = kEncodeState;
+ m_lineLen = 0;
+
+ // Write out the boundary header
+ bool bResult = true;
+ bResult = m_pOut->WriteStr("Content-type: ");
+ if (bResult)
+ bResult = m_pOut->WriteStr(m_mimeType.get());
+
+#ifdef _MAC_IMPORT_CODE
+ // include the type an creator here
+ if (bResult)
+ bResult = m_pOut->WriteStr("; x-mac-type=\"");
+ U8 hex[8];
+ LongToHexBytes(m_filePath.GetFileType(), hex);
+ if (bResult)
+ bResult = m_pOut->WriteData(hex, 8);
+ LongToHexBytes(m_filePath.GetFileCreator(), hex);
+ if (bResult)
+ bResult = m_pOut->WriteStr("\"; x-mac-creator=\"");
+ if (bResult)
+ bResult = m_pOut->WriteData(hex, 8);
+ if (bResult)
+ bResult = m_pOut->WriteStr("\"");
+#endif
+
+ /*
+ if (bResult)
+ bResult = m_pOut->WriteStr(gMimeTypeFileName);
+ */
+ if (bResult)
+ bResult = m_pOut->WriteStr(";\x0D\x0A");
+
+ nsCString fName;
+ bool trans = TranslateFileName(m_fileName, fName);
+ if (bResult)
+ bResult = WriteFileName(fName, trans, "name");
+ if (bResult)
+ bResult = m_pOut->WriteStr("Content-transfer-encoding: base64");
+ if (bResult)
+ bResult = m_pOut->WriteEol();
+ if (bResult)
+ bResult = m_pOut->WriteStr("Content-Disposition: attachment;\x0D\x0A");
+ if (bResult)
+ bResult = WriteFileName(fName, trans, "filename");
+ if (bResult)
+ bResult = m_pOut->WriteEol();
+
+ if (!bResult) {
+ CleanUp();
+ }
+
+ return bResult;
+}
+
+bool nsImportMimeEncode::DoWork(bool *pDone)
+{
+ *pDone = false;
+ switch(m_state) {
+ case kNoState:
+ return false;
+ break;
+ case kStartState:
+ return SetUpEncode();
+ break;
+ case kEncodeState:
+ if (!Scan(pDone)) {
+ CleanUp();
+ return false;
+ }
+ if (*pDone) {
+ *pDone = false;
+ m_state = kDoneState;
+ }
+ break;
+ case kDoneState:
+ CleanUp();
+ m_state = kNoState;
+ *pDone = true;
+ break;
+ }
+
+ return true;
+}
+
+static uint8_t gBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+bool nsImportMimeEncode::ScanBuffer(bool *pDone)
+{
+
+ uint32_t pos = m_pos;
+ uint32_t start = pos;
+ uint8_t * pChar = m_pBuf + pos;
+ uint32_t max = m_bytesInBuf;
+ uint8_t byte[4];
+ uint32_t lineLen = m_lineLen;
+
+ while ((pos + 2) < max) {
+ // Encode 3 bytes
+ byte[0] = gBase64[*pChar >> 2];
+ byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
+ pChar++;
+ byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
+ pChar++;
+ byte[3] = gBase64[(*pChar) & 0x3F];
+ if (!m_pOut->WriteData(byte, 4))
+ return false;
+ pos += 3;
+ pChar++;
+ lineLen += 4;
+ if (lineLen > 71) {
+ if (!m_pOut->WriteEol())
+ return false;
+ lineLen = 0;
+ }
+ }
+
+ if ((pos < max) && m_eof) {
+ // Get the last few bytes!
+ byte[0] = gBase64[*pChar >> 2];
+ pos++;
+ if (pos < max) {
+ byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
+ pChar++;
+ pos++;
+ if (pos < max) {
+ // Should be dead code!! (Then why is it here doofus?)
+ byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
+ pChar++;
+ byte[3] = gBase64[(*pChar) & 0x3F];
+ pos++;
+ }
+ else {
+ byte[2] = gBase64[(((*pChar) & 0xF) << 2)];
+ byte[3] = '=';
+ }
+ }
+ else {
+ byte[1] = gBase64[(((*pChar) & 0x3)<< 4)];
+ byte[2] = '=';
+ byte[3] = '=';
+ }
+
+ if (!m_pOut->WriteData(byte, 4))
+ return false;
+ if (!m_pOut->WriteEol())
+ return false;
+ }
+ else if (m_eof) {
+ /*
+ byte[0] = '=';
+ if (!m_pOut->WriteData(byte, 1))
+ return FALSE;
+ */
+ if (!m_pOut->WriteEol())
+ return false;
+ }
+
+ m_lineLen = (int) lineLen;
+ m_pos = pos;
+ m_bytesProcessed += (pos - start);
+ return true;
+}
+
+bool nsImportMimeEncode::TranslateFileName(nsCString& inFile, nsCString& outFile)
+{
+ const uint8_t * pIn = (const uint8_t *) inFile.get();
+ int len = inFile.Length();
+
+ while (len) {
+ if (!ImportCharSet::IsUSAscii(*pIn))
+ break;
+ len--;
+ pIn++;
+ }
+ if (len) {
+ // non US ascii!
+ // assume this string needs translating...
+ if (!ImportTranslate::ConvertString(inFile, outFile, true)) {
+ outFile = inFile;
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ else {
+ outFile = inFile;
+ return false;
+ }
+}
+
+bool nsImportMimeEncode::WriteFileName(nsCString& fName, bool wasTrans, const char *pTag)
+{
+ int tagNum = 0;
+ int idx = 0;
+ bool result = true;
+ int len;
+ nsCString numStr;
+
+ while ((((fName.Length() - idx) + strlen(pTag)) > 70) && result) {
+ len = 68 - strlen(pTag) - 5;
+ if (wasTrans) {
+ if (fName.CharAt(idx + len - 1) == '%')
+ len--;
+ else if (fName.CharAt(idx + len - 2) == '%')
+ len -= 2;
+ }
+
+ if (result)
+ result = m_pOut->WriteStr("\x09");
+ if (result)
+ result = m_pOut->WriteStr(pTag);
+ numStr = "*";
+ numStr.AppendInt(tagNum);
+ if (result)
+ result = m_pOut->WriteStr(numStr.get());
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("*=");
+ else if (result)
+ result = m_pOut->WriteStr("=\"");
+ if (result)
+ result = m_pOut->WriteData(((const uint8_t *)fName.get()) + idx, len);
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("\x0D\x0A");
+ else if (result)
+ result = m_pOut->WriteStr("\"\x0D\x0A");
+ idx += len;
+ tagNum++;
+ }
+
+ if (idx) {
+ if ((fName.Length() - idx) > 0) {
+ if (result)
+ result = m_pOut->WriteStr("\x09");
+ if (result)
+ result = m_pOut->WriteStr(pTag);
+ numStr = "*";
+ numStr.AppendInt(tagNum);
+ if (result)
+ result = m_pOut->WriteStr(numStr.get());
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("*=");
+ else if (result)
+ result = m_pOut->WriteStr("=\"");
+ if (result)
+ result = m_pOut->WriteData(((const uint8_t *)fName.get()) + idx, fName.Length() - idx);
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("\x0D\x0A");
+ else if (result)
+ result = m_pOut->WriteStr("\"\x0D\x0A");
+ }
+ }
+ else {
+ if (result)
+ result = m_pOut->WriteStr("\x09");
+ if (result)
+ result = m_pOut->WriteStr(pTag);
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("*=");
+ else if (result)
+ result = m_pOut->WriteStr("=\"");
+ if (result)
+ result = m_pOut->WriteStr(fName.get());
+ if (wasTrans && result)
+ result = m_pOut->WriteStr("\x0D\x0A");
+ else if (result)
+ result = m_pOut->WriteStr("\"\x0D\x0A");
+ }
+
+ return result;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+nsIImportMimeEncodeImpl::nsIImportMimeEncodeImpl()
+{
+ m_pOut = nullptr;
+ m_pEncode = nullptr;
+}
+
+nsIImportMimeEncodeImpl::~nsIImportMimeEncodeImpl()
+{
+ if (m_pOut)
+ delete m_pOut;
+ if (m_pEncode)
+ delete m_pEncode;
+}
+
+NS_IMPL_ISUPPORTS(nsIImportMimeEncodeImpl, nsIImportMimeEncode)
+
+NS_METHOD nsIImportMimeEncodeImpl::EncodeFile(nsIFile *inFile, nsIFile *outFile, const char *fileName, const char *mimeType)
+{
+ return Initialize(inFile, outFile, fileName, mimeType);
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::DoWork(bool *done, bool *_retval)
+{
+ if (done && _retval && m_pEncode) {
+ *_retval = m_pEncode->DoWork(done);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::NumBytesProcessed(int32_t *_retval)
+{
+ if (m_pEncode && _retval)
+ *_retval = m_pEncode->NumBytesProcessed();
+ return NS_OK;
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::DoEncoding(bool *_retval)
+{
+ if (_retval && m_pEncode) {
+ bool done = false;
+ while (m_pEncode->DoWork(&done) && !done);
+ *_retval = done;
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_METHOD nsIImportMimeEncodeImpl::Initialize(nsIFile *inFile, nsIFile *outFile, const char *fileName, const char *mimeType)
+{
+ delete m_pEncode;
+ delete m_pOut;
+
+ m_pOut = new ImportOutFile();
+ m_pOut->InitOutFile(outFile);
+
+ m_pEncode = new nsImportMimeEncode();
+ m_pEncode->EncodeFile(inFile, m_pOut, fileName, mimeType);
+
+ return NS_OK;
+}
+
diff --git a/mailnews/import/src/nsImportMimeEncode.h b/mailnews/import/src/nsImportMimeEncode.h
new file mode 100644
index 000000000..1447d11c4
--- /dev/null
+++ b/mailnews/import/src/nsImportMimeEncode.h
@@ -0,0 +1,73 @@
+/* -*- 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/. */
+#ifndef nsImportMimeEncode_h__
+#define nsImportMimeEncode_h__
+
+#include "mozilla/Attributes.h"
+#include "nsImportScanFile.h"
+#include "ImportOutFile.h"
+#include "nsImportEncodeScan.h"
+#include "nsStringGlue.h"
+#include "nsIImportMimeEncode.h"
+
+
+// Content-Type: image/gif; name="blah.xyz"
+// Content-Transfer-Encoding: base64
+// Content-Disposition: attachment; filename="blah.xyz"
+
+class nsImportMimeEncode : public nsImportEncodeScan {
+public:
+ nsImportMimeEncode();
+ ~nsImportMimeEncode();
+
+ void EncodeFile(nsIFile *pInFile, ImportOutFile *pOut, const char *pFileName, const char *pMimeType);
+
+ bool DoWork(bool *pDone);
+
+ long NumBytesProcessed(void) { long val = m_bytesProcessed; m_bytesProcessed = 0; return val;}
+
+protected:
+ void CleanUp(void);
+ bool SetUpEncode(void);
+ bool WriteFileName(nsCString& fName, bool wasTrans, const char *pTag);
+ bool TranslateFileName(nsCString& inFile, nsCString& outFile);
+
+
+ virtual bool ScanBuffer(bool *pDone) override;
+
+
+protected:
+ nsCString m_fileName;
+ nsCOMPtr <nsIFile> m_pMimeFile;
+ ImportOutFile * m_pOut;
+ nsCString m_mimeType;
+
+ int m_state;
+ long m_bytesProcessed;
+ uint8_t * m_pInputBuf;
+ bool m_appleSingle;
+
+ // Actual encoding variables
+ int m_lineLen;
+};
+
+
+class nsIImportMimeEncodeImpl : public nsIImportMimeEncode {
+public:
+ NS_DECL_ISUPPORTS
+
+ NS_DECL_NSIIMPORTMIMEENCODE
+
+ nsIImportMimeEncodeImpl();
+
+private:
+ virtual ~nsIImportMimeEncodeImpl();
+ ImportOutFile * m_pOut;
+ nsImportMimeEncode * m_pEncode;
+};
+
+
+#endif /* nsImportMimeEncode_h__ */
+
diff --git a/mailnews/import/src/nsImportScanFile.cpp b/mailnews/import/src/nsImportScanFile.cpp
new file mode 100644
index 000000000..c4eefef3b
--- /dev/null
+++ b/mailnews/import/src/nsImportScanFile.cpp
@@ -0,0 +1,172 @@
+/* -*- 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/. */
+
+#include "nscore.h"
+#include "nsIFile.h"
+#include "nsImportScanFile.h"
+#include "ImportCharSet.h"
+
+nsImportScanFile::nsImportScanFile()
+{
+ m_allocated = false;
+ m_eof = false;
+ m_pBuf = nullptr;
+}
+
+nsImportScanFile::~nsImportScanFile()
+{
+ if (m_allocated)
+ CleanUpScan();
+}
+
+void nsImportScanFile::InitScan(nsIInputStream *pInputStream, uint8_t * pBuf, uint32_t sz)
+{
+ m_pInputStream = pInputStream;
+ m_pBuf = pBuf;
+ m_bufSz = sz;
+ m_bytesInBuf = 0;
+ m_pos = 0;
+}
+
+void nsImportScanFile::CleanUpScan(void)
+{
+ m_pInputStream = nullptr;
+ if (m_allocated) {
+ delete [] m_pBuf;
+ m_pBuf = NULL;
+ }
+}
+
+void nsImportScanFile::ShiftBuffer(void)
+{
+ uint8_t * pTop;
+ uint8_t * pCurrent;
+
+ if (m_pos < m_bytesInBuf) {
+ pTop = m_pBuf;
+ pCurrent = pTop + m_pos;
+ uint32_t cnt = m_bytesInBuf - m_pos;
+ while (cnt) {
+ *pTop = *pCurrent;
+ pTop++; pCurrent++;
+ cnt--;
+ }
+ }
+
+ m_bytesInBuf -= m_pos;
+ m_pos = 0;
+}
+
+bool nsImportScanFile::FillBufferFromFile(void)
+{
+ uint64_t available;
+ nsresult rv = m_pInputStream->Available(&available);
+ if (NS_FAILED(rv))
+ return false;
+
+ // Fill up a buffer and scan it
+ ShiftBuffer();
+
+ // Read in some more bytes
+ uint32_t cnt = m_bufSz - m_bytesInBuf;
+ // To distinguish from disk errors
+ // Check first for end of file?
+ // Set a done flag if true...
+ uint32_t read;
+ char *pBuf = (char *)m_pBuf;
+ pBuf += m_bytesInBuf;
+ rv = m_pInputStream->Read(pBuf, (int32_t) cnt, &read);
+
+ if (NS_FAILED(rv))
+ return false;
+ rv = m_pInputStream->Available(&available);
+ if (NS_FAILED(rv))
+ m_eof = true;
+
+ m_bytesInBuf += cnt;
+ return true;
+}
+
+bool nsImportScanFile::Scan(bool *pDone)
+{
+ uint64_t available;
+ nsresult rv = m_pInputStream->Available(&available);
+ if (NS_FAILED(rv))
+ {
+ if (m_pos < m_bytesInBuf)
+ ScanBuffer(pDone);
+ *pDone = true;
+ return true;
+ }
+
+ // Fill up a buffer and scan it
+ if (!FillBufferFromFile())
+ return false;
+
+ return ScanBuffer(pDone);
+}
+
+bool nsImportScanFile::ScanBuffer(bool *)
+{
+ return true;
+}
+
+
+bool nsImportScanFileLines::ScanBuffer(bool *pDone)
+{
+ // m_pos, m_bytesInBuf, m_eof, m_pBuf are relevant
+
+ uint32_t pos = m_pos;
+ uint32_t max = m_bytesInBuf;
+ uint8_t * pChar = m_pBuf + pos;
+ uint32_t startPos;
+
+ while (pos < max) {
+ if (m_needEol) {
+ // Find the next eol...
+ while ((pos < max) && (*pChar != ImportCharSet::cCRChar) && (*pChar != ImportCharSet::cLinefeedChar)) {
+ pos++;
+ pChar++;
+ }
+ m_pos = pos;
+ if (pos < max)
+ m_needEol = false;
+ if (pos == max) // need more buffer for an end of line
+ break;
+ }
+ // Skip past any eol characters
+ while ((pos < max) && ((*pChar == ImportCharSet::cCRChar) || (*pChar == ImportCharSet::cLinefeedChar))) {
+ pos++;
+ pChar++;
+ }
+ m_pos = pos;
+ if (pos == max)
+ break;
+ // Make sure we can find either the eof or the
+ // next end of line
+ startPos = pos;
+ while ((pos < max) && (*pChar != ImportCharSet::cCRChar) && (*pChar != ImportCharSet::cLinefeedChar)) {
+ pos++;
+ pChar++;
+ }
+
+ // Is line too big for our buffer?
+ if ((pos == max) && !m_eof) {
+ if (!m_pos) { // line too big for our buffer
+ m_pos = pos;
+ m_needEol = true;
+ }
+ break;
+ }
+
+ if (!ProcessLine(m_pBuf + startPos, pos - startPos, pDone)) {
+ return false;
+ }
+ m_pos = pos;
+ }
+
+ return true;
+}
+
diff --git a/mailnews/import/src/nsImportScanFile.h b/mailnews/import/src/nsImportScanFile.h
new file mode 100644
index 000000000..abe5b1cdd
--- /dev/null
+++ b/mailnews/import/src/nsImportScanFile.h
@@ -0,0 +1,54 @@
+/* -*- 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/. */
+
+#ifndef nsImportScanFile_h__
+#define nsImportScanFile_h__
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+
+class nsImportScanFile {
+public:
+ nsImportScanFile();
+ virtual ~nsImportScanFile();
+
+ void InitScan(nsIInputStream *pInputStream, uint8_t * pBuf, uint32_t sz);
+
+ void CleanUpScan(void);
+
+ virtual bool Scan(bool *pDone);
+
+protected:
+ void ShiftBuffer(void);
+ bool FillBufferFromFile(void);
+ virtual bool ScanBuffer(bool *pDone);
+
+protected:
+ nsCOMPtr <nsIInputStream> m_pInputStream;
+ uint8_t * m_pBuf;
+ uint32_t m_bufSz;
+ uint32_t m_bytesInBuf;
+ uint32_t m_pos;
+ bool m_eof;
+ bool m_allocated;
+};
+
+class nsImportScanFileLines : public nsImportScanFile {
+public:
+ nsImportScanFileLines() {m_needEol = false;}
+
+ void ResetLineScan(void) { m_needEol = false;}
+
+ virtual bool ProcessLine(uint8_t * /* pLine */, uint32_t /* len */, bool * /* pDone */) {return true;}
+
+protected:
+ virtual bool ScanBuffer(bool *pDone) override;
+
+ bool m_needEol;
+
+};
+
+
+#endif /* nsImportScanFile_h__ */
diff --git a/mailnews/import/src/nsImportService.cpp b/mailnews/import/src/nsImportService.cpp
new file mode 100644
index 000000000..0013c1146
--- /dev/null
+++ b/mailnews/import/src/nsImportService.cpp
@@ -0,0 +1,583 @@
+/* -*- 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 "nsICharsetConverterManager.h"
+#include "nsIPlatformCharset.h"
+#include "nsICharsetConverterManager.h"
+
+#include "nsStringGlue.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsMemory.h"
+#include "nsIImportModule.h"
+#include "nsIImportService.h"
+#include "nsImportMailboxDescriptor.h"
+#include "nsImportABDescriptor.h"
+#include "nsIImportGeneric.h"
+#include "nsImportFieldMap.h"
+#include "nsICategoryManager.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "plstr.h"
+#include "prmem.h"
+#include "nsMsgCompCID.h"
+#include "nsThreadUtils.h"
+#include "nsIEditor.h"
+#include "ImportDebug.h"
+#include "nsImportService.h"
+#include "nsImportStringBundle.h"
+#include "nsCRTGlue.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIMutableArray.h"
+#include "nsIArray.h"
+#include "nsIMsgSend.h"
+#include "nsMsgUtils.h"
+
+PRLogModuleInfo *IMPORTLOGMODULE = nullptr;
+
+static nsIImportService * gImportService = nullptr;
+static const char * kWhitespace = "\b\t\r\n ";
+
+
+////////////////////////////////////////////////////////////////////////
+
+
+nsImportService::nsImportService() : m_pModules(nullptr)
+{
+ // Init logging module.
+ if (!IMPORTLOGMODULE)
+ IMPORTLOGMODULE = PR_NewLogModule("IMPORT");
+ IMPORT_LOG0("* nsImport Service Created\n");
+
+ m_didDiscovery = false;
+ m_pDecoder = nullptr;
+ m_pEncoder = nullptr;
+
+ nsresult rv = nsImportStringBundle::GetStringBundle(IMPORT_MSGS_URL, getter_AddRefs(m_stringBundle));
+ if (NS_FAILED(rv))
+ IMPORT_LOG0("Failed to get string bundle for Importing Mail");
+}
+
+
+nsImportService::~nsImportService()
+{
+ NS_IF_RELEASE(m_pDecoder);
+ NS_IF_RELEASE(m_pEncoder);
+
+ gImportService = nullptr;
+
+ if (m_pModules != nullptr)
+ delete m_pModules;
+
+ IMPORT_LOG0("* nsImport Service Deleted\n");
+}
+
+
+
+NS_IMPL_ISUPPORTS(nsImportService, nsIImportService)
+
+
+NS_IMETHODIMP nsImportService::DiscoverModules(void)
+{
+ m_didDiscovery = false;
+ return DoDiscover();
+}
+
+NS_IMETHODIMP nsImportService::CreateNewFieldMap(nsIImportFieldMap **_retval)
+{
+ return nsImportFieldMap::Create(m_stringBundle, nullptr, NS_GET_IID(nsIImportFieldMap), (void**)_retval);
+}
+
+NS_IMETHODIMP nsImportService::CreateNewMailboxDescriptor(nsIImportMailboxDescriptor **_retval)
+{
+ return nsImportMailboxDescriptor::Create(nullptr, NS_GET_IID(nsIImportMailboxDescriptor), (void**)_retval);
+}
+
+NS_IMETHODIMP nsImportService::CreateNewABDescriptor(nsIImportABDescriptor **_retval)
+{
+ return nsImportABDescriptor::Create(nullptr, NS_GET_IID(nsIImportABDescriptor), (void**)_retval);
+}
+
+extern nsresult NS_NewGenericMail(nsIImportGeneric** aImportGeneric);
+
+NS_IMETHODIMP nsImportService::CreateNewGenericMail(nsIImportGeneric **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (! _retval)
+ return NS_ERROR_NULL_POINTER;
+
+ return NS_NewGenericMail(_retval);
+}
+
+extern nsresult NS_NewGenericAddressBooks(nsIImportGeneric** aImportGeneric);
+
+NS_IMETHODIMP nsImportService::CreateNewGenericAddressBooks(nsIImportGeneric **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (! _retval)
+ return NS_ERROR_NULL_POINTER;
+
+ return NS_NewGenericAddressBooks(_retval);
+}
+
+
+NS_IMETHODIMP nsImportService::GetModuleCount(const char *filter, int32_t *_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (! _retval)
+ return NS_ERROR_NULL_POINTER;
+
+ DoDiscover();
+
+ if (m_pModules != nullptr) {
+ ImportModuleDesc * pDesc;
+ int32_t count = 0;
+ for (int32_t i = 0; i < m_pModules->GetCount(); i++) {
+ pDesc = m_pModules->GetModuleDesc(i);
+ if (pDesc->SupportsThings(filter))
+ count++;
+ }
+ *_retval = count;
+ }
+ else
+ *_retval = 0;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportService::GetModuleWithCID(const nsCID& cid, nsIImportModule **ppModule)
+{
+ NS_PRECONDITION(ppModule != nullptr, "null ptr");
+ if (!ppModule)
+ return NS_ERROR_NULL_POINTER;
+
+ *ppModule = nullptr;
+ nsresult rv = DoDiscover();
+ if (NS_FAILED(rv))
+ return rv;
+ if (m_pModules == nullptr)
+ return NS_ERROR_FAILURE;
+ int32_t cnt = m_pModules->GetCount();
+ ImportModuleDesc *pDesc;
+ for (int32_t i = 0; i < cnt; i++) {
+ pDesc = m_pModules->GetModuleDesc(i);
+ if (!pDesc)
+ return NS_ERROR_FAILURE;
+ if (pDesc->GetCID().Equals(cid)) {
+ *ppModule = pDesc->GetModule();
+
+ IMPORT_LOG0("* nsImportService::GetSpecificModule - attempted to load module\n");
+
+ if (*ppModule == nullptr)
+ return NS_ERROR_FAILURE;
+ return NS_OK;
+ }
+ }
+
+ IMPORT_LOG0("* nsImportService::GetSpecificModule - module not found\n");
+
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP nsImportService::GetModuleInfo(const char *filter, int32_t index, char16_t **name, char16_t **moduleDescription)
+{
+ NS_PRECONDITION(name != nullptr, "null ptr");
+ NS_PRECONDITION(moduleDescription != nullptr, "null ptr");
+ if (!name || !moduleDescription)
+ return NS_ERROR_NULL_POINTER;
+
+ *name = nullptr;
+ *moduleDescription = nullptr;
+
+ DoDiscover();
+ if (!m_pModules)
+ return NS_ERROR_FAILURE;
+
+ if ((index < 0) || (index >= m_pModules->GetCount()))
+ return NS_ERROR_FAILURE;
+
+ ImportModuleDesc * pDesc;
+ int32_t count = 0;
+ for (int32_t i = 0; i < m_pModules->GetCount(); i++) {
+ pDesc = m_pModules->GetModuleDesc(i);
+ if (pDesc->SupportsThings(filter)) {
+ if (count == index) {
+ *name = NS_strdup(pDesc->GetName());
+ *moduleDescription = NS_strdup(pDesc->GetDescription());
+ return NS_OK;
+ }
+ else
+ count++;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP nsImportService::GetModuleName(const char *filter, int32_t index, char16_t **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = nullptr;
+
+ DoDiscover();
+ if (!m_pModules)
+ return NS_ERROR_FAILURE;
+
+ if ((index < 0) || (index >= m_pModules->GetCount()))
+ return NS_ERROR_FAILURE;
+
+ ImportModuleDesc * pDesc;
+ int32_t count = 0;
+ for (int32_t i = 0; i < m_pModules->GetCount(); i++) {
+ pDesc = m_pModules->GetModuleDesc(i);
+ if (pDesc->SupportsThings(filter)) {
+ if (count == index) {
+ *_retval = NS_strdup(pDesc->GetName());
+ return NS_OK;
+ }
+ else
+ count++;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+
+NS_IMETHODIMP nsImportService::GetModuleDescription(const char *filter, int32_t index, char16_t **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ *_retval = nullptr;
+
+ DoDiscover();
+ if (!m_pModules)
+ return NS_ERROR_FAILURE;
+
+ if ((index < 0) || (index >= m_pModules->GetCount()))
+ return NS_ERROR_FAILURE;
+
+ ImportModuleDesc * pDesc;
+ int32_t count = 0;
+ for (int32_t i = 0; i < m_pModules->GetCount(); i++) {
+ pDesc = m_pModules->GetModuleDesc(i);
+ if (pDesc->SupportsThings(filter)) {
+ if (count == index) {
+ *_retval = NS_strdup(pDesc->GetDescription());
+ return NS_OK;
+ }
+ else
+ count++;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+class nsProxySendRunnable : public mozilla::Runnable
+{
+public:
+ nsProxySendRunnable(nsIMsgIdentity *aIdentity,
+ nsIMsgCompFields *aMsgFields,
+ const char *attachment1_type,
+ const nsACString &attachment1_body,
+ bool aIsDraft,
+ nsIArray *aLoadedAttachments,
+ nsIArray *aEmbeddedAttachments,
+ nsIMsgSendListener *aListener);
+ NS_DECL_NSIRUNNABLE
+private:
+ nsCOMPtr<nsIMsgIdentity> m_identity;
+ nsCOMPtr<nsIMsgCompFields> m_compFields;
+ bool m_isDraft;
+ nsCString m_bodyType;
+ nsCString m_body;
+ nsCOMPtr<nsIArray> m_loadedAttachments;
+ nsCOMPtr<nsIArray> m_embeddedAttachments;
+ nsCOMPtr<nsIMsgSendListener> m_listener;
+
+};
+
+nsProxySendRunnable::nsProxySendRunnable(nsIMsgIdentity *aIdentity,
+ nsIMsgCompFields *aMsgFields,
+ const char *aBodyType,
+ const nsACString &aBody,
+ bool aIsDraft,
+ nsIArray *aLoadedAttachments,
+ nsIArray *aEmbeddedAttachments,
+ nsIMsgSendListener *aListener) :
+ m_identity(aIdentity), m_compFields(aMsgFields),
+ m_isDraft(aIsDraft), m_bodyType(aBodyType),
+ m_body(aBody), m_loadedAttachments(aLoadedAttachments),
+ m_embeddedAttachments(aEmbeddedAttachments),
+ m_listener(aListener)
+{
+}
+
+NS_IMETHODIMP nsProxySendRunnable::Run()
+{
+ nsresult rv;
+ nsCOMPtr<nsIMsgSend> msgSend = do_CreateInstance(NS_MSGSEND_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return msgSend->CreateRFC822Message(m_identity, m_compFields,
+ m_bodyType.get(), m_body,
+ m_isDraft, m_loadedAttachments,
+ m_embeddedAttachments,
+ m_listener);
+}
+
+
+NS_IMETHODIMP
+nsImportService::CreateRFC822Message(nsIMsgIdentity *aIdentity,
+ nsIMsgCompFields *aMsgFields,
+ const char *aBodyType,
+ const nsACString &aBody,
+ bool aIsDraft,
+ nsIArray *aLoadedAttachments,
+ nsIArray *aEmbeddedAttachments,
+ nsIMsgSendListener *aListener)
+{
+ RefPtr<nsProxySendRunnable> runnable =
+ new nsProxySendRunnable(aIdentity,
+ aMsgFields,
+ aBodyType,
+ aBody,
+ aIsDraft,
+ aLoadedAttachments,
+ aEmbeddedAttachments,
+ aListener);
+ // invoke the callback
+ return NS_DispatchToMainThread(runnable);
+}
+
+NS_IMETHODIMP nsImportService::GetModule(const char *filter, int32_t index, nsIImportModule **_retval)
+{
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (!_retval)
+ return NS_ERROR_NULL_POINTER;
+ *_retval = nullptr;
+
+ DoDiscover();
+ if (!m_pModules)
+ return NS_ERROR_FAILURE;
+
+ if ((index < 0) || (index >= m_pModules->GetCount()))
+ return NS_ERROR_FAILURE;
+
+ ImportModuleDesc * pDesc;
+ int32_t count = 0;
+ for (int32_t i = 0; i < m_pModules->GetCount(); i++) {
+ pDesc = m_pModules->GetModuleDesc(i);
+ if (pDesc->SupportsThings(filter)) {
+ if (count == index) {
+ *_retval = pDesc->GetModule();
+ break;
+ }
+ else
+ count++;
+ }
+ }
+ if (! (*_retval))
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+
+nsresult nsImportService::DoDiscover(void)
+{
+ if (m_didDiscovery)
+ return NS_OK;
+
+ if (m_pModules != nullptr)
+ m_pModules->ClearList();
+
+ nsresult rv;
+
+ nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsISimpleEnumerator> e;
+ rv = catMan->EnumerateCategory("mailnewsimport", getter_AddRefs(e));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsISupports> supports;
+ nsCOMPtr<nsISupportsCString> contractid;
+ rv = e->GetNext(getter_AddRefs(supports));
+ while (NS_SUCCEEDED(rv) && supports)
+ {
+ contractid = do_QueryInterface(supports);
+ if (!contractid)
+ break;
+
+ nsCString contractIdStr;
+ contractid->ToString(getter_Copies(contractIdStr));
+ nsCString supportsStr;
+ rv = catMan->GetCategoryEntry("mailnewsimport", contractIdStr.get(), getter_Copies(supportsStr));
+ if (NS_SUCCEEDED(rv))
+ LoadModuleInfo(contractIdStr.get(), supportsStr.get());
+ rv = e->GetNext(getter_AddRefs(supports));
+ }
+
+ m_didDiscovery = true;
+
+ return NS_OK;
+}
+
+nsresult nsImportService::LoadModuleInfo(const char *pClsId, const char *pSupports)
+{
+ if (!pClsId || !pSupports)
+ return NS_OK;
+
+ if (m_pModules == nullptr)
+ m_pModules = new nsImportModuleList();
+
+ // load the component and get all of the info we need from it....
+ // then call AddModule
+ nsresult rv;
+
+ nsCID clsId;
+ clsId.Parse(pClsId);
+ nsIImportModule * module;
+ rv = CallCreateInstance(clsId, &module);
+ if (NS_FAILED(rv)) return rv;
+
+ nsString theTitle;
+ nsString theDescription;
+ rv = module->GetName(getter_Copies(theTitle));
+ if (NS_FAILED(rv))
+ theTitle.AssignLiteral("Unknown");
+
+ rv = module->GetDescription(getter_Copies(theDescription));
+ if (NS_FAILED(rv))
+ theDescription.AssignLiteral("Unknown description");
+
+ // call the module to get the info we need
+ m_pModules->AddModule(clsId, pSupports, theTitle.get(), theDescription.get());
+
+ module->Release();
+
+ return NS_OK;
+}
+
+
+nsIImportModule *ImportModuleDesc::GetModule(bool keepLoaded)
+{
+ if (m_pModule)
+ {
+ m_pModule->AddRef();
+ return m_pModule;
+ }
+
+ nsresult rv;
+ rv = CallCreateInstance(m_cid, &m_pModule);
+ if (NS_FAILED(rv))
+ {
+ m_pModule = nullptr;
+ return nullptr;
+ }
+
+ if (keepLoaded)
+ {
+ m_pModule->AddRef();
+ return m_pModule;
+ }
+ else
+ {
+ nsIImportModule *pModule = m_pModule;
+ m_pModule = nullptr;
+ return pModule;
+ }
+}
+
+void ImportModuleDesc::ReleaseModule(void)
+{
+ if (m_pModule)
+ {
+ m_pModule->Release();
+ m_pModule = nullptr;
+ }
+}
+
+bool ImportModuleDesc::SupportsThings(const char *pThings)
+{
+ if (!pThings || !*pThings)
+ return true;
+
+ nsCString thing(pThings);
+ nsCString item;
+ int32_t idx;
+
+ while ((idx = thing.FindChar(',')) != -1)
+ {
+ item = StringHead(thing, idx);
+ item.Trim(kWhitespace);
+ ToLowerCase(item);
+ if (item.Length() && (m_supports.Find(item) == -1))
+ return false;
+ thing = Substring(thing, idx + 1);
+ }
+ thing.Trim(kWhitespace);
+ ToLowerCase(thing);
+ return thing.IsEmpty() || (m_supports.Find(thing) != -1);
+}
+
+void nsImportModuleList::ClearList(void)
+{
+ if (m_pList)
+ {
+ for (int i = 0; i < m_count; i++)
+ {
+ delete m_pList[i];
+ m_pList[i] = nullptr;
+ }
+ m_count = 0;
+ delete [] m_pList;
+ m_pList = nullptr;
+ m_alloc = 0;
+ }
+
+}
+
+void nsImportModuleList::AddModule(const nsCID& cid, const char *pSupports, const char16_t *pName, const char16_t *pDesc)
+{
+ if (!m_pList)
+ {
+ m_alloc = 10;
+ m_pList = new ImportModuleDesc *[m_alloc];
+ m_count = 0;
+ memset(m_pList, 0, sizeof(ImportModuleDesc *) * m_alloc);
+ }
+
+ if (m_count == m_alloc)
+ {
+ ImportModuleDesc **pList = new ImportModuleDesc *[m_alloc + 10];
+ memset(&(pList[m_alloc]), 0, sizeof(ImportModuleDesc *) * 10);
+ memcpy(pList, m_pList, sizeof(ImportModuleDesc *) * m_alloc);
+ for(int i = 0; i < m_count; i++)
+ delete m_pList[i];
+ delete [] m_pList;
+ m_pList = pList;
+ m_alloc += 10;
+ }
+
+ m_pList[m_count] = new ImportModuleDesc();
+ m_pList[m_count]->SetCID(cid);
+ m_pList[m_count]->SetSupports(pSupports);
+ m_pList[m_count]->SetName(pName);
+ m_pList[m_count]->SetDescription(pDesc);
+
+ m_count++;
+#ifdef IMPORT_DEBUG
+ IMPORT_LOG3("* nsImportService registered import module: %s, %s, %s\n", NS_LossyConvertUTF16toASCII(pName).get(), NS_LossyConvertUTF16toASCII(pDesc).get(), pSupports);
+#endif
+}
+
diff --git a/mailnews/import/src/nsImportService.h b/mailnews/import/src/nsImportService.h
new file mode 100644
index 000000000..889cfa6c4
--- /dev/null
+++ b/mailnews/import/src/nsImportService.h
@@ -0,0 +1,96 @@
+/* -*- 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/. */
+
+#ifndef nsImportService_h__
+#define nsImportService_h__
+
+#include "nsICharsetConverterManager.h"
+
+#include "nsStringGlue.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsMemory.h"
+#include "nsIImportModule.h"
+#include "nsIImportService.h"
+#include "nsICategoryManager.h"
+#include "nsIStringBundle.h"
+
+class nsImportModuleList;
+
+class nsImportService : public nsIImportService
+{
+public:
+
+ nsImportService();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ NS_DECL_NSIIMPORTSERVICE
+
+private:
+ virtual ~nsImportService();
+ nsresult LoadModuleInfo(const char*pClsId, const char *pSupports);
+ nsresult DoDiscover(void);
+
+private:
+ nsImportModuleList * m_pModules;
+ bool m_didDiscovery;
+ nsCString m_sysCharset;
+ nsIUnicodeDecoder * m_pDecoder;
+ nsIUnicodeEncoder * m_pEncoder;
+ nsCOMPtr<nsIStringBundle> m_stringBundle;
+};
+
+class ImportModuleDesc {
+public:
+ ImportModuleDesc() { m_pModule = nullptr;}
+ ~ImportModuleDesc() { ReleaseModule(); }
+
+ void SetCID(const nsCID& cid) { m_cid = cid;}
+ void SetName(const char16_t *pName) { m_name = pName;}
+ void SetDescription(const char16_t *pDesc) { m_description = pDesc;}
+ void SetSupports(const char *pSupports) { m_supports = pSupports;}
+
+ nsCID GetCID(void) { return m_cid;}
+ const char16_t *GetName(void) { return m_name.get();}
+ const char16_t *GetDescription(void) { return m_description.get();}
+ const char * GetSupports(void) { return m_supports.get();}
+
+ nsIImportModule * GetModule(bool keepLoaded = false); // Adds ref
+ void ReleaseModule(void);
+
+ bool SupportsThings(const char *pThings);
+
+private:
+ nsCID m_cid;
+ nsString m_name;
+ nsString m_description;
+ nsCString m_supports;
+ nsIImportModule *m_pModule;
+};
+
+class nsImportModuleList {
+public:
+ nsImportModuleList() { m_pList = nullptr; m_alloc = 0; m_count = 0;}
+ ~nsImportModuleList() { ClearList(); }
+
+ void AddModule(const nsCID& cid, const char *pSupports, const char16_t *pName, const char16_t *pDesc);
+
+ void ClearList(void);
+
+ int32_t GetCount(void) { return m_count;}
+
+ ImportModuleDesc * GetModuleDesc(int32_t idx)
+ { if ((idx < 0) || (idx >= m_count)) return nullptr; else return m_pList[idx];}
+
+private:
+
+private:
+ ImportModuleDesc ** m_pList;
+ int32_t m_alloc;
+ int32_t m_count;
+};
+
+#endif // nsImportService_h__
diff --git a/mailnews/import/src/nsImportStringBundle.cpp b/mailnews/import/src/nsImportStringBundle.cpp
new file mode 100644
index 000000000..3adb6655a
--- /dev/null
+++ b/mailnews/import/src/nsImportStringBundle.cpp
@@ -0,0 +1,80 @@
+/* -*- 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 "nsIStringBundle.h"
+#include "nsImportStringBundle.h"
+#include "nsIServiceManager.h"
+#include "nsIURI.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/Services.h"
+
+nsresult nsImportStringBundle::GetStringBundle(const char *aPropertyURL,
+ nsIStringBundle **aBundle)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIStringBundleService> sBundleService =
+ mozilla::services::GetStringBundleService();
+ NS_ENSURE_TRUE(sBundleService, NS_ERROR_UNEXPECTED);
+ rv = sBundleService->CreateBundle(aPropertyURL, aBundle);
+
+ return rv;
+}
+
+void nsImportStringBundle::GetStringByID(int32_t aStringID,
+ nsIStringBundle *aBundle,
+ nsString &aResult)
+{
+ aResult.Adopt(GetStringByID(aStringID, aBundle));
+}
+
+char16_t *nsImportStringBundle::GetStringByID(int32_t aStringID,
+ nsIStringBundle *aBundle)
+{
+ if (aBundle)
+ {
+ char16_t *ptrv = nullptr;
+ nsresult rv = aBundle->GetStringFromID(aStringID, &ptrv);
+
+ if (NS_SUCCEEDED(rv) && ptrv)
+ return ptrv;
+ }
+
+ nsString resultString(NS_LITERAL_STRING("[StringID "));
+ resultString.AppendInt(aStringID);
+ resultString.AppendLiteral("?]");
+
+ return ToNewUnicode(resultString);
+}
+
+void nsImportStringBundle::GetStringByName(const char *aName,
+ nsIStringBundle *aBundle,
+ nsString &aResult)
+{
+ aResult.Adopt(GetStringByName(aName, aBundle));
+}
+
+char16_t *nsImportStringBundle::GetStringByName(const char *aName,
+ nsIStringBundle *aBundle)
+{
+ if (aBundle)
+ {
+ char16_t *ptrv = nullptr;
+ nsresult rv = aBundle->GetStringFromName(
+ NS_ConvertUTF8toUTF16(aName).get(), &ptrv);
+
+ if (NS_SUCCEEDED(rv) && ptrv)
+ return ptrv;
+ }
+
+ nsString resultString(NS_LITERAL_STRING("[StringName "));
+ resultString.Append(NS_ConvertUTF8toUTF16(aName).get());
+ resultString.AppendLiteral("?]");
+
+ return ToNewUnicode(resultString);
+}
diff --git a/mailnews/import/src/nsImportStringBundle.h b/mailnews/import/src/nsImportStringBundle.h
new file mode 100644
index 000000000..c9db012e6
--- /dev/null
+++ b/mailnews/import/src/nsImportStringBundle.h
@@ -0,0 +1,48 @@
+/* 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 _nsImportStringBundle_H__
+#define _nsImportStringBundle_H__
+
+#include "nsStringGlue.h"
+
+class nsIStringBundle;
+
+class nsImportStringBundle
+{
+public:
+ static char16_t* GetStringByID(int32_t aStringID,
+ nsIStringBundle *aBundle = nullptr);
+ static void GetStringByID(int32_t aStringID,
+ nsIStringBundle *aBundle,
+ nsString &aResult);
+ static char16_t* GetStringByName(const char *aName,
+ nsIStringBundle *aBundle = nullptr);
+ static void GetStringByName(const char *aName,
+ nsIStringBundle *aBundle,
+ nsString &aResult);
+ static nsresult GetStringBundle(const char *aPropertyURL,
+ nsIStringBundle **aBundle);
+};
+
+#define IMPORT_MSGS_URL "chrome://messenger/locale/importMsgs.properties"
+
+
+#define IMPORT_NO_ADDRBOOKS 2000
+#define IMPORT_ERROR_AB_NOTINITIALIZED 2001
+#define IMPORT_ERROR_AB_NOTHREAD 2002
+#define IMPORT_ERROR_GETABOOK 2003
+#define IMPORT_NO_MAILBOXES 2004
+#define IMPORT_ERROR_MB_NOTINITIALIZED 2005
+#define IMPORT_ERROR_MB_NOTHREAD 2006
+#define IMPORT_ERROR_MB_NOPROXY 2007
+#define IMPORT_ERROR_MB_FINDCHILD 2008
+#define IMPORT_ERROR_MB_CREATE 2009
+#define IMPORT_ERROR_MB_NODESTFOLDER 2010
+
+#define IMPORT_FIELD_DESC_START 2100
+#define IMPORT_FIELD_DESC_END 2136
+
+
+#endif /* _nsImportStringBundle_H__ */
diff --git a/mailnews/import/src/nsImportTranslator.cpp b/mailnews/import/src/nsImportTranslator.cpp
new file mode 100644
index 000000000..beec8b93a
--- /dev/null
+++ b/mailnews/import/src/nsImportTranslator.cpp
@@ -0,0 +1,296 @@
+/* -*- 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/. */
+
+#include "ImportOutFile.h"
+#include "nsImportTranslator.h"
+
+#include "ImportCharSet.h"
+
+
+bool nsImportTranslator::ConvertToFile(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed)
+{
+ if (pProcessed)
+ *pProcessed = inLen;
+ return (pOutFile->WriteData(pIn, inLen));
+}
+
+void CMHTranslator::ConvertBuffer(const uint8_t * pIn, uint32_t inLen, uint8_t * pOut)
+{
+ while (inLen) {
+ if (!ImportCharSet::IsUSAscii(*pIn) || ImportCharSet::Is822SpecialChar(*pIn) || ImportCharSet::Is822CtlChar(*pIn) ||
+ (*pIn == ImportCharSet::cSpaceChar) || (*pIn == '*') || (*pIn == '\'') ||
+ (*pIn == '%')) {
+ // needs to be encode as %hex val
+ *pOut = '%'; pOut++;
+ ImportCharSet::ByteToHex(*pIn, pOut);
+ pOut += 2;
+ }
+ else {
+ *pOut = *pIn;
+ pOut++;
+ }
+ pIn++; inLen--;
+ }
+ *pOut = 0;
+}
+
+bool CMHTranslator::ConvertToFile(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed)
+{
+ uint8_t hex[2];
+ while (inLen) {
+ if (!ImportCharSet::IsUSAscii(*pIn) || ImportCharSet::Is822SpecialChar(*pIn) || ImportCharSet::Is822CtlChar(*pIn) ||
+ (*pIn == ImportCharSet::cSpaceChar) || (*pIn == '*') || (*pIn == '\'') ||
+ (*pIn == '%')) {
+ // needs to be encode as %hex val
+ if (!pOutFile->WriteByte('%'))
+ return false;
+ ImportCharSet::ByteToHex(*pIn, hex);
+ if (!pOutFile->WriteData(hex, 2))
+ return false;
+ }
+ else {
+ if (!pOutFile->WriteByte(*pIn))
+ return false;
+ }
+ pIn++; inLen--;
+ }
+
+ if (pProcessed)
+ *pProcessed = inLen;
+
+ return true;
+}
+
+
+bool C2047Translator::ConvertToFileQ(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed)
+{
+ if (!inLen)
+ return true;
+
+ int maxLineLen = 64;
+ int curLineLen = m_startLen;
+ bool startLine = true;
+
+ uint8_t hex[2];
+ while (inLen) {
+ if (startLine) {
+ if (!pOutFile->WriteStr(" =?"))
+ return false;
+ if (!pOutFile->WriteStr(m_charset.get()))
+ return false;
+ if (!pOutFile->WriteStr("?q?"))
+ return false;
+ curLineLen += (6 + m_charset.Length());
+ startLine = false;
+ }
+
+ if (!ImportCharSet::IsUSAscii(*pIn) || ImportCharSet::Is822SpecialChar(*pIn) || ImportCharSet::Is822CtlChar(*pIn) ||
+ (*pIn == ImportCharSet::cSpaceChar) || (*pIn == '?') || (*pIn == '=')) {
+ // needs to be encode as =hex val
+ if (!pOutFile->WriteByte('='))
+ return false;
+ ImportCharSet::ByteToHex(*pIn, hex);
+ if (!pOutFile->WriteData(hex, 2))
+ return false;
+ curLineLen += 3;
+ }
+ else {
+ if (!pOutFile->WriteByte(*pIn))
+ return false;
+ curLineLen++;
+ }
+ pIn++; inLen--;
+ if (curLineLen > maxLineLen) {
+ if (!pOutFile->WriteStr("?="))
+ return false;
+ if (inLen) {
+ if (!pOutFile->WriteStr("\x0D\x0A "))
+ return false;
+ }
+
+ startLine = true;
+ curLineLen = 0;
+ }
+ }
+
+ if (!startLine) {
+ // end the encoding!
+ if (!pOutFile->WriteStr("?="))
+ return false;
+ }
+
+ if (pProcessed)
+ *pProcessed = inLen;
+
+ return true;
+}
+
+bool C2047Translator::ConvertToFile(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed)
+{
+ if (m_useQuotedPrintable)
+ return ConvertToFileQ(pIn, inLen, pOutFile, pProcessed);
+
+ if (!inLen)
+ return true;
+
+ int maxLineLen = 64;
+ int curLineLen = m_startLen;
+ bool startLine = true;
+ int encodeMax;
+ uint8_t * pEncoded = new uint8_t[maxLineLen * 2];
+
+ while (inLen) {
+ if (startLine) {
+ if (!pOutFile->WriteStr(" =?")) {
+ delete [] pEncoded;
+ return false;
+ }
+ if (!pOutFile->WriteStr(m_charset.get())) {
+ delete [] pEncoded;
+ return false;
+ }
+ if (!pOutFile->WriteStr("?b?")) {
+ delete [] pEncoded;
+ return false;
+ }
+ curLineLen += (6 + m_charset.Length());
+ startLine = false;
+ }
+ encodeMax = maxLineLen - curLineLen;
+ encodeMax *= 3;
+ encodeMax /= 4;
+ if ((uint32_t)encodeMax > inLen)
+ encodeMax = (int)inLen;
+
+ // encode the line, end the line
+ // then continue. Update curLineLen, pIn, startLine, and inLen
+ UMimeEncode::ConvertBuffer(pIn, encodeMax, pEncoded, maxLineLen, maxLineLen, "\x0D\x0A");
+
+ if (!pOutFile->WriteStr((const char *)pEncoded)) {
+ delete [] pEncoded;
+ return false;
+ }
+
+ pIn += encodeMax;
+ inLen -= encodeMax;
+ startLine = true;
+ curLineLen = 0;
+ if (!pOutFile->WriteStr("?=")) {
+ delete [] pEncoded;
+ return false;
+ }
+ if (inLen) {
+ if (!pOutFile->WriteStr("\x0D\x0A ")) {
+ delete [] pEncoded;
+ return false;
+ }
+ }
+ }
+
+ delete [] pEncoded;
+
+ if (pProcessed)
+ *pProcessed = inLen;
+
+ return true;
+}
+
+
+uint32_t UMimeEncode::GetBufferSize(uint32_t inBytes)
+{
+ // it takes 4 base64 bytes to represent 3 regular bytes
+ inBytes += 3;
+ inBytes /= 3;
+ inBytes *= 4;
+ // This should be plenty, but just to be safe
+ inBytes += 4;
+
+ // now allow for end of line characters
+ inBytes += ((inBytes + 39) / 40) * 4;
+
+ return inBytes;
+}
+
+static uint8_t gBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+uint32_t UMimeEncode::ConvertBuffer(const uint8_t * pIn, uint32_t inLen, uint8_t * pOut, uint32_t maxLen, uint32_t firstLineLen, const char * pEolStr)
+{
+
+ uint32_t pos = 0;
+ uint32_t len = 0;
+ uint32_t lineLen = 0;
+ uint32_t maxLine = firstLineLen;
+ int eolLen = 0;
+ if (pEolStr)
+ eolLen = strlen(pEolStr);
+
+ while ((pos + 2) < inLen) {
+ // Encode 3 bytes
+ *pOut = gBase64[*pIn >> 2];
+ pOut++; len++; lineLen++;
+ *pOut = gBase64[(((*pIn) & 0x3)<< 4) | (((*(pIn + 1)) & 0xF0) >> 4)];
+ pIn++; pOut++; len++; lineLen++;
+ *pOut = gBase64[(((*pIn) & 0xF) << 2) | (((*(pIn + 1)) & 0xC0) >>6)];
+ pIn++; pOut++; len++; lineLen++;
+ *pOut = gBase64[(*pIn) & 0x3F];
+ pIn++; pOut++; len++; lineLen++;
+ pos += 3;
+ if (lineLen >= maxLine) {
+ lineLen = 0;
+ maxLine = maxLen;
+ if (pEolStr) {
+ memcpy(pOut, pEolStr, eolLen);
+ pOut += eolLen;
+ len += eolLen;
+ }
+ }
+ }
+
+ if ((pos < inLen) && ((lineLen + 3) > maxLine)) {
+ lineLen = 0;
+ maxLine = maxLen;
+ if (pEolStr) {
+ memcpy(pOut, pEolStr, eolLen);
+ pOut += eolLen;
+ len += eolLen;
+ }
+ }
+
+ if (pos < inLen) {
+ // Get the last few bytes!
+ *pOut = gBase64[*pIn >> 2];
+ pOut++; len++;
+ pos++;
+ if (pos < inLen) {
+ *pOut = gBase64[(((*pIn) & 0x3)<< 4) | (((*(pIn + 1)) & 0xF0) >> 4)];
+ pIn++; pOut++; pos++; len++;
+ if (pos < inLen) {
+ // Should be dead code!! (Then why is it here doofus?)
+ *pOut = gBase64[(((*pIn) & 0xF) << 2) | (((*(pIn + 1)) & 0xC0) >>6)];
+ pIn++; pOut++; len++;
+ *pOut = gBase64[(*pIn) & 0x3F];
+ pos++; pOut++; len++;
+ }
+ else {
+ *pOut = gBase64[(((*pIn) & 0xF) << 2)];
+ pOut++; len++;
+ *pOut = '=';
+ pOut++; len++;
+ }
+ }
+ else {
+ *pOut = gBase64[(((*pIn) & 0x3)<< 4)];
+ pOut++; len++;
+ *pOut = '=';
+ pOut++; len++;
+ *pOut = '=';
+ pOut++; len++;
+ }
+ }
+
+ *pOut = 0;
+
+ return len;
+}
diff --git a/mailnews/import/src/nsImportTranslator.h b/mailnews/import/src/nsImportTranslator.h
new file mode 100644
index 000000000..998616063
--- /dev/null
+++ b/mailnews/import/src/nsImportTranslator.h
@@ -0,0 +1,66 @@
+/* -*- 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/. */
+
+#ifndef nsImportTranslator_h___
+#define nsImportTranslator_h___
+
+#include "mozilla/Attributes.h"
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsCOMPtr.h"
+
+class ImportOutFile;
+
+class UMimeEncode {
+public:
+ static uint32_t GetBufferSize(uint32_t inByes);
+ static uint32_t ConvertBuffer(const uint8_t * pIn, uint32_t inLen, uint8_t *pOut, uint32_t maxLen = 72, uint32_t firstLineLen = 72, const char * pEolStr = nullptr);
+};
+
+
+class nsImportTranslator {
+public:
+ virtual ~nsImportTranslator() {}
+ virtual bool Supports8bitEncoding(void) { return false;}
+ virtual uint32_t GetMaxBufferSize(uint32_t inLen) { return inLen + 1;}
+ virtual void ConvertBuffer(const uint8_t * pIn, uint32_t inLen, uint8_t * pOut) { memcpy(pOut, pIn, inLen); pOut[inLen] = 0;}
+ virtual bool ConvertToFile(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed = nullptr);
+ virtual bool FinishConvertToFile(ImportOutFile * /* pOutFile */) { return true;}
+
+ virtual void GetCharset(nsCString& charSet) { charSet = "us-ascii";}
+ virtual void GetLanguage(nsCString& lang) { lang = "en";}
+ virtual void GetEncoding(nsCString& encoding) { encoding.Truncate();}
+};
+
+// Specialized encoder, not a vaild language translator, used for Mime headers.
+// rfc2231
+class CMHTranslator : public nsImportTranslator {
+public:
+ virtual uint32_t GetMaxBufferSize(uint32_t inLen) override { return (inLen * 3) + 1;}
+ virtual void ConvertBuffer(const uint8_t * pIn, uint32_t inLen, uint8_t * pOut) override;
+ virtual bool ConvertToFile(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed = nullptr) override;
+};
+
+// Specialized encoder, not a vaild language translator, used for mail headers
+// rfc2047
+class C2047Translator : public nsImportTranslator {
+public:
+ virtual ~C2047Translator() {}
+
+ C2047Translator(const char *pCharset, uint32_t headerLen) { m_charset = pCharset; m_startLen = headerLen; m_useQuotedPrintable = false;}
+
+ void SetUseQuotedPrintable(void) { m_useQuotedPrintable = true;}
+
+ virtual bool ConvertToFile(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed = nullptr) override;
+ bool ConvertToFileQ(const uint8_t * pIn, uint32_t inLen, ImportOutFile *pOutFile, uint32_t *pProcessed);
+
+protected:
+ bool m_useQuotedPrintable;
+ nsCString m_charset;
+ uint32_t m_startLen;
+};
+
+#endif /* nsImportTranslator_h__ */
+