/* -*- 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 "nsAbCardProperty.h" #include "nsIPrefService.h" #include "nsIAbDirectory.h" #include "plbase64.h" #include "nsIStringBundle.h" #include "plstr.h" #include "nsMsgUtils.h" #include "nsINetUtil.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "nsMemory.h" #include "mozITXTToHTMLConv.h" #include "nsIAbManager.h" #include "nsIUUIDGenerator.h" #include "nsIMsgVCardService.h" #include "nsVariant.h" #include "nsIProperty.h" #include "nsCOMArray.h" #include "prmem.h" #include "mozilla/ArrayUtils.h" #include "mozilla/Components.h" using namespace mozilla; #define PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST "mail.addr_book.lastnamefirst" const char sAddrbookProperties[] = "chrome://messenger/locale/addressbook/addressBook.properties"; enum EAppendType { eAppendLine, eAppendLabel, eAppendCityStateZip, eAppendUndefined }; struct AppendItem { const char* mColumn; const char* mLabel; EAppendType mAppendType; }; static const AppendItem NAME_ATTRS_ARRAY[] = { {kDisplayNameProperty, "propertyDisplayName", eAppendLabel}, {kNicknameProperty, "propertyNickname", eAppendLabel}, {kPriEmailProperty, "", eAppendLine}, {k2ndEmailProperty, "", eAppendLine}}; static const AppendItem PHONE_ATTRS_ARRAY[] = { {kWorkPhoneProperty, "propertyWork", eAppendLabel}, {kHomePhoneProperty, "propertyHome", eAppendLabel}, {kFaxProperty, "propertyFax", eAppendLabel}, {kPagerProperty, "propertyPager", eAppendLabel}, {kCellularProperty, "propertyCellular", eAppendLabel}}; static const AppendItem HOME_ATTRS_ARRAY[] = { {kHomeAddressProperty, "", eAppendLine}, {kHomeAddress2Property, "", eAppendLine}, {kHomeCityProperty, "", eAppendCityStateZip}, {kHomeCountryProperty, "", eAppendLine}, {kHomeWebPageProperty, "", eAppendLine}}; static const AppendItem WORK_ATTRS_ARRAY[] = { {kJobTitleProperty, "", eAppendLine}, {kDepartmentProperty, "", eAppendLine}, {kCompanyProperty, "", eAppendLine}, {kWorkAddressProperty, "", eAppendLine}, {kWorkAddress2Property, "", eAppendLine}, {kWorkCityProperty, "", eAppendCityStateZip}, {kWorkCountryProperty, "", eAppendLine}, {kWorkWebPageProperty, "", eAppendLine}}; static const AppendItem CUSTOM_ATTRS_ARRAY[] = { {kCustom1Property, "propertyCustom1", eAppendLabel}, {kCustom2Property, "propertyCustom2", eAppendLabel}, {kCustom3Property, "propertyCustom3", eAppendLabel}, {kCustom4Property, "propertyCustom4", eAppendLabel}, {kNotesProperty, "", eAppendLine}}; static const AppendItem CHAT_ATTRS_ARRAY[] = { {kGtalkProperty, "propertyGtalk", eAppendLabel}, {kAIMProperty, "propertyAIM", eAppendLabel}, {kYahooProperty, "propertyYahoo", eAppendLabel}, {kSkypeProperty, "propertySkype", eAppendLabel}, {kQQProperty, "propertyQQ", eAppendLabel}, {kMSNProperty, "propertyMSN", eAppendLabel}, {kICQProperty, "propertyICQ", eAppendLabel}, {kXMPPProperty, "propertyXMPP", eAppendLabel}, {kIRCProperty, "propertyIRC", eAppendLabel}}; nsAbCardProperty::nsAbCardProperty() : m_IsMailList(false) { // Initialize some default properties SetPropertyAsUint32(kPopularityIndexProperty, 0); // Uninitialized... SetPropertyAsUint32(kLastModifiedDateProperty, 0); } nsAbCardProperty::~nsAbCardProperty(void) {} NS_IMPL_ISUPPORTS(nsAbCardProperty, nsIAbCard) NS_IMETHODIMP nsAbCardProperty::GetDirectoryUID(nsACString& dirUID) { dirUID = m_directoryUID; return NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetDirectoryUID(const nsACString& aDirUID) { m_directoryUID = aDirUID; return NS_OK; } //////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP nsAbCardProperty::GetIsMailList(bool* aIsMailList) { *aIsMailList = m_IsMailList; return NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetIsMailList(bool aIsMailList) { m_IsMailList = aIsMailList; return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetMailListURI(char** aMailListURI) { if (aMailListURI) { *aMailListURI = ToNewCString(m_MailListURI); return (*aMailListURI) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } else return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsAbCardProperty::SetMailListURI(const char* aMailListURI) { if (aMailListURI) { m_MailListURI = aMailListURI; return NS_OK; } else return NS_ERROR_NULL_POINTER; } /////////////////////////////////////////////////////////////////////////////// // Property bag portion of nsAbCardProperty /////////////////////////////////////////////////////////////////////////////// class nsAbSimpleProperty final : public nsIProperty { public: nsAbSimpleProperty(const nsACString& aName, nsIVariant* aValue) : mName(aName), mValue(aValue) {} NS_DECL_ISUPPORTS NS_DECL_NSIPROPERTY protected: ~nsAbSimpleProperty() {} nsCString mName; nsCOMPtr mValue; }; NS_IMPL_ISUPPORTS(nsAbSimpleProperty, nsIProperty) NS_IMETHODIMP nsAbSimpleProperty::GetName(nsAString& aName) { aName.Assign(NS_ConvertUTF8toUTF16(mName)); return NS_OK; } NS_IMETHODIMP nsAbSimpleProperty::GetValue(nsIVariant** aValue) { NS_IF_ADDREF(*aValue = mValue); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetProperties( nsTArray>& props) { props.ClearAndRetainStorage(); props.SetCapacity(m_properties.Count()); for (auto iter = m_properties.Iter(); !iter.Done(); iter.Next()) { props.AppendElement(new nsAbSimpleProperty(iter.Key(), iter.UserData())); } return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetProperty(const nsACString& name, nsIVariant* defaultValue, nsIVariant** value) { if (!m_properties.Get(name, value)) NS_ADDREF(*value = defaultValue); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetPropertyAsAString(const char* name, nsAString& value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant; return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ? variant->GetAsAString(value) : NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsAbCardProperty::GetPropertyAsAUTF8String(const char* name, nsACString& value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant; return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ? variant->GetAsAUTF8String(value) : NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsAbCardProperty::GetPropertyAsUint32(const char* name, uint32_t* value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant; return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ? variant->GetAsUint32(value) : NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsAbCardProperty::GetPropertyAsBool(const char* name, bool defaultValue, bool* value) { NS_ENSURE_ARG_POINTER(name); *value = defaultValue; nsCOMPtr variant; return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ? variant->GetAsBool(value) : NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetProperty(const nsACString& name, nsIVariant* value) { m_properties.InsertOrUpdate(name, value); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetPropertyAsAString(const char* name, const nsAString& value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant = new nsVariant(); variant->SetAsAString(value); m_properties.InsertOrUpdate(nsDependentCString(name), variant); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetPropertyAsAUTF8String( const char* name, const nsACString& value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant = new nsVariant(); variant->SetAsAUTF8String(value); m_properties.InsertOrUpdate(nsDependentCString(name), variant); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetPropertyAsUint32(const char* name, uint32_t value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant = new nsVariant(); variant->SetAsUint32(value); m_properties.InsertOrUpdate(nsDependentCString(name), variant); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::SetPropertyAsBool(const char* name, bool value) { NS_ENSURE_ARG_POINTER(name); nsCOMPtr variant = new nsVariant(); variant->SetAsBool(value); m_properties.InsertOrUpdate(nsDependentCString(name), variant); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::DeleteProperty(const nsACString& name) { m_properties.Remove(name); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetSupportsVCard(bool* aSupportsVCard) { *aSupportsVCard = false; return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetVCardProperties( JS::MutableHandle properties) { properties.setNull(); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetUID(nsACString& uid) { nsAutoString aString; nsresult rv = GetPropertyAsAString(kUIDProperty, aString); if (NS_SUCCEEDED(rv)) { uid = NS_ConvertUTF16toUTF8(aString); return rv; } nsCOMPtr uuidgen = mozilla::components::UUIDGenerator::Service(); NS_ENSURE_TRUE(uuidgen, NS_ERROR_FAILURE); nsID id; rv = uuidgen->GenerateUUIDInPlace(&id); NS_ENSURE_SUCCESS(rv, rv); char idString[NSID_LENGTH]; id.ToProvidedString(idString); uid.AppendASCII(idString + 1, NSID_LENGTH - 3); return SetUID(uid); } NS_IMETHODIMP nsAbCardProperty::SetUID(const nsACString& aUID) { nsAutoString aString; nsresult rv = GetPropertyAsAString(kUIDProperty, aString); if (NS_SUCCEEDED(rv)) { if (!aString.Equals(NS_ConvertUTF8toUTF16(aUID))) { return NS_ERROR_FAILURE; } } rv = SetPropertyAsAString(kUIDProperty, NS_ConvertUTF8toUTF16(aUID)); NS_ENSURE_SUCCESS(rv, rv); if (m_directoryUID.IsEmpty()) { // This card's not in a directory. return NS_OK; } nsCOMPtr abManager = do_GetService("@mozilla.org/abmanager;1", &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr directory = nullptr; rv = abManager->GetDirectoryFromUID(m_directoryUID, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); if (!directory) { // This card claims to be in a directory, but we can't find it. return NS_OK; } bool readOnly; rv = directory->GetReadOnly(&readOnly); NS_ENSURE_SUCCESS(rv, rv); if (readOnly) { // The directory is read-only. return NS_OK; } // Save the new UID so we can use it again in the future. return directory->ModifyCard(this); } NS_IMETHODIMP nsAbCardProperty::GetFirstName(nsAString& aString) { nsresult rv = GetPropertyAsAString(kFirstNameProperty, aString); if (rv == NS_ERROR_NOT_AVAILABLE) { aString.Truncate(); return NS_OK; } return rv; } NS_IMETHODIMP nsAbCardProperty::SetFirstName(const nsAString& aString) { return SetPropertyAsAString(kFirstNameProperty, aString); } NS_IMETHODIMP nsAbCardProperty::GetLastName(nsAString& aString) { nsresult rv = GetPropertyAsAString(kLastNameProperty, aString); if (rv == NS_ERROR_NOT_AVAILABLE) { aString.Truncate(); return NS_OK; } return rv; } NS_IMETHODIMP nsAbCardProperty::SetLastName(const nsAString& aString) { return SetPropertyAsAString(kLastNameProperty, aString); } NS_IMETHODIMP nsAbCardProperty::GetDisplayName(nsAString& aString) { nsresult rv = GetPropertyAsAString(kDisplayNameProperty, aString); if (rv == NS_ERROR_NOT_AVAILABLE) { aString.Truncate(); return NS_OK; } return rv; } NS_IMETHODIMP nsAbCardProperty::SetDisplayName(const nsAString& aString) { return SetPropertyAsAString(kDisplayNameProperty, aString); } NS_IMETHODIMP nsAbCardProperty::GetPrimaryEmail(nsAString& aString) { nsresult rv = GetPropertyAsAString(kPriEmailProperty, aString); if (rv == NS_ERROR_NOT_AVAILABLE) { aString.Truncate(); return NS_OK; } return rv; } NS_IMETHODIMP nsAbCardProperty::SetPrimaryEmail(const nsAString& aString) { return SetPropertyAsAString(kPriEmailProperty, aString); } NS_IMETHODIMP nsAbCardProperty::GetEmailAddresses( nsTArray& aEmailAddresses) { aEmailAddresses.Clear(); nsresult rv; nsString emailAddress; rv = GetPropertyAsAString(kPriEmailProperty, emailAddress); if (rv != NS_ERROR_NOT_AVAILABLE && !emailAddress.IsEmpty()) { aEmailAddresses.AppendElement(emailAddress); } rv = GetPropertyAsAString(k2ndEmailProperty, emailAddress); if (rv != NS_ERROR_NOT_AVAILABLE && !emailAddress.IsEmpty()) { aEmailAddresses.AppendElement(emailAddress); } return NS_OK; } NS_IMETHODIMP nsAbCardProperty::HasEmailAddress(const nsACString& aEmailAddress, bool* aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = false; nsCString emailAddress; nsresult rv = GetPropertyAsAUTF8String(kPriEmailProperty, emailAddress); if (rv != NS_ERROR_NOT_AVAILABLE && emailAddress.Equals(aEmailAddress, nsCaseInsensitiveCStringComparator)) { *aResult = true; return NS_OK; } rv = GetPropertyAsAUTF8String(k2ndEmailProperty, emailAddress); if (rv != NS_ERROR_NOT_AVAILABLE && emailAddress.Equals(aEmailAddress, nsCaseInsensitiveCStringComparator)) *aResult = true; return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GetPhotoURL(nsAString& aPhotoURL) { aPhotoURL.Truncate(); return NS_OK; } // This function may be overridden by derived classes for // nsAb*Card specific implementations. NS_IMETHODIMP nsAbCardProperty::Copy(nsIAbCard* srcCard) { NS_ENSURE_ARG_POINTER(srcCard); nsTArray> properties; nsresult rv = srcCard->GetProperties(properties); NS_ENSURE_SUCCESS(rv, rv); for (nsIProperty* property : properties) { nsAutoString name; property->GetName(name); nsCOMPtr value; property->GetValue(getter_AddRefs(value)); SetProperty(NS_ConvertUTF16toUTF8(name), value); } bool isMailList; srcCard->GetIsMailList(&isMailList); SetIsMailList(isMailList); nsCString mailListURI; srcCard->GetMailListURI(getter_Copies(mailListURI)); SetMailListURI(mailListURI.get()); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::Equals(nsIAbCard* card, bool* result) { *result = (card == this); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// // The following methods are other views of a card //////////////////////////////////////////////////////////////////////////////// // XXX: Use the category manager instead of this file to implement these NS_IMETHODIMP nsAbCardProperty::TranslateTo(const nsACString& type, nsACString& result) { if (type.EqualsLiteral("base64xml")) { return ConvertToBase64EncodedXML(result); } else if (type.EqualsLiteral("xml")) { nsString utf16String; nsresult rv = ConvertToXMLPrintData(utf16String); NS_ENSURE_SUCCESS(rv, rv); result = NS_ConvertUTF16toUTF8(utf16String); return NS_OK; } else if (type.EqualsLiteral("vcard")) { return ConvertToEscapedVCard(result); } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsAbCardProperty::ConvertToEscapedVCard(nsACString& aResult) { nsresult rv; nsCOMPtr vCardService = do_GetService("@mozilla.org/addressbook/msgvcardservice;1", &rv); NS_ENSURE_SUCCESS(rv, rv); nsAutoString result; rv = vCardService->AbCardToEscapedVCard(this, result); NS_ENSURE_SUCCESS(rv, rv); aResult = NS_ConvertUTF16toUTF8(result); return NS_OK; } nsresult nsAbCardProperty::ConvertToBase64EncodedXML(nsACString& result) { nsresult rv; nsString xmlStr; xmlStr.AppendLiteral( "\n" "\n" "\n"); // Get Address Book string and set it as title of XML document nsCOMPtr bundle; nsCOMPtr stringBundleService = mozilla::components::StringBundle::Service(); if (stringBundleService) { rv = stringBundleService->CreateBundle(sAddrbookProperties, getter_AddRefs(bundle)); if (NS_SUCCEEDED(rv)) { nsString addrBook; rv = bundle->GetStringFromName("addressBook", addrBook); if (NS_SUCCEEDED(rv)) { xmlStr.AppendLiteral(""); xmlStr.Append(addrBook); xmlStr.AppendLiteral("\n"); } } } nsString xmlSubstr; rv = ConvertToXMLPrintData(xmlSubstr); NS_ENSURE_SUCCESS(rv, rv); xmlStr.Append(xmlSubstr); xmlStr.AppendLiteral("\n"); char* tmpRes = PL_Base64Encode(NS_ConvertUTF16toUTF8(xmlStr).get(), 0, nullptr); result.Assign(tmpRes); PR_Free(tmpRes); return NS_OK; } nsresult nsAbCardProperty::ConvertToXMLPrintData(nsAString& aXMLSubstr) { nsresult rv; nsCOMPtr prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); int32_t generatedNameFormat; rv = prefBranch->GetIntPref(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, &generatedNameFormat); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr stringBundleService = mozilla::components::StringBundle::Service(); NS_ENSURE_TRUE(stringBundleService, NS_ERROR_UNEXPECTED); nsCOMPtr bundle; rv = stringBundleService->CreateBundle(sAddrbookProperties, getter_AddRefs(bundle)); NS_ENSURE_SUCCESS(rv, rv); nsString generatedName; rv = GenerateName(generatedNameFormat, bundle, generatedName); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr conv = do_CreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsString xmlStr; xmlStr.SetLength( 4096); // to reduce allocations. should be enough for most cards xmlStr.AssignLiteral("\n"); // use ScanTXT to convert < > & to safe values. nsString safeText; if (!generatedName.IsEmpty()) { rv = conv->ScanTXT(generatedName, mozITXTToHTMLConv::kEntities, safeText); NS_ENSURE_SUCCESS(rv, rv); } if (safeText.IsEmpty()) { nsAutoString primaryEmail; GetPrimaryEmail(primaryEmail); // use ScanTXT to convert < > & to safe values. rv = conv->ScanTXT(primaryEmail, mozITXTToHTMLConv::kEntities, safeText); NS_ENSURE_SUCCESS(rv, rv); } xmlStr.Append(safeText); xmlStr.AppendLiteral( "\n" "
"); rv = AppendSection(NAME_ATTRS_ARRAY, sizeof(NAME_ATTRS_ARRAY) / sizeof(AppendItem), EmptyString(), bundle, conv, xmlStr); xmlStr.AppendLiteral("
"); rv = AppendSection(PHONE_ATTRS_ARRAY, sizeof(PHONE_ATTRS_ARRAY) / sizeof(AppendItem), u"headingPhone"_ns, bundle, conv, xmlStr); if (!m_IsMailList) { rv = AppendSection(CUSTOM_ATTRS_ARRAY, sizeof(CUSTOM_ATTRS_ARRAY) / sizeof(AppendItem), u"headingOther"_ns, bundle, conv, xmlStr); rv = AppendSection(CHAT_ATTRS_ARRAY, sizeof(CHAT_ATTRS_ARRAY) / sizeof(AppendItem), u"headingChat"_ns, bundle, conv, xmlStr); } else { rv = AppendSection(CUSTOM_ATTRS_ARRAY, sizeof(CUSTOM_ATTRS_ARRAY) / sizeof(AppendItem), u"headingDescription"_ns, bundle, conv, xmlStr); xmlStr.AppendLiteral("
"); nsString headingAddresses; rv = bundle->GetStringFromName("headingAddresses", headingAddresses); NS_ENSURE_SUCCESS(rv, rv); xmlStr.Append(headingAddresses); xmlStr.AppendLiteral(""); nsCOMPtr abManager = do_GetService("@mozilla.org/abmanager;1", &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr mailList = nullptr; rv = abManager->GetDirectory(m_MailListURI, getter_AddRefs(mailList)); NS_ENSURE_SUCCESS(rv, rv); nsTArray> mailListAddresses; rv = mailList->GetChildCards(mailListAddresses); NS_ENSURE_SUCCESS(rv, rv); for (nsIAbCard* listCard : mailListAddresses) { xmlStr.AppendLiteral("\n"); nsAutoString displayName; rv = listCard->GetDisplayName(displayName); NS_ENSURE_SUCCESS(rv, rv); // use ScanTXT to convert < > & to safe values. nsString safeText; rv = conv->ScanTXT(displayName, mozITXTToHTMLConv::kEntities, safeText); NS_ENSURE_SUCCESS(rv, rv); xmlStr.Append(safeText); xmlStr.AppendLiteral(" <"); nsAutoString primaryEmail; listCard->GetPrimaryEmail(primaryEmail); // use ScanTXT to convert < > & to safe values. nsString safeText2; rv = conv->ScanTXT(primaryEmail, mozITXTToHTMLConv::kEntities, safeText2); NS_ENSURE_SUCCESS(rv, rv); xmlStr.Append(safeText2); xmlStr.AppendLiteral(">\n"); } xmlStr.AppendLiteral("
"); } xmlStr.AppendLiteral("
"); rv = AppendSection(HOME_ATTRS_ARRAY, sizeof(HOME_ATTRS_ARRAY) / sizeof(AppendItem), u"headingHome"_ns, bundle, conv, xmlStr); rv = AppendSection(WORK_ATTRS_ARRAY, sizeof(WORK_ATTRS_ARRAY) / sizeof(AppendItem), u"headingWork"_ns, bundle, conv, xmlStr); xmlStr.AppendLiteral("
"); aXMLSubstr = xmlStr; return NS_OK; } nsresult nsAbCardProperty::AppendSection( const AppendItem* aArray, int16_t aCount, const nsString& aHeading, nsIStringBundle* aBundle, mozITXTToHTMLConv* aConv, nsString& aResult) { nsresult rv = NS_OK; aResult.AppendLiteral("
"); nsString attrValue; bool sectionIsEmpty = true; int16_t i = 0; for (i = 0; i < aCount; i++) { rv = GetPropertyAsAString(aArray[i].mColumn, attrValue); if (NS_SUCCEEDED(rv) && !attrValue.IsEmpty()) sectionIsEmpty = false; } if (!sectionIsEmpty && !aHeading.IsEmpty()) { nsString heading; rv = aBundle->GetStringFromName(NS_ConvertUTF16toUTF8(aHeading).get(), heading); NS_ENSURE_SUCCESS(rv, rv); aResult.AppendLiteral(""); aResult.Append(heading); aResult.AppendLiteral(""); } for (i = 0; i < aCount; i++) { switch (aArray[i].mAppendType) { case eAppendLine: rv = AppendLine(aArray[i], aConv, aResult); break; case eAppendLabel: rv = AppendLabel(aArray[i], aBundle, aConv, aResult); break; case eAppendCityStateZip: rv = AppendCityStateZip(aArray[i], aBundle, aConv, aResult); break; default: rv = NS_ERROR_FAILURE; break; } if (NS_FAILED(rv)) { NS_WARNING("append item failed"); break; } } aResult.AppendLiteral("
"); return rv; } nsresult nsAbCardProperty::AppendLine(const AppendItem& aItem, mozITXTToHTMLConv* aConv, nsString& aResult) { NS_ENSURE_ARG_POINTER(aConv); nsString attrValue; nsresult rv = GetPropertyAsAString(aItem.mColumn, attrValue); if (NS_FAILED(rv) || attrValue.IsEmpty()) return NS_OK; aResult.Append(char16_t('<')); aResult.Append(NS_ConvertUTF8toUTF16(aItem.mColumn)); aResult.Append(char16_t('>')); // use ScanTXT to convert < > & to safe values. nsString safeText; rv = aConv->ScanTXT(attrValue, mozITXTToHTMLConv::kEntities, safeText); NS_ENSURE_SUCCESS(rv, rv); aResult.Append(safeText); aResult.AppendLiteral("')); return NS_OK; } nsresult nsAbCardProperty::AppendLabel(const AppendItem& aItem, nsIStringBundle* aBundle, mozITXTToHTMLConv* aConv, nsString& aResult) { NS_ENSURE_ARG_POINTER(aBundle); nsresult rv; nsString label, attrValue; rv = GetPropertyAsAString(aItem.mColumn, attrValue); if (NS_FAILED(rv) || attrValue.IsEmpty()) return NS_OK; rv = aBundle->GetStringFromName(aItem.mLabel, label); NS_ENSURE_SUCCESS(rv, rv); aResult.AppendLiteral(""); rv = AppendLine(aItem, aConv, aResult); NS_ENSURE_SUCCESS(rv, rv); aResult.AppendLiteral(""); return NS_OK; } nsresult nsAbCardProperty::AppendCityStateZip(const AppendItem& aItem, nsIStringBundle* aBundle, mozITXTToHTMLConv* aConv, nsString& aResult) { NS_ENSURE_ARG_POINTER(aBundle); nsresult rv; AppendItem item; const char *statePropName, *zipPropName; if (strcmp(aItem.mColumn, kHomeCityProperty) == 0) { statePropName = kHomeStateProperty; zipPropName = kHomeZipCodeProperty; } else { statePropName = kWorkStateProperty; zipPropName = kWorkZipCodeProperty; } nsAutoString cityResult, stateResult, zipResult; rv = AppendLine(aItem, aConv, cityResult); NS_ENSURE_SUCCESS(rv, rv); item.mColumn = statePropName; item.mLabel = ""; item.mAppendType = eAppendUndefined; rv = AppendLine(item, aConv, stateResult); NS_ENSURE_SUCCESS(rv, rv); item.mColumn = zipPropName; rv = AppendLine(item, aConv, zipResult); NS_ENSURE_SUCCESS(rv, rv); nsString formattedString; if (!cityResult.IsEmpty() && !stateResult.IsEmpty() && !zipResult.IsEmpty()) { AutoTArray formatStrings = {cityResult, stateResult, zipResult}; rv = aBundle->FormatStringFromName("cityAndStateAndZip", formatStrings, formattedString); NS_ENSURE_SUCCESS(rv, rv); } else if (!cityResult.IsEmpty() && !stateResult.IsEmpty() && zipResult.IsEmpty()) { AutoTArray formatStrings = {cityResult, stateResult}; rv = aBundle->FormatStringFromName("cityAndStateNoZip", formatStrings, formattedString); NS_ENSURE_SUCCESS(rv, rv); } else if ((!cityResult.IsEmpty() && stateResult.IsEmpty() && !zipResult.IsEmpty()) || (cityResult.IsEmpty() && !stateResult.IsEmpty() && !zipResult.IsEmpty())) { AutoTArray formatStrings = { cityResult.IsEmpty() ? stateResult : cityResult, zipResult}; rv = aBundle->FormatStringFromName("cityOrStateAndZip", formatStrings, formattedString); NS_ENSURE_SUCCESS(rv, rv); } else { if (!cityResult.IsEmpty()) formattedString = cityResult; else if (!stateResult.IsEmpty()) formattedString = stateResult; else formattedString = zipResult; } aResult.Append(formattedString); return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GenerateName(int32_t aGenerateFormat, nsIStringBundle* aBundle, nsAString& aResult) { aResult.Truncate(); // Cache the first and last names nsAutoString firstName, lastName; GetFirstName(firstName); GetLastName(lastName); // No need to check for aBundle present straight away, only do that if we're // actually going to use it. if (aGenerateFormat == GENERATE_DISPLAY_NAME) GetDisplayName(aResult); else if (lastName.IsEmpty()) aResult = firstName; else if (firstName.IsEmpty()) aResult = lastName; else { nsresult rv; nsCOMPtr bundle(aBundle); if (!bundle) { nsCOMPtr stringBundleService = mozilla::components::StringBundle::Service(); NS_ENSURE_TRUE(stringBundleService, NS_ERROR_UNEXPECTED); rv = stringBundleService->CreateBundle(sAddrbookProperties, getter_AddRefs(bundle)); NS_ENSURE_SUCCESS(rv, rv); } nsString result; if (aGenerateFormat == GENERATE_LAST_FIRST_ORDER) { AutoTArray stringParams = {lastName, firstName}; rv = bundle->FormatStringFromName("lastFirstFormat", stringParams, result); } else { AutoTArray stringParams = {firstName, lastName}; rv = bundle->FormatStringFromName("firstLastFormat", stringParams, result); } NS_ENSURE_SUCCESS(rv, rv); aResult.Assign(result); } if (aResult.IsEmpty()) { // The normal names have failed, does this card have a company name? If so, // use that instead, because that is likely to be more meaningful than an // email address. // // If this errors, the string isn't found and we'll fall into the next // check. (void)GetPropertyAsAString(kCompanyProperty, aResult); } if (aResult.IsEmpty()) { // see bug #211078 // if there is no generated name at this point // use the userid from the email address // it is better than nothing. GetPrimaryEmail(aResult); int32_t index = aResult.FindChar('@'); if (index != -1) aResult.SetLength(index); } return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GeneratePhoneticName(bool aLastNameFirst, nsAString& aResult) { nsAutoString firstName, lastName; GetPropertyAsAString(kPhoneticFirstNameProperty, firstName); GetPropertyAsAString(kPhoneticLastNameProperty, lastName); if (aLastNameFirst) { aResult = lastName; aResult += firstName; } else { aResult = firstName; aResult += lastName; } return NS_OK; } NS_IMETHODIMP nsAbCardProperty::GenerateChatName(nsAString& aResult) { aResult.Truncate(); #define CHECK_CHAT_PROPERTY(aProtocol) \ if (NS_SUCCEEDED(GetPropertyAsAString(k##aProtocol##Property, aResult)) && \ !aResult.IsEmpty()) \ return NS_OK CHECK_CHAT_PROPERTY(Gtalk); CHECK_CHAT_PROPERTY(AIM); CHECK_CHAT_PROPERTY(Yahoo); CHECK_CHAT_PROPERTY(Skype); CHECK_CHAT_PROPERTY(QQ); CHECK_CHAT_PROPERTY(MSN); CHECK_CHAT_PROPERTY(ICQ); CHECK_CHAT_PROPERTY(XMPP); CHECK_CHAT_PROPERTY(IRC); return NS_OK; }