summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/src/nsMsgAccount.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/base/src/nsMsgAccount.cpp')
-rw-r--r--comm/mailnews/base/src/nsMsgAccount.cpp413
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;
+}