summaryrefslogtreecommitdiffstats
path: root/mailnews/import/text
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/import/text')
-rw-r--r--mailnews/import/text/src/TextDebugLog.h21
-rw-r--r--mailnews/import/text/src/moz.build16
-rw-r--r--mailnews/import/text/src/nsTextAddress.cpp470
-rw-r--r--mailnews/import/text/src/nsTextAddress.h57
-rw-r--r--mailnews/import/text/src/nsTextImport.cpp714
-rw-r--r--mailnews/import/text/src/nsTextImport.h39
6 files changed, 1317 insertions, 0 deletions
diff --git a/mailnews/import/text/src/TextDebugLog.h b/mailnews/import/text/src/TextDebugLog.h
new file mode 100644
index 000000000..3f9bf1ec4
--- /dev/null
+++ b/mailnews/import/text/src/TextDebugLog.h
@@ -0,0 +1,21 @@
+/* -*- 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 TextDebugLog_h___
+#define TextDebugLog_h___
+
+// Use PR_LOG for logging.
+#include "mozilla/Logging.h"
+extern PRLogModuleInfo *TEXTIMPORTLOGMODULE; // Logging module
+
+#define IMPORT_LOG0(x) MOZ_LOG(TEXTIMPORTLOGMODULE, mozilla::LogLevel::Debug, (x))
+#define IMPORT_LOG1(x, y) MOZ_LOG(TEXTIMPORTLOGMODULE, mozilla::LogLevel::Debug, (x, y))
+#define IMPORT_LOG2(x, y, z) MOZ_LOG(TEXTIMPORTLOGMODULE, mozilla::LogLevel::Debug, (x, y, z))
+#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(TEXTIMPORTLOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d))
+
+
+
+#endif /* TextDebugLog_h___ */
diff --git a/mailnews/import/text/src/moz.build b/mailnews/import/text/src/moz.build
new file mode 100644
index 000000000..1bdbb07c9
--- /dev/null
+++ b/mailnews/import/text/src/moz.build
@@ -0,0 +1,16 @@
+# 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 += [
+ 'nsTextAddress.cpp',
+ 'nsTextImport.cpp',
+]
+
+FINAL_LIBRARY = 'import'
+
+LOCAL_INCLUDES += [
+ '../../src'
+]
+
diff --git a/mailnews/import/text/src/nsTextAddress.cpp b/mailnews/import/text/src/nsTextAddress.cpp
new file mode 100644
index 000000000..8a22498d2
--- /dev/null
+++ b/mailnews/import/text/src/nsTextAddress.cpp
@@ -0,0 +1,470 @@
+/* -*- 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 "nsTextAddress.h"
+#include "nsIAddrDatabase.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsIFile.h"
+#include "nsIInputStream.h"
+#include "nsILineInputStream.h"
+#include "nsNetUtil.h"
+#include "nsMsgI18N.h"
+#include "nsMsgUtils.h"
+#include "mdb.h"
+#include "nsIConverterInputStream.h"
+#include "nsIUnicharLineInputStream.h"
+#include "nsMsgUtils.h"
+
+#include "TextDebugLog.h"
+#include "plstr.h"
+#include "msgCore.h"
+
+#ifndef MOZILLA_INTERNAL_API
+#include "nsMsgI18N.h"
+#define NS_CopyNativeToUnicode(source, dest) \
+ nsMsgI18NConvertToUnicode(nsMsgI18NFileSystemCharset(), source, dest)
+#endif
+
+#define kWhitespace " \t\b\r\n"
+
+nsTextAddress::nsTextAddress()
+{
+ m_database = nullptr;
+ m_fieldMap = nullptr;
+ m_LFCount = 0;
+ m_CRCount = 0;
+}
+
+nsTextAddress::~nsTextAddress()
+{
+ NS_IF_RELEASE(m_database);
+ NS_IF_RELEASE(m_fieldMap);
+}
+
+nsresult nsTextAddress::GetUnicharLineStreamForFile(nsIFile *aFile,
+ nsIInputStream *aInputStream,
+ nsIUnicharLineInputStream **aStream)
+{
+ nsAutoCString charset;
+ nsresult rv = MsgDetectCharsetFromFile(aFile, charset);
+ if (NS_FAILED(rv)) {
+ charset.Assign(nsMsgI18NFileSystemCharset());
+ }
+
+ nsCOMPtr<nsIConverterInputStream> converterStream =
+ do_CreateInstance("@mozilla.org/intl/converter-input-stream;1", &rv);
+ if (NS_SUCCEEDED(rv)) {
+ rv = converterStream->Init(aInputStream,
+ charset.get(),
+ 8192,
+ nsIConverterInputStream::DEFAULT_REPLACEMENT_CHARACTER);
+ }
+
+ return CallQueryInterface(converterStream, aStream);
+}
+
+nsresult nsTextAddress::ImportAddresses(bool *pAbort, const char16_t *pName, nsIFile *pSrc, nsIAddrDatabase *pDb, nsIImportFieldMap *fieldMap, nsString& errors, uint32_t *pProgress)
+{
+ // Open the source file for reading, read each line and process it!
+ NS_IF_RELEASE(m_database);
+ NS_IF_RELEASE(m_fieldMap);
+ m_database = pDb;
+ m_fieldMap = fieldMap;
+ NS_ADDREF(m_fieldMap);
+ NS_ADDREF(m_database);
+
+ nsCOMPtr<nsIInputStream> inputStream;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), pSrc);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error opening address file for reading\n");
+ return rv;
+ }
+
+ // Here we use this to work out the size of the file, so we can update
+ // an integer as we go through the file which will update a progress
+ // bar if required by the caller.
+ uint64_t bytesLeft = 0;
+ rv = inputStream->Available(&bytesLeft);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error checking address file for size\n");
+ inputStream->Close();
+ return rv;
+ }
+
+ uint64_t totalBytes = bytesLeft;
+ bool skipRecord = false;
+
+ rv = m_fieldMap->GetSkipFirstRecord(&skipRecord);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error checking to see if we should skip the first record\n");
+ return rv;
+ }
+
+ nsCOMPtr<nsIUnicharLineInputStream> lineStream;
+ rv = GetUnicharLineStreamForFile(pSrc, inputStream, getter_AddRefs(lineStream));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error opening converter stream for importer\n");
+ return rv;
+ }
+
+ bool more = true;
+ nsAutoString line;
+
+ // Skip the first record if the user has requested it.
+ if (skipRecord)
+ rv = ReadRecord(lineStream, line, &more);
+
+ while (!(*pAbort) && more && NS_SUCCEEDED(rv)) {
+ // Read the line in
+ rv = ReadRecord(lineStream, line, &more);
+ if (NS_SUCCEEDED(rv)) {
+ // Now proces it to add it to the database
+ rv = ProcessLine(line, errors);
+
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error processing text record.\n");
+ }
+ }
+ if (NS_SUCCEEDED(rv) && pProgress) {
+ // This won't be totally accurate, but its the best we can do
+ // considering that lineStream won't give us how many bytes
+ // are actually left.
+ bytesLeft -= line.Length();
+ *pProgress = std::min(totalBytes - bytesLeft, uint64_t(PR_UINT32_MAX));
+ }
+ }
+
+ inputStream->Close();
+
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error reading the address book - probably incorrect ending\n");
+ return NS_ERROR_FAILURE;
+ }
+
+ return pDb->Commit(nsAddrDBCommitType::kLargeCommit);
+}
+
+nsresult nsTextAddress::ReadRecord(nsIUnicharLineInputStream *aLineStream,
+ nsAString &aLine,
+ bool *aMore)
+{
+ bool more = true;
+ uint32_t numQuotes = 0;
+ nsresult rv;
+ nsAutoString line;
+
+ // ensure aLine is empty
+ aLine.Truncate();
+
+ do {
+ if (!more) {
+ // No more, so we must have an incorrect file.
+ rv = NS_ERROR_FAILURE;
+ }
+ else {
+ // Read the line and append it
+ rv = aLineStream->ReadLine(line, &more);
+ if (NS_SUCCEEDED(rv)) {
+ if (!aLine.IsEmpty())
+ aLine.AppendLiteral(MSG_LINEBREAK);
+ aLine.Append(line);
+
+ numQuotes += MsgCountChar(line, char16_t('"'));
+ }
+ }
+ // Continue whilst everything is ok, and we have an odd number of quotes.
+ } while (NS_SUCCEEDED(rv) && (numQuotes % 2 != 0));
+
+ *aMore = more;
+ return rv;
+}
+
+nsresult nsTextAddress::ReadRecordNumber(nsIFile *aSrc, nsAString &aLine, int32_t rNum)
+{
+ nsCOMPtr<nsIInputStream> inputStream;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aSrc);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error opening address file for reading\n");
+ return rv;
+ }
+
+ int32_t rIndex = 0;
+ uint64_t bytesLeft = 0;
+
+ rv = inputStream->Available(&bytesLeft);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error checking address file for eof\n");
+ inputStream->Close();
+ return rv;
+ }
+
+ nsCOMPtr<nsIUnicharLineInputStream> lineStream;
+ rv = GetUnicharLineStreamForFile(aSrc, inputStream, getter_AddRefs(lineStream));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error opening converter stream for importer\n");
+ return rv;
+ }
+
+ bool more = true;
+
+ while (more && (rIndex <= rNum)) {
+ rv = ReadRecord(lineStream, aLine, &more);
+ if (NS_FAILED(rv)) {
+ inputStream->Close();
+ return rv;
+ }
+ if (rIndex == rNum) {
+ inputStream->Close();
+ return NS_OK;
+ }
+
+ rIndex++;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+int32_t nsTextAddress::CountFields(const nsAString &aLine, char16_t delim)
+{
+ int32_t pos = 0;
+ int32_t maxLen = aLine.Length();
+ int32_t count = 0;
+ char16_t tab = char16_t('\t');
+ char16_t doubleQuote = char16_t('"');
+
+ if (delim == tab)
+ tab = char16_t('\0');
+
+ while (pos < maxLen) {
+ while (((aLine[pos] == char16_t(' ')) || (aLine[pos] == tab)) &&
+ (pos < maxLen)) {
+ pos++;
+ }
+ if ((pos < maxLen) && (aLine[pos] == doubleQuote)) {
+ pos++;
+ while ((pos < maxLen) && (aLine[pos] != doubleQuote)) {
+ pos++;
+ if (((pos + 1) < maxLen) &&
+ (aLine[pos] == doubleQuote) &&
+ (aLine[pos + 1] == doubleQuote)) {
+ pos += 2;
+ }
+ }
+ if (pos < maxLen)
+ pos++;
+ }
+ while ((pos < maxLen) && (aLine[pos] != delim))
+ pos++;
+
+ count++;
+ pos++;
+ }
+
+ return count;
+}
+
+bool nsTextAddress::GetField(const nsAString &aLine,
+ int32_t index,
+ nsString &field,
+ char16_t delim)
+{
+ bool result = false;
+ int32_t pos = 0;
+ int32_t maxLen = aLine.Length();
+ char16_t tab = char16_t('\t');
+ char16_t doubleQuote = char16_t('"');
+
+ field.Truncate();
+
+ if (delim == tab)
+ tab = 0;
+
+ while (index && (pos < maxLen)) {
+ while (((aLine[pos] == char16_t(' ')) || (aLine[pos] == tab)) &&
+ (pos < maxLen)) {
+ pos++;
+ }
+ if (pos >= maxLen)
+ break;
+ if (aLine[pos] == doubleQuote) {
+ do {
+ pos++;
+ if (((pos + 1) < maxLen) &&
+ (aLine[pos] == doubleQuote) &&
+ (aLine[pos + 1] == doubleQuote)) {
+ pos += 2;
+ }
+ } while ((pos < maxLen) && (aLine[pos] != doubleQuote));
+ if (pos < maxLen)
+ pos++;
+ }
+ if (pos >= maxLen)
+ break;
+
+ while ((pos < maxLen) && (aLine[pos] != delim))
+ pos++;
+
+ if (pos >= maxLen)
+ break;
+
+ index--;
+ pos++;
+ }
+
+ if (pos >= maxLen)
+ return result;
+
+ result = true;
+
+ while ((pos < maxLen) && ((aLine[pos] == ' ') || (aLine[pos] == tab)))
+ pos++;
+
+ int32_t fLen = 0;
+ int32_t startPos = pos;
+ bool quoted = false;
+ if (aLine[pos] == '"') {
+ startPos++;
+ fLen = -1;
+ do {
+ pos++;
+ fLen++;
+ if (((pos + 1) < maxLen) &&
+ (aLine[pos] == doubleQuote) &&
+ (aLine[pos + 1] == doubleQuote)) {
+ quoted = true;
+ pos += 2;
+ fLen += 2;
+ }
+ } while ((pos < maxLen) && (aLine[pos] != doubleQuote));
+ }
+ else {
+ while ((pos < maxLen) && (aLine[pos] != delim)) {
+ pos++;
+ fLen++;
+ }
+ }
+
+ if (!fLen) {
+ return result;
+ }
+
+ field.Append(nsDependentSubstring(aLine, startPos, fLen));
+ field.Trim(kWhitespace);
+
+ if (quoted) {
+ int32_t offset = field.Find("\"\"");
+ while (offset != -1) {
+ field.Cut(offset, 1);
+ offset = MsgFind(field, "\"\"", false, offset + 1);
+ }
+ }
+
+ return result;
+}
+
+nsresult nsTextAddress::DetermineDelim(nsIFile *aSrc)
+{
+ nsCOMPtr<nsIInputStream> inputStream;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aSrc);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error opening address file for reading\n");
+ return rv;
+ }
+
+ int32_t lineCount = 0;
+ int32_t tabCount = 0;
+ int32_t commaCount = 0;
+ int32_t tabLines = 0;
+ int32_t commaLines = 0;
+ nsAutoString line;
+ bool more = true;
+
+ nsCOMPtr<nsIUnicharLineInputStream> lineStream;
+ rv = GetUnicharLineStreamForFile(aSrc, inputStream, getter_AddRefs(lineStream));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error opening converter stream for importer\n");
+ return rv;
+ }
+
+ while (more && NS_SUCCEEDED(rv) && (lineCount < 100)) {
+ rv = lineStream->ReadLine(line, &more);
+ if (NS_SUCCEEDED(rv)) {
+ tabCount = CountFields(line, char16_t('\t'));
+ commaCount = CountFields(line, char16_t(','));
+ if (tabCount > commaCount)
+ tabLines++;
+ else if (commaCount)
+ commaLines++;
+ }
+ lineCount++;
+ }
+
+ rv = inputStream->Close();
+
+ if (tabLines > commaLines)
+ m_delim = char16_t('\t');
+ else
+ m_delim = char16_t(',');
+
+ IMPORT_LOG2( "Tab count = %d, Comma count = %d\n", tabLines, commaLines);
+
+ return rv;
+}
+
+/*
+ This is where the real work happens!
+ Go through the field map and set the data in a new database row
+*/
+nsresult nsTextAddress::ProcessLine(const nsAString &aLine, nsString& errors)
+{
+ if (!m_fieldMap) {
+ IMPORT_LOG0("*** Error, text import needs a field map\n");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv;
+
+ // Wait until we get our first non-empty field, then create a new row,
+ // fill in the data, then add the row to the database.
+ nsCOMPtr<nsIMdbRow> newRow;
+ nsAutoString fieldVal;
+ int32_t fieldNum;
+ int32_t numFields = 0;
+ bool active;
+ rv = m_fieldMap->GetMapSize(&numFields);
+ for (int32_t i = 0; (i < numFields) && NS_SUCCEEDED(rv); i++) {
+ active = false;
+ rv = m_fieldMap->GetFieldMap(i, &fieldNum);
+ if (NS_SUCCEEDED(rv))
+ rv = m_fieldMap->GetFieldActive(i, &active);
+ if (NS_SUCCEEDED(rv) && active) {
+ if (GetField(aLine, i, fieldVal, m_delim)) {
+ if (!fieldVal.IsEmpty()) {
+ if (!newRow) {
+ rv = m_database->GetNewRow(getter_AddRefs(newRow));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error getting new address database row\n");
+ }
+ }
+ if (newRow) {
+ rv = m_fieldMap->SetFieldValue(m_database, newRow, fieldNum, fieldVal.get());
+ }
+ }
+ }
+ else
+ break;
+ }
+ else if (active) {
+ IMPORT_LOG1("*** Error getting field map for index %ld\n", (long) i);
+ }
+ }
+
+ if (NS_SUCCEEDED(rv) && newRow)
+ rv = m_database->AddCardRowToDB(newRow);
+
+ return rv;
+}
+
diff --git a/mailnews/import/text/src/nsTextAddress.h b/mailnews/import/text/src/nsTextAddress.h
new file mode 100644
index 000000000..69a311be4
--- /dev/null
+++ b/mailnews/import/text/src/nsTextAddress.h
@@ -0,0 +1,57 @@
+/* -*- 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 nsTextAddress_h__
+#define nsTextAddress_h__
+
+#include "nsCOMPtr.h"
+#include "nsStringGlue.h"
+#include "nsIImportFieldMap.h"
+#include "nsIImportService.h"
+
+class nsIAddrDatabase;
+class nsIFile;
+class nsIInputStream;
+class nsIUnicharLineInputStream;
+
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+
+class nsTextAddress {
+public:
+ nsTextAddress();
+ virtual ~nsTextAddress();
+
+ nsresult ImportAddresses(bool *pAbort, const char16_t *pName, nsIFile *pSrc, nsIAddrDatabase *pDb, nsIImportFieldMap *fieldMap, nsString& errors, uint32_t *pProgress);
+
+ nsresult DetermineDelim(nsIFile *pSrc);
+ char16_t GetDelim(void) { return m_delim; }
+
+ static nsresult ReadRecordNumber(nsIFile *pSrc, nsAString &aLine, int32_t rNum);
+ static bool GetField(const nsAString &aLine, int32_t index, nsString &field, char16_t delim);
+
+private:
+ nsresult ProcessLine(const nsAString &aLine, nsString &errors);
+
+ static int32_t CountFields(const nsAString &aLine, char16_t delim);
+ static nsresult ReadRecord(nsIUnicharLineInputStream *pSrc, nsAString &aLine, bool *aMore);
+ static nsresult GetUnicharLineStreamForFile(nsIFile *aFile,
+ nsIInputStream *aInputStream,
+ nsIUnicharLineInputStream **aStream);
+
+ char16_t m_delim;
+ int32_t m_LFCount;
+ int32_t m_CRCount;
+ nsIAddrDatabase *m_database;
+ nsIImportFieldMap *m_fieldMap;
+ nsCOMPtr<nsIImportService> m_pService;
+};
+
+
+
+#endif /* nsTextAddress_h__ */
+
diff --git a/mailnews/import/text/src/nsTextImport.cpp b/mailnews/import/text/src/nsTextImport.cpp
new file mode 100644
index 000000000..0b99e652b
--- /dev/null
+++ b/mailnews/import/text/src/nsTextImport.cpp
@@ -0,0 +1,714 @@
+/* -*- 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/. */
+
+
+/*
+
+ Text import addressbook interfaces
+
+*/
+#include "nscore.h"
+#include "nsIServiceManager.h"
+#include "nsCOMPtr.h"
+#include "nsIImportService.h"
+#include "nsMsgI18N.h"
+#include "nsIComponentManager.h"
+#include "nsTextImport.h"
+#include "nsIMemory.h"
+#include "nsIMutableArray.h"
+#include "nsIImportGeneric.h"
+#include "nsIImportAddressBooks.h"
+#include "nsIImportABDescriptor.h"
+#include "nsIImportFieldMap.h"
+#include "nsIOutputStream.h"
+#include "nsIAddrDatabase.h"
+#include "nsIAbLDIFService.h"
+#include "nsAbBaseCID.h"
+#include "nsTextFormatter.h"
+#include "nsImportStringBundle.h"
+#include "nsTextAddress.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "TextDebugLog.h"
+#include "nsNetUtil.h"
+#include "nsMsgUtils.h"
+
+#define TEXT_MSGS_URL "chrome://messenger/locale/textImportMsgs.properties"
+#define TEXTIMPORT_NAME 2000
+#define TEXTIMPORT_DESCRIPTION 2001
+#define TEXTIMPORT_ADDRESS_NAME 2002
+#define TEXTIMPORT_ADDRESS_SUCCESS 2003
+#define TEXTIMPORT_ADDRESS_BADPARAM 2004
+#define TEXTIMPORT_ADDRESS_BADSOURCEFILE 2005
+#define TEXTIMPORT_ADDRESS_CONVERTERROR 2006
+
+static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
+PRLogModuleInfo* TEXTIMPORTLOGMODULE;
+
+class ImportAddressImpl final : public nsIImportAddressBooks
+{
+public:
+ explicit ImportAddressImpl(nsIStringBundle* aStringBundle);
+
+ static nsresult Create(nsIImportAddressBooks** aImport,
+ nsIStringBundle *aStringBundle);
+
+ // nsISupports interface
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // nsIImportAddressBooks interface
+
+ NS_IMETHOD GetSupportsMultiple(bool *_retval) override { *_retval = false; return NS_OK;}
+
+ NS_IMETHOD GetAutoFind(char16_t **description, bool *_retval) override;
+
+ NS_IMETHOD GetNeedsFieldMap(nsIFile *location, bool *_retval) override;
+
+ NS_IMETHOD GetDefaultLocation(nsIFile **location, bool *found, bool *userVerify) override;
+
+ NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval) override;
+
+ NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap) override;
+
+ NS_IMETHOD ImportAddressBook(nsIImportABDescriptor *source,
+ nsIAddrDatabase *destination,
+ nsIImportFieldMap *fieldMap,
+ nsISupports *aSupportService,
+ char16_t **errorLog,
+ char16_t **successLog,
+ bool *fatalError) override;
+
+ NS_IMETHOD GetImportProgress(uint32_t *_retval) override;
+
+ NS_IMETHOD GetSampleData(int32_t index, bool *pFound, char16_t **pStr) override;
+
+ NS_IMETHOD SetSampleLocation(nsIFile *) override;
+
+private:
+ void ClearSampleFile(void);
+ void SaveFieldMap(nsIImportFieldMap *pMap);
+
+ static void ReportSuccess(nsString& name, nsString *pStream,
+ nsIStringBundle* pBundle);
+ static void SetLogs(nsString& success, nsString& error, char16_t **pError,
+ char16_t **pSuccess);
+ static void ReportError(int32_t errorNum, nsString& name, nsString *pStream,
+ nsIStringBundle* pBundle);
+ static void SanitizeSampleData(nsString& val);
+
+private:
+ ~ImportAddressImpl() {}
+ nsTextAddress m_text;
+ bool m_haveDelim;
+ nsCOMPtr<nsIFile> m_fileLoc;
+ nsCOMPtr<nsIStringBundle> m_notProxyBundle;
+ char16_t m_delim;
+ uint32_t m_bytesImported;
+};
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+nsTextImport::nsTextImport()
+{
+ // Init logging module.
+ if (!TEXTIMPORTLOGMODULE)
+ TEXTIMPORTLOGMODULE = PR_NewLogModule("IMPORT");
+ IMPORT_LOG0("nsTextImport Module Created\n");
+
+ nsImportStringBundle::GetStringBundle(TEXT_MSGS_URL,
+ getter_AddRefs(m_stringBundle));
+}
+
+nsTextImport::~nsTextImport()
+{
+ IMPORT_LOG0("nsTextImport Module Deleted\n");
+}
+
+NS_IMPL_ISUPPORTS(nsTextImport, nsIImportModule)
+
+NS_IMETHODIMP nsTextImport::GetName(char16_t **name)
+{
+ NS_ENSURE_ARG_POINTER(name);
+ *name = nsImportStringBundle::GetStringByID(TEXTIMPORT_NAME, m_stringBundle);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTextImport::GetDescription(char16_t **name)
+{
+ NS_ENSURE_ARG_POINTER(name);
+ *name = nsImportStringBundle::GetStringByID(TEXTIMPORT_DESCRIPTION,
+ m_stringBundle);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTextImport::GetSupports(char **supports)
+{
+ NS_ENSURE_ARG_POINTER(supports);
+ *supports = strdup(kTextSupportsString);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTextImport::GetSupportsUpgrade(bool *pUpgrade)
+{
+ NS_PRECONDITION(pUpgrade != nullptr, "null ptr");
+ if (! pUpgrade)
+ return NS_ERROR_NULL_POINTER;
+
+ *pUpgrade = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTextImport::GetImportInterface(const char *pImportType, nsISupports **ppInterface)
+{
+ NS_ENSURE_ARG_POINTER(pImportType);
+ NS_ENSURE_ARG_POINTER(ppInterface);
+
+ *ppInterface = nullptr;
+ nsresult rv;
+
+ if (!strcmp(pImportType, "addressbook")) {
+ // create the nsIImportMail interface and return it!
+ nsIImportAddressBooks * pAddress = nullptr;
+ nsIImportGeneric * pGeneric = nullptr;
+ rv = ImportAddressImpl::Create(&pAddress, m_stringBundle);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ rv = impSvc->CreateNewGenericAddressBooks(&pGeneric);
+ if (NS_SUCCEEDED(rv)) {
+ pGeneric->SetData("addressInterface", pAddress);
+ rv = pGeneric->QueryInterface(kISupportsIID, (void **)ppInterface);
+ }
+ }
+ }
+ NS_IF_RELEASE(pAddress);
+ NS_IF_RELEASE(pGeneric);
+ return rv;
+ }
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+
+
+nsresult ImportAddressImpl::Create(nsIImportAddressBooks** aImport,
+ nsIStringBundle* aStringBundle)
+{
+ NS_ENSURE_ARG_POINTER(aImport);
+ *aImport = new ImportAddressImpl(aStringBundle);
+ if (! *aImport)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(*aImport);
+ return NS_OK;
+}
+
+ImportAddressImpl::ImportAddressImpl(nsIStringBundle* aStringBundle) :
+ m_notProxyBundle(aStringBundle)
+{
+ m_haveDelim = false;
+}
+
+NS_IMPL_ISUPPORTS(ImportAddressImpl, nsIImportAddressBooks)
+
+
+NS_IMETHODIMP ImportAddressImpl::GetAutoFind(char16_t **addrDescription, bool *_retval)
+{
+ NS_PRECONDITION(addrDescription != nullptr, "null ptr");
+ NS_PRECONDITION(_retval != nullptr, "null ptr");
+ if (! addrDescription || !_retval)
+ return NS_ERROR_NULL_POINTER;
+
+ nsString str;
+ *_retval = false;
+
+ if (!m_notProxyBundle)
+ return NS_ERROR_FAILURE;
+
+ nsImportStringBundle::GetStringByID(TEXTIMPORT_ADDRESS_NAME, m_notProxyBundle, str);
+ *addrDescription = ToNewUnicode(str);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP ImportAddressImpl::GetDefaultLocation(nsIFile **ppLoc, bool *found, bool *userVerify)
+{
+ NS_PRECONDITION(found != nullptr, "null ptr");
+ NS_PRECONDITION(ppLoc != nullptr, "null ptr");
+ NS_PRECONDITION(userVerify != nullptr, "null ptr");
+ if (! found || !userVerify || !ppLoc)
+ return NS_ERROR_NULL_POINTER;
+
+ *ppLoc = nullptr;
+ *found = false;
+ *userVerify = true;
+ return NS_OK;
+}
+
+
+
+NS_IMETHODIMP ImportAddressImpl::FindAddressBooks(nsIFile *pLoc, nsIArray **ppArray)
+{
+ NS_PRECONDITION(pLoc != nullptr, "null ptr");
+ NS_PRECONDITION(ppArray != nullptr, "null ptr");
+ if (!pLoc || !ppArray)
+ return NS_ERROR_NULL_POINTER;
+
+ ClearSampleFile();
+
+ *ppArray = nullptr;
+ bool exists = false;
+ nsresult rv = pLoc->Exists(&exists);
+ if (NS_FAILED(rv) || !exists)
+ return NS_ERROR_FAILURE;
+
+ bool isFile = false;
+ rv = pLoc->IsFile(&isFile);
+ if (NS_FAILED(rv) || !isFile)
+ return NS_ERROR_FAILURE;
+
+ rv = m_text.DetermineDelim(pLoc);
+
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error determining delimitter\n");
+ return rv;
+ }
+ m_haveDelim = true;
+ m_delim = m_text.GetDelim();
+
+ m_fileLoc = do_QueryInterface(pLoc);
+
+ /* Build an address book descriptor based on the file passed in! */
+ nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("FAILED to allocate the nsIMutableArray\n");
+ return rv;
+ }
+
+ nsString name;
+ m_fileLoc->GetLeafName(name);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Failed getting leaf name of file\n");
+ return rv;
+ }
+
+ int32_t idx = name.RFindChar('.');
+ if ((idx != -1) && (idx > 0) && ((name.Length() - idx - 1) < 5)) {
+ name.SetLength(idx);
+ }
+
+ nsCOMPtr<nsIImportABDescriptor> desc;
+ nsISupports * pInterface;
+
+ nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Failed to obtain the import service\n");
+ return rv;
+ }
+
+ rv = impSvc->CreateNewABDescriptor(getter_AddRefs(desc));
+ if (NS_SUCCEEDED(rv)) {
+ int64_t sz = 0;
+ pLoc->GetFileSize(&sz);
+ desc->SetPreferredName(name);
+ desc->SetSize((uint32_t) sz);
+ desc->SetAbFile(m_fileLoc);
+ rv = desc->QueryInterface(kISupportsIID, (void **) &pInterface);
+ array->AppendElement(pInterface, false);
+ pInterface->Release();
+ }
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error creating address book descriptor for text import\n");
+ return rv;
+ }
+ array.forget(ppArray);
+ return NS_OK;
+}
+
+void ImportAddressImpl::ReportSuccess(nsString& name, nsString *pStream,
+ nsIStringBundle* pBundle)
+{
+ if (!pStream)
+ return;
+
+ // load the success string
+ char16_t *pFmt =
+ nsImportStringBundle::GetStringByID(TEXTIMPORT_ADDRESS_SUCCESS, pBundle);
+
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get());
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ NS_Free(pFmt);
+ pStream->Append(char16_t('\n'));
+}
+
+void ImportAddressImpl::ReportError(int32_t errorNum, nsString& name,
+ nsString *pStream, nsIStringBundle* pBundle)
+{
+ if (!pStream)
+ return;
+
+ // load the error string
+ char16_t *pFmt = nsImportStringBundle::GetStringByID(errorNum, pBundle);
+ char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get());
+ pStream->Append(pText);
+ nsTextFormatter::smprintf_free(pText);
+ NS_Free(pFmt);
+ pStream->Append(char16_t('\n'));
+}
+
+void ImportAddressImpl::SetLogs(nsString& success, nsString& error, char16_t **pError, char16_t **pSuccess)
+{
+ if (pError)
+ *pError = ToNewUnicode(error);
+ if (pSuccess)
+ *pSuccess = ToNewUnicode(success);
+}
+
+
+NS_IMETHODIMP
+ImportAddressImpl::ImportAddressBook(nsIImportABDescriptor *pSource,
+ nsIAddrDatabase *pDestination,
+ nsIImportFieldMap *fieldMap,
+ nsISupports *aSupportService,
+ char16_t ** pErrorLog,
+ char16_t ** pSuccessLog,
+ bool * fatalError)
+{
+ NS_PRECONDITION(pSource != nullptr, "null ptr");
+ NS_PRECONDITION(pDestination != nullptr, "null ptr");
+ NS_PRECONDITION(fatalError != nullptr, "null ptr");
+
+ m_bytesImported = 0;
+
+ nsString success, error;
+ if (!pSource || !pDestination || !fatalError) {
+ IMPORT_LOG0("*** Bad param passed to text address import\n");
+ nsImportStringBundle::GetStringByID(TEXTIMPORT_ADDRESS_BADPARAM,
+ m_notProxyBundle,
+ error);
+
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+
+ if (fatalError)
+ *fatalError = true;
+
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ ClearSampleFile();
+
+ bool addrAbort = false;
+ nsString name;
+ pSource->GetPreferredName(name);
+
+ uint32_t addressSize = 0;
+ pSource->GetSize(&addressSize);
+ if (addressSize == 0) {
+ IMPORT_LOG0("Address book size is 0, skipping import.\n");
+ ReportSuccess(name, &success, m_notProxyBundle);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIFile> inFile;
+ if (NS_FAILED(pSource->GetAbFile(getter_AddRefs(inFile)))) {
+ ReportError(TEXTIMPORT_ADDRESS_BADSOURCEFILE, name, &error, m_notProxyBundle);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ return NS_ERROR_FAILURE;
+ }
+
+ if (!aSupportService) {
+ IMPORT_LOG0("Missing support service to import call");
+ return NS_ERROR_FAILURE;
+ }
+
+ bool isLDIF = false;
+ nsresult rv;
+ nsCOMPtr<nsIAbLDIFService> ldifService(do_QueryInterface(aSupportService, &rv));
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = ldifService->IsLDIFFile(inFile, &isLDIF);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error reading address file\n");
+ }
+ }
+
+ if (NS_FAILED(rv)) {
+ ReportError(TEXTIMPORT_ADDRESS_CONVERTERROR, name, &error, m_notProxyBundle);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ return rv;
+ }
+
+ if (isLDIF) {
+ if (ldifService)
+ rv = ldifService->ImportLDIFFile(pDestination, inFile, false, &m_bytesImported);
+ else
+ return NS_ERROR_FAILURE;
+ }
+ else {
+ rv = m_text.ImportAddresses(&addrAbort, name.get(), inFile, pDestination, fieldMap, error, &m_bytesImported);
+ SaveFieldMap(fieldMap);
+ }
+
+ if (NS_SUCCEEDED(rv) && error.IsEmpty()) {
+ ReportSuccess(name, &success, m_notProxyBundle);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ }
+ else {
+ ReportError(TEXTIMPORT_ADDRESS_CONVERTERROR, name, &error, m_notProxyBundle);
+ SetLogs(success, error, pErrorLog, pSuccessLog);
+ }
+
+ IMPORT_LOG0("*** Text address import done\n");
+ return rv;
+}
+
+
+NS_IMETHODIMP ImportAddressImpl::GetImportProgress(uint32_t *_retval)
+{
+ NS_ENSURE_ARG_POINTER(_retval);
+ *_retval = m_bytesImported;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP ImportAddressImpl::GetNeedsFieldMap(nsIFile *aLocation, bool *_retval)
+{
+ NS_ENSURE_ARG_POINTER(_retval);
+ NS_ENSURE_ARG_POINTER(aLocation);
+
+ *_retval = true;
+ bool exists = false;
+ bool isFile = false;
+
+ nsresult rv = aLocation->Exists(&exists);
+ rv = aLocation->IsFile(&isFile);
+
+ if (!exists || !isFile)
+ return NS_ERROR_FAILURE;
+
+ bool isLDIF = false;
+ nsCOMPtr<nsIAbLDIFService> ldifService = do_GetService(NS_ABLDIFSERVICE_CONTRACTID, &rv);
+
+ if (NS_SUCCEEDED(rv))
+ rv = ldifService->IsLDIFFile(aLocation, &isLDIF);
+
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error determining if file is of type LDIF\n");
+ return rv;
+ }
+
+ if (isLDIF)
+ *_retval = false;
+
+ return NS_OK;
+}
+
+void ImportAddressImpl::SanitizeSampleData(nsString& val)
+{
+ // remove any line-feeds...
+ int32_t offset = val.Find(NS_LITERAL_STRING("\x0D\x0A"));
+ while (offset != -1) {
+ val.Replace(offset, 2, NS_LITERAL_STRING(", "));
+ offset = val.Find(NS_LITERAL_STRING("\x0D\x0A"), offset + 2);
+ }
+ offset = val.FindChar(13);
+ while (offset != -1) {
+ val.Replace(offset, 1, ',');
+ offset = val.FindChar(13, offset + 2);
+ }
+ offset = val.FindChar(10);
+ while (offset != -1) {
+ val.Replace(offset, 1, ',');
+ offset = val.FindChar(10, offset + 2);
+ }
+}
+
+NS_IMETHODIMP ImportAddressImpl::GetSampleData(int32_t index, bool *pFound, char16_t **pStr)
+{
+ NS_PRECONDITION(pFound != nullptr, "null ptr");
+ NS_PRECONDITION(pStr != nullptr, "null ptr");
+ if (!pFound || !pStr)
+ return NS_ERROR_NULL_POINTER;
+
+ if (!m_fileLoc) {
+ IMPORT_LOG0("*** Error, called GetSampleData before SetSampleLocation\n");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv;
+ *pStr = nullptr;
+ char16_t term = 0;
+
+ if (!m_haveDelim) {
+ rv = m_text.DetermineDelim(m_fileLoc);
+ NS_ENSURE_SUCCESS(rv, rv);
+ m_haveDelim = true;
+ m_delim = m_text.GetDelim();
+ }
+
+ bool fileExists;
+ rv = m_fileLoc->Exists(&fileExists);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!fileExists) {
+ *pFound = false;
+ *pStr = NS_strdup(&term);
+ return NS_OK;
+ }
+
+ nsAutoString line;
+ rv = nsTextAddress::ReadRecordNumber(m_fileLoc, line, index);
+ if (NS_SUCCEEDED(rv)) {
+ nsString str;
+ nsString field;
+ int32_t fNum = 0;
+ while (nsTextAddress::GetField(line, fNum, field, m_delim)) {
+ if (fNum)
+ str.Append(char16_t('\n'));
+ SanitizeSampleData(field);
+ str.Append(field);
+ fNum++;
+ field.Truncate();
+ }
+
+ *pStr = ToNewUnicode(str);
+ *pFound = true;
+
+ /* IMPORT_LOG1("Sample data: %S\n", str.get()); */
+ }
+ else {
+ *pFound = false;
+ *pStr = NS_strdup(&term);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP ImportAddressImpl::SetSampleLocation(nsIFile *pLocation)
+{
+ NS_ENSURE_ARG_POINTER(pLocation);
+
+ m_fileLoc = do_QueryInterface(pLocation);
+ m_haveDelim = false;
+ return NS_OK;
+}
+
+void ImportAddressImpl::ClearSampleFile(void)
+{
+ m_fileLoc = nullptr;
+ m_haveDelim = false;
+}
+
+NS_IMETHODIMP ImportAddressImpl::InitFieldMap(nsIImportFieldMap *fieldMap)
+{
+ // Let's remember the last one the user used!
+ // This should be normal for someone importing multiple times, it's usually
+ // from the same file format.
+
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv)) {
+ nsCString prefStr;
+ rv = prefs->GetCharPref("mailnews.import.text.fieldmap", getter_Copies(prefStr));
+ if (NS_SUCCEEDED(rv)) {
+ const char *pStr = prefStr.get();
+ if (pStr) {
+ fieldMap->SetFieldMapSize(0);
+ long fNum;
+ bool active;
+ long fIndex = 0;
+ while (*pStr) {
+ while (*pStr && (*pStr != '+') && (*pStr != '-'))
+ pStr++;
+ if (*pStr == '+')
+ active = true;
+ else if (*pStr == '-')
+ active = false;
+ else
+ break;
+ fNum = 0;
+ while (*pStr && ((*pStr < '0') || (*pStr > '9')))
+ pStr++;
+ if (!(*pStr))
+ break;
+ while (*pStr && (*pStr >= '0') && (*pStr <= '9')) {
+ fNum *= 10;
+ fNum += (*pStr - '0');
+ pStr++;
+ }
+ while (*pStr && (*pStr != ','))
+ pStr++;
+ if (*pStr == ',')
+ pStr++;
+ fieldMap->SetFieldMap(-1, fNum);
+ fieldMap->SetFieldActive(fIndex, active);
+ fIndex++;
+ }
+ if (!fIndex) {
+ int num;
+ fieldMap->GetNumMozFields(&num);
+ fieldMap->DefaultFieldMap(num);
+ }
+ }
+ }
+
+ // Now also get the last used skip first record value.
+ bool skipFirstRecord = false;
+ rv = prefs->GetBoolPref("mailnews.import.text.skipfirstrecord", &skipFirstRecord);
+ if (NS_SUCCEEDED(rv))
+ fieldMap->SetSkipFirstRecord(skipFirstRecord);
+ }
+
+ return NS_OK;
+}
+
+
+void ImportAddressImpl::SaveFieldMap(nsIImportFieldMap *pMap)
+{
+ if (!pMap)
+ return;
+
+ int size;
+ int index;
+ bool active;
+ nsCString str;
+
+ pMap->GetMapSize(&size);
+ for (long i = 0; i < size; i++) {
+ index = i;
+ active = false;
+ pMap->GetFieldMap(i, &index);
+ pMap->GetFieldActive(i, &active);
+ if (active)
+ str.Append('+');
+ else
+ str.Append('-');
+
+ str.AppendInt(index);
+ str.Append(',');
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+
+ if (NS_SUCCEEDED(rv)) {
+ nsCString prefStr;
+ rv = prefs->GetCharPref("mailnews.import.text.fieldmap", getter_Copies(prefStr));
+ if (NS_FAILED(rv) || !str.Equals(prefStr))
+ rv = prefs->SetCharPref("mailnews.import.text.fieldmap", str.get());
+ }
+
+ // Now also save last used skip first record value.
+ bool skipFirstRecord = false;
+ rv = pMap->GetSkipFirstRecord(&skipFirstRecord);
+ if (NS_SUCCEEDED(rv))
+ prefs->SetBoolPref("mailnews.import.text.skipfirstrecord", skipFirstRecord);
+}
diff --git a/mailnews/import/text/src/nsTextImport.h b/mailnews/import/text/src/nsTextImport.h
new file mode 100644
index 000000000..4c3c440e0
--- /dev/null
+++ b/mailnews/import/text/src/nsTextImport.h
@@ -0,0 +1,39 @@
+/* -*- 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 nsTextImport_h___
+#define nsTextImport_h___
+
+#include "nsIImportModule.h"
+#include "nsCOMPtr.h"
+#include "nsIStringBundle.h"
+
+#define NS_TEXTIMPORT_CID \
+{ /* A5991D01-ADA7-11d3-A9C2-00A0CC26DA63 */ \
+ 0xa5991d01, 0xada7, 0x11d3, \
+ {0xa9, 0xc2, 0x0, 0xa0, 0xcc, 0x26, 0xda, 0x63 }}
+
+#define kTextSupportsString NS_IMPORT_ADDRESS_STR
+
+class nsTextImport : public nsIImportModule
+{
+public:
+ nsTextImport();
+
+ NS_DECL_ISUPPORTS
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // we suppport the nsIImportModule interface
+ ////////////////////////////////////////////////////////////////////////////////////////
+
+ NS_DECL_NSIIMPORTMODULE
+
+protected:
+ virtual ~nsTextImport();
+ nsCOMPtr<nsIStringBundle> m_stringBundle;
+};
+
+#endif /* nsTextImport_h___ */