/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Outlook mail import */ #include "nsCOMPtr.h" #include "nscore.h" #include "nsMsgUtils.h" #include "nsIServiceManager.h" #include "nsIImportService.h" #include "nsIImportFieldMap.h" #include "nsIImportMailboxDescriptor.h" #include "nsIImportABDescriptor.h" #include "nsIMutableArray.h" #include "nsOutlookStringBundle.h" #include "nsABBaseCID.h" #include "nsIAbCard.h" #include "mdb.h" #include "OutlookDebugLog.h" #include "nsOutlookMail.h" #include "nsUnicharUtils.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" #include "nsIMsgPluggableStore.h" #include "nsIMsgHdr.h" #include "nsIMsgFolder.h" #include "nsMsgI18N.h" #include "nsNetUtil.h" static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); /* ------------ Address book stuff ----------------- */ typedef struct { int32_t mozField; int32_t multiLine; ULONG mapiTag; } MAPIFields; /* Fields in MAPI, not in Mozilla PR_OFFICE_LOCATION FIX - PR_BIRTHDAY - stored as PT_SYSTIME - FIX to extract for moz address book birthday PR_DISPLAY_NAME_PREFIX - Mr., Mrs. Dr., etc. PR_SPOUSE_NAME PR_GENDER - integer, not text FIX - PR_CONTACT_EMAIL_ADDRESSES - multiuline strings for email addresses, needs parsing to get secondary email address for mozilla */ #define kIsMultiLine -2 #define kNoMultiLine -1 static MAPIFields gMapiFields[] = { { 35, kIsMultiLine, PR_BODY}, { 6, kNoMultiLine, PR_BUSINESS_TELEPHONE_NUMBER}, { 7, kNoMultiLine, PR_HOME_TELEPHONE_NUMBER}, { 25, kNoMultiLine, PR_COMPANY_NAME}, { 23, kNoMultiLine, PR_TITLE}, { 10, kNoMultiLine, PR_CELLULAR_TELEPHONE_NUMBER}, { 9, kNoMultiLine, PR_PAGER_TELEPHONE_NUMBER}, { 8, kNoMultiLine, PR_BUSINESS_FAX_NUMBER}, { 8, kNoMultiLine, PR_HOME_FAX_NUMBER}, { 22, kNoMultiLine, PR_COUNTRY}, { 19, kNoMultiLine, PR_LOCALITY}, { 20, kNoMultiLine, PR_STATE_OR_PROVINCE}, { 17, 18, PR_STREET_ADDRESS}, { 21, kNoMultiLine, PR_POSTAL_CODE}, { 27, kNoMultiLine, PR_PERSONAL_HOME_PAGE}, { 26, kNoMultiLine, PR_BUSINESS_HOME_PAGE}, { 13, kNoMultiLine, PR_HOME_ADDRESS_CITY}, { 16, kNoMultiLine, PR_HOME_ADDRESS_COUNTRY}, { 15, kNoMultiLine, PR_HOME_ADDRESS_POSTAL_CODE}, { 14, kNoMultiLine, PR_HOME_ADDRESS_STATE_OR_PROVINCE}, { 11, 12, PR_HOME_ADDRESS_STREET}, { 24, kNoMultiLine, PR_DEPARTMENT_NAME} }; /* ---------------------------------------------------- */ #define kCopyBufferSize (16 * 1024) // The email address in Outlook Contacts doesn't have a named // property, we need to use this mapi name ID to access the email // The MAPINAMEID for email address has ulKind=MNID_ID // Outlook stores each email address in two IDs, 32899/32900 for Email1 // 32915/32916 for Email2, 32931/32932 for Email3 // Current we use OUTLOOK_EMAIL1_MAPI_ID1 for primary email // OUTLOOK_EMAIL2_MAPI_ID1 for secondary email #define OUTLOOK_EMAIL1_MAPI_ID1 32899 #define OUTLOOK_EMAIL1_MAPI_ID2 32900 #define OUTLOOK_EMAIL2_MAPI_ID1 32915 #define OUTLOOK_EMAIL2_MAPI_ID2 32916 #define OUTLOOK_EMAIL3_MAPI_ID1 32931 #define OUTLOOK_EMAIL3_MAPI_ID2 32932 nsOutlookMail::nsOutlookMail() { m_gotAddresses = false; m_gotFolders = false; m_haveMapi = CMapiApi::LoadMapi(); m_lpMdb = NULL; } nsOutlookMail::~nsOutlookMail() { // EmptyAttachments(); } nsresult nsOutlookMail::GetMailFolders(nsIArray **pArray) { if (!m_haveMapi) { IMPORT_LOG0("GetMailFolders called before Mapi is initialized\n"); return NS_ERROR_FAILURE; } nsresult rv; nsCOMPtr array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv)); if (NS_FAILED(rv)) { IMPORT_LOG0("FAILED to allocate the nsIMutableArray for the mail folder list\n"); return rv; } nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; m_gotFolders = true; m_folderList.ClearAll(); m_mapi.Initialize(); m_mapi.LogOn(); if (m_storeList.GetSize() == 0) m_mapi.IterateStores(m_storeList); int i = 0; CMapiFolder *pFolder; if (m_storeList.GetSize() > 1) { while ((pFolder = m_storeList.GetItem(i))) { CMapiFolder *pItem = new CMapiFolder(pFolder); pItem->SetDepth(1); m_folderList.AddItem(pItem); if (!m_mapi.GetStoreFolders(pItem->GetCBEntryID(), pItem->GetEntryID(), m_folderList, 2)) { IMPORT_LOG1("GetStoreFolders for index %d failed.\n", i); } i++; } } else { if ((pFolder = m_storeList.GetItem(i))) { if (!m_mapi.GetStoreFolders(pFolder->GetCBEntryID(), pFolder->GetEntryID(), m_folderList, 1)) { IMPORT_LOG1("GetStoreFolders for index %d failed.\n", i); } } } // Create the mailbox descriptors for the list of folders nsIImportMailboxDescriptor * pID; nsISupports * pInterface; nsString name; nsString uniName; for (i = 0; i < m_folderList.GetSize(); i++) { pFolder = m_folderList.GetItem(i); rv = impSvc->CreateNewMailboxDescriptor(&pID); if (NS_SUCCEEDED(rv)) { pID->SetDepth(pFolder->GetDepth()); pID->SetIdentifier(i); pFolder->GetDisplayName(name); pID->SetDisplayName(name.get()); pID->SetSize(1000); rv = pID->QueryInterface(kISupportsIID, (void **) &pInterface); array->AppendElement(pInterface, false); pInterface->Release(); pID->Release(); } } array.forget(pArray); return NS_OK; } bool nsOutlookMail::IsAddressBookNameUnique(nsString& name, nsString& list) { nsString usedName; usedName.AppendLiteral("["); usedName.Append(name); usedName.AppendLiteral("],"); return list.Find(usedName) == -1; } void nsOutlookMail::MakeAddressBookNameUnique(nsString& name, nsString& list) { nsString newName; int idx = 1; newName = name; while (!IsAddressBookNameUnique(newName, list)) { newName = name; newName.Append(char16_t(' ')); newName.AppendInt((int32_t) idx); idx++; } name = newName; list.AppendLiteral("["); list.Append(name); list.AppendLiteral("],"); } nsresult nsOutlookMail::GetAddressBooks(nsIArray **pArray) { if (!m_haveMapi) { IMPORT_LOG0("GetAddressBooks called before Mapi is initialized\n"); return NS_ERROR_FAILURE; } nsresult rv; nsCOMPtr array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv)); if (NS_FAILED(rv)) { IMPORT_LOG0("FAILED to allocate the nsIMutableArray for the address book list\n"); return rv; } nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; m_gotAddresses = true; m_addressList.ClearAll(); m_mapi.Initialize(); m_mapi.LogOn(); if (m_storeList.GetSize() == 0) m_mapi.IterateStores(m_storeList); int i = 0; CMapiFolder *pFolder; if (m_storeList.GetSize() > 1) { while ((pFolder = m_storeList.GetItem(i))) { CMapiFolder *pItem = new CMapiFolder(pFolder); pItem->SetDepth(1); m_addressList.AddItem(pItem); if (!m_mapi.GetStoreAddressFolders(pItem->GetCBEntryID(), pItem->GetEntryID(), m_addressList)) { IMPORT_LOG1("GetStoreAddressFolders for index %d failed.\n", i); } i++; } } else { if ((pFolder = m_storeList.GetItem(i))) { if (!m_mapi.GetStoreAddressFolders(pFolder->GetCBEntryID(), pFolder->GetEntryID(), m_addressList)) { IMPORT_LOG1("GetStoreFolders for index %d failed.\n", i); } } } // Create the mailbox descriptors for the list of folders nsIImportABDescriptor * pID; nsISupports * pInterface; nsString name; nsString list; for (i = 0; i < m_addressList.GetSize(); i++) { pFolder = m_addressList.GetItem(i); if (!pFolder->IsStore()) { rv = impSvc->CreateNewABDescriptor(&pID); if (NS_SUCCEEDED(rv)) { pID->SetIdentifier(i); pFolder->GetDisplayName(name); MakeAddressBookNameUnique(name, list); pID->SetPreferredName(name); pID->SetSize(100); rv = pID->QueryInterface(kISupportsIID, (void **) &pInterface); array->AppendElement(pInterface, false); pInterface->Release(); pID->Release(); } } } array.forget(pArray); return NS_OK; } void nsOutlookMail::OpenMessageStore(CMapiFolder *pNextFolder) { // Open the store specified if (pNextFolder->IsStore()) { if (!m_mapi.OpenStore(pNextFolder->GetCBEntryID(), pNextFolder->GetEntryID(), &m_lpMdb)) { m_lpMdb = NULL; IMPORT_LOG0("CMapiApi::OpenStore failed\n"); } return; } // Check to see if we should open the one and only store if (!m_lpMdb) { if (m_storeList.GetSize() == 1) { CMapiFolder * pFolder = m_storeList.GetItem(0); if (pFolder) { if (!m_mapi.OpenStore(pFolder->GetCBEntryID(), pFolder->GetEntryID(), &m_lpMdb)) { m_lpMdb = NULL; IMPORT_LOG0("CMapiApi::OpenStore failed\n"); } } else { IMPORT_LOG0("Error retrieving the one & only message store\n"); } } else { IMPORT_LOG0("*** Error importing a folder without a valid message store\n"); } } } // Roles and responsibilities: // nsOutlookMail // - Connect to Outlook // - Enumerate the mailboxes // - Iterate the mailboxes // - For each mail, create one nsOutlookCompose object // - For each mail, create one CMapiMessage object // // nsOutlookCompose // - Establish a TB session // - Connect to all required services // - Perform the composition of the RC822 document from the data gathered by CMapiMessage // - Save the composed message to the TB mailbox // - Ensure the proper cleanup // // CMapiMessage // - Encapsulate the MAPI message interface // - Gather the information required to (re)compose the message nsresult nsOutlookMail::ImportMailbox(uint32_t *pDoneSoFar, bool *pAbort, int32_t index, const char16_t *pName, nsIMsgFolder *dstFolder, int32_t *pMsgCount) { if ((index < 0) || (index >= m_folderList.GetSize())) { IMPORT_LOG0("*** Bad mailbox identifier, unable to import\n"); *pAbort = true; return NS_ERROR_FAILURE; } int32_t dummyMsgCount = 0; if (pMsgCount) *pMsgCount = 0; else pMsgCount = &dummyMsgCount; CMapiFolder *pFolder = m_folderList.GetItem(index); OpenMessageStore(pFolder); if (!m_lpMdb) { IMPORT_LOG1("*** Unable to obtain mapi message store for mailbox: %S\n", pName); return NS_ERROR_FAILURE; } if (pFolder->IsStore()) return NS_OK; // now what? CMapiFolderContents contents(m_lpMdb, pFolder->GetCBEntryID(), pFolder->GetEntryID()); BOOL done = FALSE; ULONG cbEid; LPENTRYID lpEid; ULONG oType; LPMESSAGE lpMsg = nullptr; ULONG totalCount; double doneCalc; nsCOMPtr outputStream; nsCOMPtr msgStore; nsresult rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore)); NS_ENSURE_SUCCESS(rv, rv); while (!done) { if (!contents.GetNext(&cbEid, &lpEid, &oType, &done)) { IMPORT_LOG1("*** Error iterating mailbox: %S\n", pName); return NS_ERROR_FAILURE; } nsCOMPtr msgHdr; bool reusable; rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable, getter_AddRefs(outputStream)); if (NS_FAILED(rv)) { IMPORT_LOG1("*** Error getting nsIOutputStream of mailbox: %S\n", pName); return rv; } totalCount = contents.GetCount(); doneCalc = *pMsgCount; doneCalc /= totalCount; doneCalc *= 1000; if (pDoneSoFar) { *pDoneSoFar = (uint32_t) doneCalc; if (*pDoneSoFar > 1000) *pDoneSoFar = 1000; } if (!done && (oType == MAPI_MESSAGE)) { if (!m_mapi.OpenMdbEntry(m_lpMdb, cbEid, lpEid, (LPUNKNOWN *) &lpMsg)) { IMPORT_LOG1("*** Error opening messages in mailbox: %S\n", pName); return NS_ERROR_FAILURE; } // See if it's a drafts folder. Outlook doesn't allow drafts // folder to be configured so it's ok to hard code it here. nsAutoString folderName(pName); nsMsgDeliverMode mode = nsIMsgSend::nsMsgDeliverNow; mode = nsIMsgSend::nsMsgSaveAsDraft; if (folderName.LowerCaseEqualsLiteral("drafts")) mode = nsIMsgSend::nsMsgSaveAsDraft; rv = ImportMessage(lpMsg, outputStream, mode); if (NS_SUCCEEDED(rv)){ // No errors & really imported (*pMsgCount)++; msgStore->FinishNewMessage(outputStream, msgHdr); } else { IMPORT_LOG1( "*** Error reading message from mailbox: %S\n", pName); msgStore->DiscardNewMessage(outputStream, msgHdr); } if (!reusable) outputStream->Close(); } } if (outputStream) outputStream->Close(); return NS_OK; } nsresult nsOutlookMail::ImportMessage(LPMESSAGE lpMsg, nsIOutputStream *pDest, nsMsgDeliverMode mode) { CMapiMessage msg(lpMsg); // If we wanted to skip messages that were downloaded in header only mode, we // would return NS_ERROR_FAILURE if !msg.FullMessageDownloaded. However, we // don't do this because it may cause seemingly wrong import results. // A user will get less mails in his imported folder than were in the original folder, // and this may make user feel like TB import is bad. // In reality, the skipped messages are those that have not been downloaded yet, because // they were downloaded in the "headers-only" mode. This is different from the case when // the message is downloaded completely, but consists only of headers - in this case // the message will be imported anyway. if (!msg.ValidState()) return NS_ERROR_FAILURE; // I have to create a composer for each message, since it turns out that if we create // one composer for several messages, the Send Proxy object that is shared between those messages // isn't reset properly (at least in the current implementation), which leads to crash. // If there's a proper way to reinitialize the Send Proxy object, // then we could slightly optimize the send process. nsOutlookCompose compose; nsresult rv = compose.ProcessMessage(mode, msg, pDest); // Just for YUCKS, let's try an extra endline WriteData(pDest, "\x0D\x0A", 2); return rv; } BOOL nsOutlookMail::WriteData(nsIOutputStream *pDest, const char *pData, int32_t len) { uint32_t written; nsresult rv = pDest->Write(pData, len, &written); return NS_SUCCEEDED(rv) && written == len; } nsresult nsOutlookMail::ImportAddresses(uint32_t *pCount, uint32_t *pTotal, const char16_t *pName, uint32_t id, nsIAddrDatabase *pDb, nsString& errors) { if (id >= (uint32_t)(m_addressList.GetSize())) { IMPORT_LOG0("*** Bad address identifier, unable to import\n"); return NS_ERROR_FAILURE; } uint32_t dummyCount = 0; if (pCount) *pCount = 0; else pCount = &dummyCount; CMapiFolder *pFolder; if (id > 0) { int32_t idx = (int32_t) id; idx--; while (idx >= 0) { pFolder = m_addressList.GetItem(idx); if (pFolder->IsStore()) { OpenMessageStore(pFolder); break; } idx--; } } pFolder = m_addressList.GetItem(id); OpenMessageStore(pFolder); if (!m_lpMdb) { IMPORT_LOG1("*** Unable to obtain mapi message store for address book: %S\n", pName); return NS_ERROR_FAILURE; } if (pFolder->IsStore()) return NS_OK; nsresult rv; nsCOMPtr pFieldMap; nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { rv = impSvc->CreateNewFieldMap(getter_AddRefs(pFieldMap)); } CMapiFolderContents contents(m_lpMdb, pFolder->GetCBEntryID(), pFolder->GetEntryID()); BOOL done = FALSE; ULONG cbEid; LPENTRYID lpEid; ULONG oType; LPMESSAGE lpMsg; nsCString type; LPSPropValue pVal; nsString subject; while (!done) { (*pCount)++; if (!contents.GetNext(&cbEid, &lpEid, &oType, &done)) { IMPORT_LOG1("*** Error iterating address book: %S\n", pName); return NS_ERROR_FAILURE; } if (pTotal && (*pTotal == 0)) *pTotal = contents.GetCount(); if (!done && (oType == MAPI_MESSAGE)) { if (!m_mapi.OpenMdbEntry(m_lpMdb, cbEid, lpEid, (LPUNKNOWN *) &lpMsg)) { IMPORT_LOG1("*** Error opening messages in mailbox: %S\n", pName); return NS_ERROR_FAILURE; } // Get the PR_MESSAGE_CLASS attribute, // ensure that it is IPM.Contact pVal = m_mapi.GetMapiProperty(lpMsg, PR_MESSAGE_CLASS); if (pVal) { type.Truncate(); m_mapi.GetStringFromProp(pVal, type); if (type.EqualsLiteral("IPM.Contact")) { // This is a contact, add it to the address book! subject.Truncate(); pVal = m_mapi.GetMapiProperty(lpMsg, PR_SUBJECT); if (pVal) m_mapi.GetStringFromProp(pVal, subject); nsIMdbRow* newRow = nullptr; pDb->GetNewRow(&newRow); // FIXME: Check with Candice about releasing the newRow if it // isn't added to the database. Candice's code in nsAddressBook // never releases it but that doesn't seem right to me! if (newRow) { if (BuildCard(subject.get(), pDb, newRow, lpMsg, pFieldMap)) { pDb->AddCardRowToDB(newRow); } } } else if (type.EqualsLiteral("IPM.DistList")) { // This is a list/group, add it to the address book! subject.Truncate(); pVal = m_mapi.GetMapiProperty(lpMsg, PR_SUBJECT); if (pVal) m_mapi.GetStringFromProp(pVal, subject); CreateList(subject.get(), pDb, lpMsg, pFieldMap); } } lpMsg->Release(); } } rv = pDb->Commit(nsAddrDBCommitType::kLargeCommit); return rv; } nsresult nsOutlookMail::CreateList(const char16_t * pName, nsIAddrDatabase *pDb, LPMAPIPROP pUserList, nsIImportFieldMap *pFieldMap) { // If no name provided then we're done. if (!pName || !(*pName)) return NS_OK; nsresult rv = NS_ERROR_FAILURE; // Make sure we have db to work with. if (!pDb) return rv; nsCOMPtr newListRow; rv = pDb->GetNewListRow(getter_AddRefs(newListRow)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString column; LossyCopyUTF16toASCII(nsDependentString(pName), column); rv = pDb->AddListName(newListRow, column.get()); NS_ENSURE_SUCCESS(rv, rv); HRESULT hr; LPSPropValue value = NULL; ULONG valueCount = 0; LPSPropTagArray properties = NULL; m_mapi.MAPIAllocateBuffer(CbNewSPropTagArray(1), (void **)&properties); properties->cValues = 1; properties->aulPropTag [0] = m_mapi.GetEmailPropertyTag(pUserList, 0x8054); hr = pUserList->GetProps(properties, 0, &valueCount, &value); m_mapi.MAPIFreeBuffer(properties); if (HR_FAILED(hr)) return NS_ERROR_FAILURE; if (!value) return NS_ERROR_NOT_AVAILABLE; // XXX from here out, value must be freed with MAPIFreeBuffer SBinaryArray *sa=(SBinaryArray *)&value->Value.bin; if (!sa || !sa->lpbin) { m_mapi.MAPIFreeBuffer(value); return NS_ERROR_NULL_POINTER; } LPENTRYID lpEid; ULONG cbEid; ULONG idx; LPMESSAGE lpMsg; nsCString type; LPSPropValue pVal; nsString subject; ULONG total; total = sa->cValues; for (idx = 0; idx < total; idx++) { lpEid= (LPENTRYID) sa->lpbin[idx].lpb; cbEid = sa->lpbin[idx].cb; if (!m_mapi.OpenEntry(cbEid, lpEid, (LPUNKNOWN *) &lpMsg)) { IMPORT_LOG1("*** Error opening messages in mailbox: %S\n", pName); m_mapi.MAPIFreeBuffer(value); return NS_ERROR_FAILURE; } // This is a contact, add it to the address book! subject.Truncate(); pVal = m_mapi.GetMapiProperty(lpMsg, PR_SUBJECT); if (pVal) m_mapi.GetStringFromProp(pVal, subject); nsCOMPtr newRow; nsCOMPtr oldRow; pDb->GetNewRow(getter_AddRefs(newRow)); if (newRow) { if (BuildCard(subject.get(), pDb, newRow, lpMsg, pFieldMap)) { nsCOMPtr userCard; nsCOMPtr newCard; userCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); pDb->InitCardFromRow(userCard,newRow); //add card to db pDb->FindRowByCard(userCard,getter_AddRefs(oldRow)); if (oldRow) newRow = oldRow; else pDb->AddCardRowToDB(newRow); //add card list pDb->AddListCardColumnsToRow(userCard, newListRow,idx+1, getter_AddRefs(newCard), true, nullptr, nullptr); } } } m_mapi.MAPIFreeBuffer(value); rv = pDb->AddCardRowToDB(newListRow); NS_ENSURE_SUCCESS(rv, rv); rv = pDb->SetListAddressTotal(newListRow, (uint32_t)total); rv = pDb->AddListDirNode(newListRow); return rv; } void nsOutlookMail::SanitizeValue(nsString& val) { MsgReplaceSubstring(val, NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING(", ")); MsgReplaceChar(val, "\r\n", ','); } void nsOutlookMail::SplitString(nsString& val1, nsString& val2) { // Find the last line if there is more than one! int32_t idx = val1.RFind("\x0D\x0A"); int32_t cnt = 2; if (idx == -1) { cnt = 1; idx = val1.RFindChar(13); } if (idx == -1) idx= val1.RFindChar(10); if (idx != -1) { val2 = Substring(val1, idx + cnt); val1.SetLength(idx); SanitizeValue(val1); } } bool nsOutlookMail::BuildCard(const char16_t *pName, nsIAddrDatabase *pDb, nsIMdbRow *newRow, LPMAPIPROP pUser, nsIImportFieldMap *pFieldMap) { nsString lastName; nsString firstName; nsString eMail; nsString nickName; nsString middleName; nsString secondEMail; ULONG emailTag; LPSPropValue pProp = m_mapi.GetMapiProperty(pUser, PR_EMAIL_ADDRESS); if (!pProp) { emailTag = m_mapi.GetEmailPropertyTag(pUser, OUTLOOK_EMAIL1_MAPI_ID1); if (emailTag) { pProp = m_mapi.GetMapiProperty(pUser, emailTag); } } if (pProp) { m_mapi.GetStringFromProp(pProp, eMail); SanitizeValue(eMail); } // for secondary email emailTag = m_mapi.GetEmailPropertyTag(pUser, OUTLOOK_EMAIL2_MAPI_ID1); if (emailTag) { pProp = m_mapi.GetMapiProperty(pUser, emailTag); if (pProp) { m_mapi.GetStringFromProp(pProp, secondEMail); SanitizeValue(secondEMail); } } pProp = m_mapi.GetMapiProperty(pUser, PR_GIVEN_NAME); if (pProp) { m_mapi.GetStringFromProp(pProp, firstName); SanitizeValue(firstName); } pProp = m_mapi.GetMapiProperty(pUser, PR_SURNAME); if (pProp) { m_mapi.GetStringFromProp(pProp, lastName); SanitizeValue(lastName); } pProp = m_mapi.GetMapiProperty(pUser, PR_MIDDLE_NAME); if (pProp) { m_mapi.GetStringFromProp(pProp, middleName); SanitizeValue(middleName); } pProp = m_mapi.GetMapiProperty(pUser, PR_NICKNAME); if (pProp) { m_mapi.GetStringFromProp(pProp, nickName); SanitizeValue(nickName); } if (firstName.IsEmpty() && lastName.IsEmpty()) { firstName = pName; } nsString displayName; pProp = m_mapi.GetMapiProperty(pUser, PR_DISPLAY_NAME); if (pProp) { m_mapi.GetStringFromProp(pProp, displayName); SanitizeValue(displayName); } if (displayName.IsEmpty()) { if (firstName.IsEmpty()) displayName = pName; else { displayName = firstName; if (!middleName.IsEmpty()) { displayName.Append(char16_t(' ')); displayName.Append(middleName); } if (!lastName.IsEmpty()) { displayName.Append(char16_t(' ')); displayName.Append(lastName); } } } // We now have the required fields // write them out followed by any optional fields! if (!displayName.IsEmpty()) { pDb->AddDisplayName(newRow, NS_ConvertUTF16toUTF8(displayName).get()); } if (!firstName.IsEmpty()) { pDb->AddFirstName(newRow, NS_ConvertUTF16toUTF8(firstName).get()); } if (!lastName.IsEmpty()) { pDb->AddLastName(newRow, NS_ConvertUTF16toUTF8(lastName).get()); } if (!nickName.IsEmpty()) { pDb->AddNickName(newRow, NS_ConvertUTF16toUTF8(nickName).get()); } if (!eMail.IsEmpty()) { pDb->AddPrimaryEmail(newRow, NS_ConvertUTF16toUTF8(eMail).get()); } if (!secondEMail.IsEmpty()) { pDb->Add2ndEmail(newRow, NS_ConvertUTF16toUTF8(secondEMail).get()); } // Do all of the extra fields! nsString value; nsString line2; if (pFieldMap) { int max = sizeof(gMapiFields) / sizeof(MAPIFields); for (int i = 0; i < max; i++) { pProp = m_mapi.GetMapiProperty(pUser, gMapiFields[i].mapiTag); if (pProp) { m_mapi.GetStringFromProp(pProp, value); if (!value.IsEmpty()) { if (gMapiFields[i].multiLine == kNoMultiLine) { SanitizeValue(value); pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].mozField, value.get()); } else if (gMapiFields[i].multiLine == kIsMultiLine) { pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].mozField, value.get()); } else { line2.Truncate(); SplitString(value, line2); if (!value.IsEmpty()) pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].mozField, value.get()); if (!line2.IsEmpty()) pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].multiLine, line2.get()); } } } } } return true; }