diff options
Diffstat (limited to 'mailnews/import/vcard')
-rw-r--r-- | mailnews/import/vcard/src/moz.build | 20 | ||||
-rw-r--r-- | mailnews/import/vcard/src/nsVCardAddress.cpp | 139 | ||||
-rw-r--r-- | mailnews/import/vcard/src/nsVCardAddress.h | 40 | ||||
-rw-r--r-- | mailnews/import/vcard/src/nsVCardImport.cpp | 398 | ||||
-rw-r--r-- | mailnews/import/vcard/src/nsVCardImport.h | 38 |
5 files changed, 635 insertions, 0 deletions
diff --git a/mailnews/import/vcard/src/moz.build b/mailnews/import/vcard/src/moz.build new file mode 100644 index 000000000..9e6c49698 --- /dev/null +++ b/mailnews/import/vcard/src/moz.build @@ -0,0 +1,20 @@ +# 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 += [ + 'nsVCardAddress.cpp', + 'nsVCardImport.cpp', +] + +EXPORTS += [ + 'nsVCardAddress.h', +] + +FINAL_LIBRARY = 'import' + +LOCAL_INCLUDES += [ + '../../src' +] + diff --git a/mailnews/import/vcard/src/nsVCardAddress.cpp b/mailnews/import/vcard/src/nsVCardAddress.cpp new file mode 100644 index 000000000..7495d4c26 --- /dev/null +++ b/mailnews/import/vcard/src/nsVCardAddress.cpp @@ -0,0 +1,139 @@ +/* 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 "nsAbBaseCID.h" +#include "nsNativeCharsetUtils.h" +#include "nsNetUtil.h" +#include "nsVCardAddress.h" + +#include "nsIAbCard.h" +#include "nsIAbManager.h" +#include "nsIAddrDatabase.h" +#include "nsIFile.h" +#include "nsIInputStream.h" +#include "nsILineInputStream.h" + +#include "plstr.h" +#include "msgCore.h" +#include "nsMsgUtils.h" + +nsVCardAddress::nsVCardAddress() +{ +} + +nsVCardAddress::~nsVCardAddress() +{ +} + +nsresult nsVCardAddress::ImportAddresses( + bool *pAbort, + const char16_t *pName, + nsIFile *pSrc, + nsIAddrDatabase *pDb, + nsString& errors, + uint32_t *pProgress) +{ + // Open the source file for reading, read each line and process it! + 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; + } + + // Open the source file for reading, read each line and process it! + // 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; + nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(inputStream, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbManager> ab = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + bool more = true; + nsCString record; + while (!(*pAbort) && more && NS_SUCCEEDED(rv)) { + rv = ReadRecord(lineStream, record, &more); + if (NS_SUCCEEDED(rv) && !record.IsEmpty()) { + // Parse the vCard and build an nsIAbCard from it + nsCOMPtr<nsIAbCard> cardFromVCard; + rv = ab->EscapedVCardToAbCard(record.get(), getter_AddRefs(cardFromVCard)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = pDb->CreateNewCardAndAddToDB(cardFromVCard, false, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + if (NS_FAILED(rv)) { + IMPORT_LOG0("*** Error processing vCard 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 -= record.Length(); + *pProgress = totalBytes - bytesLeft; + } + } + 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 nsVCardAddress::ReadRecord( + nsILineInputStream *aLineStream, nsCString &aRecord, bool *aMore) +{ + bool more = true; + nsresult rv; + nsCString line; + + aRecord.Truncate(); + + // remove the empty lines. + do { + rv = aLineStream->ReadLine(line, aMore); + } + while (line.IsEmpty() && *aMore); + if (!*aMore) + return rv; + + // read BEGIN:VCARD + if (!line.LowerCaseEqualsLiteral("begin:vcard")) { + IMPORT_LOG0("*** Expected case-insensitive BEGIN:VCARD at start of vCard\n"); + rv = NS_ERROR_FAILURE; + *aMore = more; + return rv; + } + aRecord.Append(line); + + // read until END:VCARD + do { + if (!more) { + IMPORT_LOG0("*** Expected case-insensitive END:VCARD at start of vCard\n"); + rv = NS_ERROR_FAILURE; + break; + } + rv = aLineStream->ReadLine(line, &more); + aRecord.AppendLiteral(MSG_LINEBREAK); + aRecord.Append(line); + } while (!line.LowerCaseEqualsLiteral("end:vcard")); + + *aMore = more; + return rv; +} diff --git a/mailnews/import/vcard/src/nsVCardAddress.h b/mailnews/import/vcard/src/nsVCardAddress.h new file mode 100644 index 000000000..bc5e2bd06 --- /dev/null +++ b/mailnews/import/vcard/src/nsVCardAddress.h @@ -0,0 +1,40 @@ +/* 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 nsVCardAddress_h__ +#define nsVCardAddress_h__ + +#include "mozilla/Logging.h" + +extern PRLogModuleInfo *VCARDLOGMODULE; // Logging module + +#define IMPORT_LOG0(x) MOZ_LOG(VCARDLOGMODULE, mozilla::LogLevel::Debug, (x)) +#define IMPORT_LOG1(x, y) MOZ_LOG(VCARDLOGMODULE, mozilla::LogLevel::Debug, (x, y)) +#define IMPORT_LOG2(x, y, z) MOZ_LOG(VCARDLOGMODULE, mozilla::LogLevel::Debug, (x, y, z)) +#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(VCARDLOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d)) + +class nsIAddrDatabase; +class nsIFile; +class nsILineInputStream; + +class nsVCardAddress { +public: + nsVCardAddress(); + virtual ~nsVCardAddress(); + + nsresult ImportAddresses( + bool *pAbort, + const char16_t *pName, + nsIFile *pSrc, + nsIAddrDatabase *pDb, + nsString& errors, + uint32_t *pProgress); + +private: + static nsresult ReadRecord( + nsILineInputStream *aLineStream, nsCString &aRecord, bool *aMore); +}; + +#endif /* nsVCardAddress_h__ */ + diff --git a/mailnews/import/vcard/src/nsVCardImport.cpp b/mailnews/import/vcard/src/nsVCardImport.cpp new file mode 100644 index 000000000..6081c36d7 --- /dev/null +++ b/mailnews/import/vcard/src/nsVCardImport.cpp @@ -0,0 +1,398 @@ +/* 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/. */ + +/* + VCard import addressbook interfaces +*/ +#include "nscore.h" +#include "nsIAddrDatabase.h" +#include "nsIFile.h" +#include "nsIImportABDescriptor.h" +#include "nsIImportAddressBooks.h" +#include "nsIImportFieldMap.h" +#include "nsIImportGeneric.h" +#include "nsIMutableArray.h" +#include "nsCOMPtr.h" +#include "nsIImportService.h" +#include "nsIFile.h" +#include "nsImportStringBundle.h" +#include "nsMsgUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsTextFormatter.h" +#include "nsVCardAddress.h" +#include "nsVCardImport.h" + +PRLogModuleInfo *VCARDLOGMODULE = nullptr; +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + +class ImportVCardAddressImpl : public nsIImportAddressBooks +{ +public: + ImportVCardAddressImpl(nsIStringBundle* aStringBundle); + + static nsresult Create( + nsIImportAddressBooks** aImport, nsIStringBundle* aStringBundle); + + // nsISupports interface + NS_DECL_THREADSAFE_ISUPPORTS + + // nsIImportAddressBooks interface + + // TODO: support multiple vCard files in future - shouldn't be too hard, + // since you just import each file in turn. + 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 + { *_retval = false; return NS_OK;} + + NS_IMETHOD GetDefaultLocation( + nsIFile **location, bool *found, bool *userVerify) override; + + NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval) override; + + NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap) override + { return NS_ERROR_FAILURE;} + + 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 + { return NS_ERROR_FAILURE;} + + NS_IMETHOD SetSampleLocation(nsIFile *) override + { return NS_ERROR_FAILURE; } + +private: + virtual ~ImportVCardAddressImpl(); + 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( + const char *errorName, nsString& name, nsString *pStream, + nsIStringBundle* pBundle); + +private: + nsVCardAddress m_vCard; + nsCOMPtr<nsIFile> m_fileLoc; + uint32_t m_bytesImported; + nsCOMPtr<nsIStringBundle> m_notProxyBundle; +}; + +nsVCardImport::nsVCardImport() +{ + if (!VCARDLOGMODULE) + VCARDLOGMODULE = PR_NewLogModule("IMPORT"); + + nsImportStringBundle::GetStringBundle( + VCARDIMPORT_MSGS_URL, getter_AddRefs(m_stringBundle)); + + IMPORT_LOG0("nsVCardImport Module Created\n"); +} + +nsVCardImport::~nsVCardImport() +{ + IMPORT_LOG0("nsVCardImport Module Deleted\n"); +} + +NS_IMPL_ISUPPORTS(nsVCardImport, nsIImportModule) + +NS_IMETHODIMP nsVCardImport::GetName(char16_t **name) +{ + NS_ENSURE_ARG_POINTER(name); + *name = nsImportStringBundle::GetStringByName( + "vCardImportName", m_stringBundle); + return NS_OK; +} + +NS_IMETHODIMP nsVCardImport::GetDescription(char16_t **name) +{ + NS_ENSURE_ARG_POINTER(name); + *name = nsImportStringBundle::GetStringByName( + "vCardImportDescription", m_stringBundle); + return NS_OK; +} + +NS_IMETHODIMP nsVCardImport::GetSupports(char **supports) +{ + NS_ENSURE_ARG_POINTER(supports); + *supports = strdup(NS_IMPORT_ADDRESS_STR); + return NS_OK; +} + +NS_IMETHODIMP nsVCardImport::GetSupportsUpgrade(bool *pUpgrade) +{ + NS_ENSURE_ARG_POINTER(pUpgrade); + *pUpgrade = true; + return NS_OK; +} + +NS_IMETHODIMP nsVCardImport::GetImportInterface( + const char *pImportType, nsISupports **ppInterface) +{ + NS_ENSURE_ARG_POINTER(pImportType); + NS_ENSURE_ARG_POINTER(ppInterface); + *ppInterface = nullptr; + if (!strcmp(pImportType, "addressbook")) { + nsresult rv; + // create the nsIImportMail interface and return it! + nsIImportAddressBooks *pAddress = nullptr; + nsIImportGeneric *pGeneric = nullptr; + rv = ImportVCardAddressImpl::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 ImportVCardAddressImpl::Create( + nsIImportAddressBooks** aImport, nsIStringBundle* aStringBundle) +{ + NS_ENSURE_ARG_POINTER(aImport); + *aImport = new ImportVCardAddressImpl(aStringBundle); + if (!*aImport) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*aImport); + return NS_OK; +} + +ImportVCardAddressImpl::ImportVCardAddressImpl( + nsIStringBundle* aStringBundle) : m_notProxyBundle(aStringBundle) +{ +} + +ImportVCardAddressImpl::~ImportVCardAddressImpl() +{ +} + +NS_IMPL_ISUPPORTS(ImportVCardAddressImpl, nsIImportAddressBooks) + +NS_IMETHODIMP ImportVCardAddressImpl::GetAutoFind( + char16_t **addrDescription, bool *_retval) +{ + NS_ENSURE_ARG_POINTER(addrDescription); + NS_ENSURE_ARG_POINTER(_retval); + + nsString str; + *_retval = false; + + if (!m_notProxyBundle) + return NS_ERROR_FAILURE; + + nsImportStringBundle::GetStringByName("vCardImportAddressName", m_notProxyBundle, str); + *addrDescription = ToNewUnicode(str); + return NS_OK; +} + +NS_IMETHODIMP ImportVCardAddressImpl::GetDefaultLocation( + nsIFile **ppLoc, bool *found, bool *userVerify) +{ + NS_ENSURE_ARG_POINTER(found); + NS_ENSURE_ARG_POINTER(ppLoc); + NS_ENSURE_ARG_POINTER(userVerify); + + *ppLoc = nullptr; + *found = false; + *userVerify = true; + return NS_OK; +} + +NS_IMETHODIMP ImportVCardAddressImpl::FindAddressBooks( + nsIFile *pLoc, nsIArray **ppArray) +{ + NS_ENSURE_ARG_POINTER(pLoc); + NS_ENSURE_ARG_POINTER(ppArray); + + *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; + + 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; + 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); + nsCOMPtr<nsISupports> pInterface(do_QueryInterface(desc, &rv)); + array->AppendElement(pInterface, false); + } + if (NS_FAILED(rv)) { + IMPORT_LOG0( + "*** Error creating address book descriptor for vCard import\n"); + return rv; + } + + array.forget(ppArray); + return NS_OK; +} + +void ImportVCardAddressImpl::ReportSuccess( + nsString& name, nsString *pStream, nsIStringBundle* pBundle) +{ + if (!pStream) + return; + + // load the success string + char16_t *pFmt = nsImportStringBundle::GetStringByName( + "vCardImportAddressSuccess", 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 ImportVCardAddressImpl::ReportError( + const char *errorName, nsString& name, nsString *pStream, + nsIStringBundle* pBundle) +{ + if (!pStream) + return; + + // load the error string + char16_t *pFmt = nsImportStringBundle::GetStringByName(errorName, 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 ImportVCardAddressImpl::SetLogs( + nsString& success, nsString& error, + char16_t **pError, char16_t **pSuccess) +{ + if (pError) + *pError = ToNewUnicode(error); + if (pSuccess) + *pSuccess = ToNewUnicode(success); +} + +NS_IMETHODIMP ImportVCardAddressImpl::ImportAddressBook( + nsIImportABDescriptor *pSource, + nsIAddrDatabase *pDestination, + nsIImportFieldMap *fieldMap, + nsISupports *aSupportService, + char16_t ** pErrorLog, + char16_t ** pSuccessLog, + bool * fatalError) +{ + NS_ENSURE_ARG_POINTER(pSource); + NS_ENSURE_ARG_POINTER(pDestination); + NS_ENSURE_ARG_POINTER(fatalError); + + if (!m_notProxyBundle) + return NS_ERROR_FAILURE; + + m_bytesImported = 0; + nsString success, error; + 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("vCardImportAddressBadSourceFile", name, &error, m_notProxyBundle); + SetLogs(success, error, pErrorLog, pSuccessLog); + return NS_ERROR_FAILURE; + } + + if (!aSupportService) { + IMPORT_LOG0("Missing support service to import call\n"); + return NS_ERROR_FAILURE; + } + + nsresult rv = m_vCard.ImportAddresses( + &addrAbort, name.get(), inFile, pDestination, error, &m_bytesImported); + + if (NS_SUCCEEDED(rv) && error.IsEmpty()) { + ReportSuccess(name, &success, m_notProxyBundle); + SetLogs(success, error, pErrorLog, pSuccessLog); + } + else { + ReportError("vCardImportAddressConvertError", name, &error, m_notProxyBundle); + SetLogs(success, error, pErrorLog, pSuccessLog); + } + + IMPORT_LOG0("*** VCard address import done\n"); + return rv; +} + +NS_IMETHODIMP ImportVCardAddressImpl::GetImportProgress(uint32_t *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = m_bytesImported; + return NS_OK; +} diff --git a/mailnews/import/vcard/src/nsVCardImport.h b/mailnews/import/vcard/src/nsVCardImport.h new file mode 100644 index 000000000..3204412a2 --- /dev/null +++ b/mailnews/import/vcard/src/nsVCardImport.h @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsVCardImport_h___ +#define nsVCardImport_h___ + +#include "nsIImportModule.h" +#include "nsIStringBundle.h" +#include "nsCOMPtr.h" + +#define NS_VCARDIMPORT_CID \ +{ /* 0EB034A3-964A-4E2F-92EBCC55D9AE9DD2 */ \ + 0x0eb034a3, 0x964a, 0x4e2f, \ + {0x92, 0xeb, 0xcc, 0x55, 0xd9, 0xae, 0x9d, 0xd2}} + +#define VCARDIMPORT_MSGS_URL "chrome://messenger/locale/vCardImportMsgs.properties" + +class nsVCardImport : public nsIImportModule +{ +public: + + nsVCardImport(); + + NS_DECL_ISUPPORTS + + //////////////////////////////////////////////////////////////////////////////////////// + // we suppport the nsIImportModule interface + //////////////////////////////////////////////////////////////////////////////////////// + + NS_DECL_NSIIMPORTMODULE + +protected: + virtual ~nsVCardImport(); + nsCOMPtr<nsIStringBundle> m_stringBundle; +}; + +#endif /* nsVCardImport_h___ */ |