diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/base/src/nsMsgAccount.cpp | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mailnews/base/src/nsMsgAccount.cpp')
-rw-r--r-- | comm/mailnews/base/src/nsMsgAccount.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/nsMsgAccount.cpp b/comm/mailnews/base/src/nsMsgAccount.cpp new file mode 100644 index 0000000000..8751e4cdde --- /dev/null +++ b/comm/mailnews/base/src/nsMsgAccount.cpp @@ -0,0 +1,413 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "prprf.h" +#include "plstr.h" +#include "prmem.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsCRTGlue.h" +#include "nsCOMPtr.h" +#include "nsIMsgFolderNotificationService.h" +#include "nsPrintfCString.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsMsgAccount.h" +#include "nsIMsgAccount.h" +#include "nsIMsgAccountManager.h" +#include "nsIObserverService.h" +#include "mozilla/Services.h" +#include "nsServiceManagerUtils.h" +#include "nsMemory.h" +#include "nsComponentManagerUtils.h" +#include "nsMsgUtils.h" + +NS_IMPL_ISUPPORTS(nsMsgAccount, nsIMsgAccount) + +nsMsgAccount::nsMsgAccount() + : m_identitiesValid(false), mTriedToGetServer(false) {} + +nsMsgAccount::~nsMsgAccount() {} + +nsresult nsMsgAccount::getPrefService() { + if (m_prefs) return NS_OK; + + nsresult rv; + NS_ENSURE_FALSE(m_accountKey.IsEmpty(), NS_ERROR_NOT_INITIALIZED); + nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString accountRoot("mail.account."); + accountRoot.Append(m_accountKey); + accountRoot.Append('.'); + return prefs->GetBranch(accountRoot.get(), getter_AddRefs(m_prefs)); +} + +NS_IMETHODIMP +nsMsgAccount::GetIncomingServer(nsIMsgIncomingServer** aIncomingServer) { + NS_ENSURE_ARG_POINTER(aIncomingServer); + + // create the incoming server lazily + if (!mTriedToGetServer && !m_incomingServer) { + mTriedToGetServer = true; + // ignore the error (and return null), but it's still bad so warn + mozilla::DebugOnly<nsresult> rv = createIncomingServer(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "couldn't lazily create the server\n"); + } + + NS_IF_ADDREF(*aIncomingServer = m_incomingServer); + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgAccount::CreateServer() { + if (m_incomingServer) return NS_ERROR_ALREADY_INITIALIZED; + return createIncomingServer(); +} + +nsresult nsMsgAccount::createIncomingServer() { + // from here, load mail.account.myaccount.server + // Load the incoming server + // + // ex) mail.account.myaccount.server = "myserver" + + nsresult rv = getPrefService(); + NS_ENSURE_SUCCESS(rv, rv); + + // get the "server" pref + nsCString serverKey; + rv = m_prefs->GetCharPref("server", serverKey); + NS_ENSURE_SUCCESS(rv, rv); + + // get the server from the account manager + nsCOMPtr<nsIMsgAccountManager> accountManager = + do_GetService("@mozilla.org/messenger/account-manager;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMsgIncomingServer> server; + rv = accountManager->GetIncomingServer(serverKey, getter_AddRefs(server)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCString hostname; + rv = server->GetHostName(hostname); + NS_ENSURE_SUCCESS(rv, rv); + if (hostname.IsEmpty()) { + NS_WARNING( + nsPrintfCString("Server had no hostname; key=%s", serverKey.get()) + .get()); + return NS_ERROR_UNEXPECTED; + } + + // store the server in this structure + m_incomingServer = server; + accountManager->NotifyServerLoaded(server); + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgAccount::SetIncomingServer(nsIMsgIncomingServer* aIncomingServer) { + NS_ENSURE_ARG_POINTER(aIncomingServer); + + nsCString key; + nsresult rv = aIncomingServer->GetKey(key); + + if (NS_SUCCEEDED(rv)) { + rv = getPrefService(); + NS_ENSURE_SUCCESS(rv, rv); + m_prefs->SetCharPref("server", key); + } + + m_incomingServer = aIncomingServer; + + bool serverValid; + (void)aIncomingServer->GetValid(&serverValid); + // only notify server loaded if server is valid so + // account manager only gets told about finished accounts. + if (serverValid) { + // this is the point at which we can notify listeners about the + // creation of the root folder, which implies creation of the new server. + nsCOMPtr<nsIMsgFolder> rootFolder; + rv = aIncomingServer->GetRootFolder(getter_AddRefs(rootFolder)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIFolderListener> mailSession = + do_GetService("@mozilla.org/messenger/services/session;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + mailSession->OnFolderAdded(nullptr, rootFolder); + nsCOMPtr<nsIMsgFolderNotificationService> notifier( + do_GetService("@mozilla.org/messenger/msgnotificationservice;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + notifier->NotifyFolderAdded(rootFolder); + + nsCOMPtr<nsIMsgAccountManager> accountManager = + do_GetService("@mozilla.org/messenger/account-manager;1", &rv); + if (NS_SUCCEEDED(rv)) accountManager->NotifyServerLoaded(aIncomingServer); + + // Force built-in folders to be created and discovered. Then, notify + // listeners about them. + nsTArray<RefPtr<nsIMsgFolder>> subFolders; + rv = rootFolder->GetSubFolders(subFolders); + NS_ENSURE_SUCCESS(rv, rv); + + for (nsIMsgFolder* msgFolder : subFolders) { + mailSession->OnFolderAdded(rootFolder, msgFolder); + notifier->NotifyFolderAdded(msgFolder); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsMsgAccount::GetIdentities(nsTArray<RefPtr<nsIMsgIdentity>>& identities) { + NS_ENSURE_TRUE(m_identitiesValid, NS_ERROR_FAILURE); + identities.Clear(); + identities.AppendElements(m_identities); + return NS_OK; +} + +/* + * set up the m_identities array + * do not call this more than once or we'll leak. + */ +nsresult nsMsgAccount::createIdentities() { + NS_ENSURE_FALSE(m_identitiesValid, NS_ERROR_FAILURE); + + nsresult rv; + m_identities.Clear(); + + nsCString identityKey; + rv = getPrefService(); + NS_ENSURE_SUCCESS(rv, rv); + + m_prefs->GetCharPref("identities", identityKey); + if (identityKey.IsEmpty()) { + // not an error if no identities, but strtok will be unhappy. + m_identitiesValid = true; + return NS_OK; + } + // get the server from the account manager + nsCOMPtr<nsIMsgAccountManager> accountManager = + do_GetService("@mozilla.org/messenger/account-manager;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + char* newStr = identityKey.BeginWriting(); + char* token = NS_strtok(",", &newStr); + + // temporaries used inside the loop + nsCOMPtr<nsIMsgIdentity> identity; + nsAutoCString key; + + // iterate through id1,id2, etc + while (token) { + key = token; + key.StripWhitespace(); + + // create the account + rv = accountManager->GetIdentity(key, getter_AddRefs(identity)); + if (NS_SUCCEEDED(rv)) { + m_identities.AppendElement(identity); + } + + // advance to next key, if any + token = NS_strtok(",", &newStr); + } + + m_identitiesValid = true; + return rv; +} + +/* attribute nsIMsgIdentity defaultIdentity; */ +NS_IMETHODIMP +nsMsgAccount::GetDefaultIdentity(nsIMsgIdentity** aDefaultIdentity) { + NS_ENSURE_ARG_POINTER(aDefaultIdentity); + NS_ENSURE_TRUE(m_identitiesValid, NS_ERROR_NOT_INITIALIZED); + + // Default identity is the first in the list. + if (m_identities.IsEmpty()) { + *aDefaultIdentity = nullptr; + } else { + NS_IF_ADDREF(*aDefaultIdentity = m_identities[0]); + } + return NS_OK; +} + +NS_IMETHODIMP +nsMsgAccount::SetDefaultIdentity(nsIMsgIdentity* aDefaultIdentity) { + NS_ENSURE_TRUE(m_identitiesValid, NS_ERROR_FAILURE); + + auto position = m_identities.IndexOf(aDefaultIdentity); + if (position == m_identities.NoIndex) { + return NS_ERROR_FAILURE; + } + + // Move it to the front of the list. + m_identities.RemoveElementAt(position); + m_identities.InsertElementAt(0, aDefaultIdentity); + + nsresult rv = saveIdentitiesPref(); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(aDefaultIdentity, "account-default-identity-changed", + NS_ConvertUTF8toUTF16(m_accountKey).get()); + } + + return NS_OK; +} + +/* void addIdentity (in nsIMsgIdentity identity); */ +NS_IMETHODIMP +nsMsgAccount::AddIdentity(nsIMsgIdentity* identity) { + NS_ENSURE_ARG_POINTER(identity); + NS_ENSURE_TRUE(m_identitiesValid, NS_ERROR_FAILURE); + + // hack hack - need to add this to the list of identities. + // for now just treat this as a Setxxx accessor + // when this is actually implemented, don't refcount the default identity + nsCString key; + nsresult rv = identity->GetKey(key); + + if (NS_SUCCEEDED(rv)) { + nsCString identityList; + m_prefs->GetCharPref("identities", identityList); + + nsAutoCString newIdentityList(identityList); + + nsAutoCString testKey; // temporary to strip whitespace + bool foundIdentity = false; // if the input identity is found + + if (!identityList.IsEmpty()) { + char* newStr = identityList.BeginWriting(); + char* token = NS_strtok(",", &newStr); + + // look for the identity key that we're adding + while (token) { + testKey = token; + testKey.StripWhitespace(); + + if (testKey.Equals(key)) foundIdentity = true; + + token = NS_strtok(",", &newStr); + } + } + + // if it didn't already exist, append it + if (!foundIdentity) { + if (newIdentityList.IsEmpty()) + newIdentityList = key; + else { + newIdentityList.Append(','); + newIdentityList.Append(key); + } + } + + m_prefs->SetCharPref("identities", newIdentityList); + + // now add it to the in-memory list + m_identities.AppendElement(identity); + + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(identity, "account-identity-added", + NS_ConvertUTF8toUTF16(key).get()); + } + } + + return NS_OK; +} + +/* void removeIdentity (in nsIMsgIdentity identity); */ +NS_IMETHODIMP +nsMsgAccount::RemoveIdentity(nsIMsgIdentity* aIdentity) { + NS_ENSURE_ARG_POINTER(aIdentity); + NS_ENSURE_TRUE(m_identitiesValid, NS_ERROR_FAILURE); + + // At least one identity must stay after the delete. + NS_ENSURE_TRUE(m_identities.Length() > 1, NS_ERROR_FAILURE); + + nsCString key; + nsresult rv = aIdentity->GetKey(key); + NS_ENSURE_SUCCESS(rv, rv); + + if (!m_identities.RemoveElement(aIdentity)) { + return NS_ERROR_FAILURE; + } + + // Notify before clearing the pref values, so we do not get the superfluous + // update notifications. + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(aIdentity, "account-identity-removed", + NS_ConvertUTF8toUTF16(key).get()); + } + + // Clear out the actual pref values associated with the identity. + aIdentity->ClearAllValues(); + return saveIdentitiesPref(); +} + +nsresult nsMsgAccount::saveIdentitiesPref() { + nsAutoCString newIdentityList; + + // Iterate over the existing identities and build the pref value, + // a string of identity keys: id1, id2, idX... + nsCString key; + bool first = true; + for (auto identity : m_identities) { + identity->GetKey(key); + + if (first) { + newIdentityList = key; + first = false; + } else { + newIdentityList.Append(','); + newIdentityList.Append(key); + } + } + + // Save the pref. + m_prefs->SetCharPref("identities", newIdentityList); + + return NS_OK; +} + +NS_IMETHODIMP nsMsgAccount::GetKey(nsACString& accountKey) { + accountKey = m_accountKey; + return NS_OK; +} + +NS_IMETHODIMP +nsMsgAccount::SetKey(const nsACString& accountKey) { + m_accountKey = accountKey; + m_prefs = nullptr; + m_identitiesValid = false; + m_identities.Clear(); + return createIdentities(); +} + +NS_IMETHODIMP +nsMsgAccount::ToString(nsAString& aResult) { + nsAutoString val; + aResult.AssignLiteral("[nsIMsgAccount: "); + aResult.Append(NS_ConvertASCIItoUTF16(m_accountKey)); + aResult.Append(']'); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgAccount::ClearAllValues() { + nsTArray<nsCString> prefNames; + nsresult rv = m_prefs->GetChildList("", prefNames); + NS_ENSURE_SUCCESS(rv, rv); + + for (auto& prefName : prefNames) { + m_prefs->ClearUserPref(prefName.get()); + } + + return NS_OK; +} |