1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "nsIPrefService.h"
7 #include "nsIPrefBranch.h"
8 #include "nsSmtpServer.h"
9 #include "nsNetUtil.h"
10 #include "nsIAuthPrompt.h"
11 #include "nsMsgUtils.h"
12 #include "nsIMsgAccountManager.h"
13 #include "nsMsgBaseCID.h"
14 #include "nsISmtpService.h"
15 #include "nsMsgCompCID.h"
16 #include "nsILoginInfo.h"
17 #include "nsILoginManager.h"
18 #include "nsMemory.h"
19 #include "nsIObserverService.h"
20 
21 NS_IMPL_ADDREF(nsSmtpServer)
NS_IMPL_RELEASE(nsSmtpServer)22 NS_IMPL_RELEASE(nsSmtpServer)
23 NS_INTERFACE_MAP_BEGIN(nsSmtpServer)
24   NS_INTERFACE_MAP_ENTRY(nsISmtpServer)
25   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
26   NS_INTERFACE_MAP_ENTRY(nsIObserver)
27   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISmtpServer)
28 NS_INTERFACE_MAP_END
29 
30 nsSmtpServer::nsSmtpServer() : mKey("") {
31   m_logonFailed = false;
32   getPrefs();
33 }
34 
~nsSmtpServer()35 nsSmtpServer::~nsSmtpServer() {}
36 
Init()37 nsresult nsSmtpServer::Init() {
38   // We need to know when the password manager changes.
39   nsCOMPtr<nsIObserverService> observerService =
40       mozilla::services::GetObserverService();
41   NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
42 
43   observerService->AddObserver(this, "passwordmgr-storage-changed", false);
44   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
45 
46   return NS_OK;
47 }
48 
49 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)50 nsSmtpServer::Observe(nsISupports* aSubject, const char* aTopic,
51                       const char16_t* aData) {
52   // When the state of the password manager changes we need to clear the
53   // password from the cache in case the user just removed it.
54   if (strcmp(aTopic, "passwordmgr-storage-changed") == 0) {
55     // Check that the notification is for this server.
56     nsCOMPtr<nsILoginInfo> loginInfo = do_QueryInterface(aSubject);
57     if (loginInfo) {
58       nsAutoString hostnameInfo;
59       loginInfo->GetHostname(hostnameInfo);
60       nsAutoCString hostname;
61       GetHostname(hostname);
62       nsAutoCString fullName;
63       fullName = "smtp://"_ns + hostname;
64       if (!fullName.Equals(NS_ConvertUTF16toUTF8(hostnameInfo))) return NS_OK;
65     }
66     m_password.Truncate();
67   } else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
68     // Now remove ourselves from the observer service as well.
69     nsCOMPtr<nsIObserverService> observerService =
70         mozilla::services::GetObserverService();
71     NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
72 
73     observerService->RemoveObserver(this, "passwordmgr-storage-changed");
74     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
75   }
76 
77   return NS_OK;
78 }
79 
80 NS_IMETHODIMP
GetKey(char ** aKey)81 nsSmtpServer::GetKey(char** aKey) {
82   if (!aKey) return NS_ERROR_NULL_POINTER;
83   if (mKey.IsEmpty())
84     *aKey = nullptr;
85   else
86     *aKey = ToNewCString(mKey);
87   return NS_OK;
88 }
89 
90 NS_IMETHODIMP
SetKey(const char * aKey)91 nsSmtpServer::SetKey(const char* aKey) {
92   NS_ASSERTION(aKey, "Bad key pointer");
93   mKey = aKey;
94   return getPrefs();
95 }
96 
getPrefs()97 nsresult nsSmtpServer::getPrefs() {
98   nsresult rv;
99   nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
100   if (NS_FAILED(rv)) return rv;
101 
102   nsAutoCString branchName;
103   branchName.AssignLiteral("mail.smtpserver.");
104   branchName += mKey;
105   branchName.Append('.');
106   rv = prefs->GetBranch(branchName.get(), getter_AddRefs(mPrefBranch));
107   if (NS_FAILED(rv)) return rv;
108 
109   if (!mDefPrefBranch) {
110     branchName.AssignLiteral("mail.smtpserver.default.");
111     rv = prefs->GetBranch(branchName.get(), getter_AddRefs(mDefPrefBranch));
112     if (NS_FAILED(rv)) return rv;
113   }
114 
115   return NS_OK;
116 }
117 
118 // This function is intentionally called the same as in nsIMsgIncomingServer.
OnUserOrHostNameChanged(const nsACString & oldName,const nsACString & newName,bool hostnameChanged)119 nsresult nsSmtpServer::OnUserOrHostNameChanged(const nsACString& oldName,
120                                                const nsACString& newName,
121                                                bool hostnameChanged) {
122   // Reset password so that users are prompted for new password for the new
123   // user/host.
124   (void)ForgetPassword();
125 
126   return NS_OK;
127 }
128 
129 NS_IMETHODIMP
GetHostname(nsACString & aHostname)130 nsSmtpServer::GetHostname(nsACString& aHostname) {
131   nsCString result;
132   nsresult rv = mPrefBranch->GetCharPref("hostname", result);
133   if (NS_FAILED(rv))
134     aHostname.Truncate();
135   else
136     aHostname = result;
137 
138   return NS_OK;
139 }
140 
141 NS_IMETHODIMP
SetHostname(const nsACString & aHostname)142 nsSmtpServer::SetHostname(const nsACString& aHostname) {
143   nsCString oldName;
144   nsresult rv = GetHostname(oldName);
145   NS_ENSURE_SUCCESS(rv, rv);
146 
147   // A few things to take care of if we're changing the hostname.
148   if (!oldName.Equals(aHostname, nsCaseInsensitiveCStringComparator)) {
149     rv = OnUserOrHostNameChanged(oldName, aHostname, true);
150     NS_ENSURE_SUCCESS(rv, rv);
151   }
152 
153   if (!aHostname.IsEmpty())
154     return mPrefBranch->SetCharPref("hostname", aHostname);
155 
156   // If the pref value is already empty, ClearUserPref will return
157   // NS_ERROR_UNEXPECTED, so don't check the rv here.
158   (void)mPrefBranch->ClearUserPref("hostname");
159   return NS_OK;
160 }
161 
162 NS_IMETHODIMP
GetDescription(nsACString & aDescription)163 nsSmtpServer::GetDescription(nsACString& aDescription) {
164   nsCString temp;
165   mPrefBranch->GetCharPref("description", temp);
166   aDescription.Assign(temp);
167   return NS_OK;
168 }
169 
170 NS_IMETHODIMP
SetDescription(const nsACString & aDescription)171 nsSmtpServer::SetDescription(const nsACString& aDescription) {
172   if (!aDescription.IsEmpty())
173     return mPrefBranch->SetCharPref("description", aDescription);
174   else
175     mPrefBranch->ClearUserPref("description");
176   return NS_OK;
177 }
178 
179 // if GetPort returns 0, it means default port
180 NS_IMETHODIMP
GetPort(int32_t * aPort)181 nsSmtpServer::GetPort(int32_t* aPort) {
182   NS_ENSURE_ARG_POINTER(aPort);
183   if (NS_FAILED(mPrefBranch->GetIntPref("port", aPort))) *aPort = 0;
184   return NS_OK;
185 }
186 
187 NS_IMETHODIMP
SetPort(int32_t aPort)188 nsSmtpServer::SetPort(int32_t aPort) {
189   if (aPort) return mPrefBranch->SetIntPref("port", aPort);
190 
191   mPrefBranch->ClearUserPref("port");
192   return NS_OK;
193 }
194 
195 NS_IMETHODIMP
GetDisplayname(char ** aDisplayname)196 nsSmtpServer::GetDisplayname(char** aDisplayname) {
197   nsresult rv;
198   NS_ENSURE_ARG_POINTER(aDisplayname);
199 
200   nsCString hostname;
201   rv = mPrefBranch->GetCharPref("hostname", hostname);
202   if (NS_FAILED(rv)) {
203     *aDisplayname = nullptr;
204     return NS_OK;
205   }
206   int32_t port;
207   rv = mPrefBranch->GetIntPref("port", &port);
208   if (NS_FAILED(rv)) port = 0;
209 
210   if (port) {
211     hostname.Append(':');
212     hostname.AppendInt(port);
213   }
214 
215   *aDisplayname = ToNewCString(hostname);
216   return NS_OK;
217 }
218 
219 NS_IMETHODIMP
GetSocketType(int32_t * socketType)220 nsSmtpServer::GetSocketType(int32_t* socketType) {
221   NS_ENSURE_ARG_POINTER(socketType);
222   getIntPrefWithDefault("try_ssl", socketType, 0);
223   return NS_OK;
224 }
225 
226 NS_IMETHODIMP
SetSocketType(int32_t socketType)227 nsSmtpServer::SetSocketType(int32_t socketType) {
228   return mPrefBranch->SetIntPref("try_ssl", socketType);
229 }
230 
231 NS_IMETHODIMP
GetHelloArgument(nsACString & aHelloArgument)232 nsSmtpServer::GetHelloArgument(nsACString& aHelloArgument) {
233   nsresult rv;
234   rv = mPrefBranch->GetCharPref("hello_argument", aHelloArgument);
235   if (NS_FAILED(rv)) {
236     rv = mDefPrefBranch->GetCharPref("hello_argument", aHelloArgument);
237     if (NS_FAILED(rv)) aHelloArgument.Truncate();
238   }
239   return NS_OK;
240 }
241 
242 NS_IMETHODIMP
GetAuthMethod(int32_t * authMethod)243 nsSmtpServer::GetAuthMethod(int32_t* authMethod) {
244   NS_ENSURE_ARG_POINTER(authMethod);
245   getIntPrefWithDefault("authMethod", authMethod, 3);
246   return NS_OK;
247 }
248 
getIntPrefWithDefault(const char * prefName,int32_t * val,int32_t defVal)249 void nsSmtpServer::getIntPrefWithDefault(const char* prefName, int32_t* val,
250                                          int32_t defVal) {
251   nsresult rv = mPrefBranch->GetIntPref(prefName, val);
252   if (NS_SUCCEEDED(rv)) return;
253 
254   rv = mDefPrefBranch->GetIntPref(prefName, val);
255   if (NS_FAILED(rv))
256     // last resort
257     *val = defVal;
258 }
259 
260 NS_IMETHODIMP
SetAuthMethod(int32_t authMethod)261 nsSmtpServer::SetAuthMethod(int32_t authMethod) {
262   return mPrefBranch->SetIntPref("authMethod", authMethod);
263 }
264 
265 NS_IMETHODIMP
GetUsername(nsACString & aUsername)266 nsSmtpServer::GetUsername(nsACString& aUsername) {
267   nsCString result;
268   nsresult rv = mPrefBranch->GetCharPref("username", result);
269   if (NS_FAILED(rv))
270     aUsername.Truncate();
271   else
272     aUsername = result;
273   return NS_OK;
274 }
275 
276 NS_IMETHODIMP
SetUsername(const nsACString & aUsername)277 nsSmtpServer::SetUsername(const nsACString& aUsername) {
278   // Need to take care of few things if we're changing the username.
279   nsCString oldName;
280   nsresult rv = GetUsername(oldName);
281   NS_ENSURE_SUCCESS(rv, rv);
282 
283   if (!oldName.Equals(aUsername)) {
284     rv = OnUserOrHostNameChanged(oldName, aUsername, false);
285     NS_ENSURE_SUCCESS(rv, rv);
286   }
287 
288   if (!aUsername.IsEmpty())
289     return mPrefBranch->SetCharPref("username", aUsername);
290 
291   // If the pref value is already empty, ClearUserPref will return
292   // NS_ERROR_UNEXPECTED, so don't check the rv here.
293   (void)mPrefBranch->ClearUserPref("username");
294   return NS_OK;
295 }
296 
297 NS_IMETHODIMP
GetClientid(nsACString & aClientid)298 nsSmtpServer::GetClientid(nsACString& aClientid) {
299   nsresult rv;
300   rv = mPrefBranch->GetCharPref("clientid", aClientid);
301   if (NS_FAILED(rv)) {
302     rv = mDefPrefBranch->GetCharPref("clientid", aClientid);
303     if (NS_FAILED(rv)) aClientid.Truncate();
304   }
305   return NS_OK;
306 }
307 
308 NS_IMETHODIMP
SetClientid(const nsACString & aClientid)309 nsSmtpServer::SetClientid(const nsACString& aClientid) {
310   if (!aClientid.IsEmpty())
311     return mPrefBranch->SetCharPref("clientid", aClientid);
312 
313   // If the pref value is already empty, ClearUserPref will return
314   // NS_ERROR_UNEXPECTED, so don't check the rv here.
315   mPrefBranch->ClearUserPref("clientid");
316   return NS_OK;
317 }
318 
GetClientidEnabled(bool * aClientidEnabled)319 NS_IMETHODIMP nsSmtpServer::GetClientidEnabled(bool* aClientidEnabled) {
320   NS_ENSURE_ARG_POINTER(aClientidEnabled);
321   nsresult rv;
322   rv = mPrefBranch->GetBoolPref("clientidEnabled", aClientidEnabled);
323   if (NS_FAILED(rv)) {
324     rv = mDefPrefBranch->GetBoolPref("clientidEnabled", aClientidEnabled);
325     if (NS_FAILED(rv)) *aClientidEnabled = false;
326   }
327   return NS_OK;
328 }
329 
SetClientidEnabled(bool aClientidEnabled)330 NS_IMETHODIMP nsSmtpServer::SetClientidEnabled(bool aClientidEnabled) {
331   return mPrefBranch->SetBoolPref("clientidEnabled", aClientidEnabled);
332 }
333 
334 NS_IMETHODIMP
GetPassword(nsAString & aPassword)335 nsSmtpServer::GetPassword(nsAString& aPassword) {
336   if (m_password.IsEmpty() && !m_logonFailed) {
337     // try to avoid prompting the user for another password. If the user has set
338     // the appropriate pref, we'll use the password from an incoming server, if
339     // the user has already logged onto that server.
340 
341     // if this is set, we'll only use this, and not the other prefs
342     // user_pref("mail.smtpserver.smtp1.incomingAccount", "server1");
343 
344     // if this is set, we'll accept an exact match of user name and server
345     // user_pref("mail.smtp.useMatchingHostNameServer", true);
346 
347     // if this is set, and we don't find an exact match of user and host name,
348     // we'll accept a match of username and domain, where domain
349     // is everything after the first '.'
350     // user_pref("mail.smtp.useMatchingDomainServer", true);
351 
352     nsCString accountKey;
353     bool useMatchingHostNameServer = false;
354     bool useMatchingDomainServer = false;
355     mPrefBranch->GetCharPref("incomingAccount", accountKey);
356 
357     nsCOMPtr<nsIMsgAccountManager> accountManager =
358         do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
359     nsCOMPtr<nsIMsgIncomingServer> incomingServerToUse;
360     if (accountManager) {
361       if (!accountKey.IsEmpty())
362         accountManager->GetIncomingServer(accountKey,
363                                           getter_AddRefs(incomingServerToUse));
364       else {
365         nsresult rv;
366         nsCOMPtr<nsIPrefBranch> prefBranch(
367             do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
368         NS_ENSURE_SUCCESS(rv, rv);
369         prefBranch->GetBoolPref("mail.smtp.useMatchingHostNameServer",
370                                 &useMatchingHostNameServer);
371         prefBranch->GetBoolPref("mail.smtp.useMatchingDomainServer",
372                                 &useMatchingDomainServer);
373         if (useMatchingHostNameServer || useMatchingDomainServer) {
374           nsCString userName;
375           nsCString hostName;
376           GetHostname(hostName);
377           GetUsername(userName);
378           if (useMatchingHostNameServer)
379             // pass in empty type and port=0, to match imap and pop3.
380             accountManager->FindRealServer(userName, hostName, EmptyCString(),
381                                            0,
382                                            getter_AddRefs(incomingServerToUse));
383           int32_t dotPos = -1;
384           if (!incomingServerToUse && useMatchingDomainServer &&
385               (dotPos = hostName.FindChar('.')) != kNotFound) {
386             hostName.Cut(0, dotPos);
387             nsTArray<RefPtr<nsIMsgIncomingServer>> allServers;
388             accountManager->GetAllServers(allServers);
389             for (auto server : allServers) {
390               if (server) {
391                 nsCString serverUserName;
392                 nsCString serverHostName;
393                 server->GetRealUsername(serverUserName);
394                 server->GetRealHostName(serverHostName);
395                 if (serverUserName.Equals(userName)) {
396                   int32_t serverDotPos = serverHostName.FindChar('.');
397                   if (serverDotPos != kNotFound) {
398                     serverHostName.Cut(0, serverDotPos);
399                     if (serverHostName.Equals(hostName)) {
400                       incomingServerToUse = server;
401                       break;
402                     }
403                   }
404                 }
405               }
406             }
407           }
408         }
409       }
410     }
411     if (incomingServerToUse) return incomingServerToUse->GetPassword(aPassword);
412   }
413   aPassword = m_password;
414   return NS_OK;
415 }
416 
417 NS_IMETHODIMP
VerifyLogon(nsIUrlListener * aUrlListener,nsIMsgWindow * aMsgWindow,nsIURI ** aURL)418 nsSmtpServer::VerifyLogon(nsIUrlListener* aUrlListener,
419                           nsIMsgWindow* aMsgWindow, nsIURI** aURL) {
420   nsresult rv;
421   nsCOMPtr<nsISmtpService> smtpService(
422       do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
423   NS_ENSURE_SUCCESS(rv, rv);
424   return smtpService->VerifyLogon(this, aUrlListener, aMsgWindow, aURL);
425 }
426 
427 NS_IMETHODIMP
SetPassword(const nsAString & aPassword)428 nsSmtpServer::SetPassword(const nsAString& aPassword) {
429   m_password = aPassword;
430   return NS_OK;
431 }
432 
GetPasswordWithoutUI()433 nsresult nsSmtpServer::GetPasswordWithoutUI() {
434   nsresult rv;
435   nsCOMPtr<nsILoginManager> loginMgr(
436       do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv));
437   NS_ENSURE_SUCCESS(rv, rv);
438 
439   NS_ConvertASCIItoUTF16 serverUri(GetServerURIInternal(false));
440 
441   nsTArray<RefPtr<nsILoginInfo>> logins;
442   rv = loginMgr->FindLogins(serverUri, EmptyString(), serverUri, logins);
443   // Login manager can produce valid fails, e.g. NS_ERROR_ABORT when a user
444   // cancels the master password dialog. Therefore handle that here, but don't
445   // warn about it.
446   if (NS_FAILED(rv)) return rv;
447   uint32_t numLogins = logins.Length();
448 
449   // Don't abort here, if we didn't find any or failed, then we'll just have
450   // to prompt.
451   if (numLogins > 0) {
452     nsCString serverCUsername;
453     rv = GetUsername(serverCUsername);
454     NS_ConvertASCIItoUTF16 serverUsername(serverCUsername);
455 
456     nsString username;
457     for (uint32_t i = 0; i < numLogins; ++i) {
458       rv = logins[i]->GetUsername(username);
459       NS_ENSURE_SUCCESS(rv, rv);
460 
461       if (username.Equals(serverUsername)) {
462         nsString password;
463         rv = logins[i]->GetPassword(password);
464         NS_ENSURE_SUCCESS(rv, rv);
465 
466         m_password = password;
467         break;
468       }
469     }
470   }
471   return NS_OK;
472 }
473 
474 NS_IMETHODIMP
GetPasswordWithUI(const char16_t * aPromptMessage,const char16_t * aPromptTitle,nsIAuthPrompt * aDialog,nsAString & aPassword)475 nsSmtpServer::GetPasswordWithUI(const char16_t* aPromptMessage,
476                                 const char16_t* aPromptTitle,
477                                 nsIAuthPrompt* aDialog, nsAString& aPassword) {
478   if (!m_password.IsEmpty()) return GetPassword(aPassword);
479 
480   // We need to get a password, but see if we can get it from the password
481   // manager without requiring a prompt.
482   nsresult rv = GetPasswordWithoutUI();
483   if (rv == NS_ERROR_ABORT) return NS_MSG_PASSWORD_PROMPT_CANCELLED;
484 
485   // Now re-check if we've got a password or not, if we have, then we
486   // don't need to prompt the user.
487   if (!m_password.IsEmpty()) {
488     aPassword = m_password;
489     return NS_OK;
490   }
491 
492   NS_ENSURE_ARG_POINTER(aDialog);
493 
494   // PromptPassword needs the username as well.
495   nsCString serverUri(GetServerURIInternal(true));
496 
497   bool okayValue = true;
498 
499   rv = aDialog->PromptPassword(aPromptTitle, aPromptMessage,
500                                NS_ConvertASCIItoUTF16(serverUri).get(),
501                                nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
502                                getter_Copies(aPassword), &okayValue);
503   NS_ENSURE_SUCCESS(rv, rv);
504 
505   // If the user pressed cancel, just return an empty string.
506   if (!okayValue) {
507     aPassword.Truncate();
508     return NS_MSG_PASSWORD_PROMPT_CANCELLED;
509   }
510   rv = SetPassword(aPassword);
511   NS_ENSURE_SUCCESS(rv, rv);
512 
513   return NS_OK;
514 }
515 
516 NS_IMETHODIMP
GetUsernamePasswordWithUI(const char16_t * aPromptMessage,const char16_t * aPromptTitle,nsIAuthPrompt * aDialog,nsACString & aUsername,nsAString & aPassword)517 nsSmtpServer::GetUsernamePasswordWithUI(const char16_t* aPromptMessage,
518                                         const char16_t* aPromptTitle,
519                                         nsIAuthPrompt* aDialog,
520                                         nsACString& aUsername,
521                                         nsAString& aPassword) {
522   nsresult rv;
523   if (!m_password.IsEmpty()) {
524     rv = GetUsername(aUsername);
525     NS_ENSURE_SUCCESS(rv, rv);
526 
527     return GetPassword(aPassword);
528   }
529 
530   NS_ENSURE_ARG_POINTER(aDialog);
531 
532   nsCString serverUri;
533   rv = GetServerURI(serverUri);
534   NS_ENSURE_SUCCESS(rv, rv);
535 
536   nsString uniUsername;
537   bool okayValue = true;
538 
539   rv = aDialog->PromptUsernameAndPassword(
540       aPromptTitle, aPromptMessage, NS_ConvertASCIItoUTF16(serverUri).get(),
541       nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, getter_Copies(uniUsername),
542       getter_Copies(aPassword), &okayValue);
543   NS_ENSURE_SUCCESS(rv, rv);
544 
545   // If the user pressed cancel, just return empty strings.
546   if (!okayValue) {
547     aUsername.Truncate();
548     aPassword.Truncate();
549     return rv;
550   }
551 
552   // We got a username and password back...so remember them.
553   NS_LossyConvertUTF16toASCII username(uniUsername);
554 
555   rv = SetUsername(username);
556   NS_ENSURE_SUCCESS(rv, rv);
557 
558   rv = SetPassword(aPassword);
559   NS_ENSURE_SUCCESS(rv, rv);
560 
561   aUsername = username;
562   return NS_OK;
563 }
564 
565 NS_IMETHODIMP
ForgetPassword()566 nsSmtpServer::ForgetPassword() {
567   nsresult rv;
568   nsCOMPtr<nsILoginManager> loginMgr =
569       do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
570   NS_ENSURE_SUCCESS(rv, rv);
571 
572   // Get the current server URI without the username
573   NS_ConvertASCIItoUTF16 serverUri(GetServerURIInternal(false));
574 
575   nsCString serverCUsername;
576   rv = GetUsername(serverCUsername);
577   NS_ENSURE_SUCCESS(rv, rv);
578 
579   NS_ConvertUTF8toUTF16 serverUsername(serverCUsername);
580 
581   nsTArray<RefPtr<nsILoginInfo>> logins;
582   rv = loginMgr->FindLogins(serverUri, EmptyString(), serverUri, logins);
583   NS_ENSURE_SUCCESS(rv, rv);
584 
585   // There should only be one-login stored for this url, however just in case
586   // there isn't.
587   nsString username;
588   for (uint32_t i = 0; i < logins.Length(); ++i) {
589     if (NS_SUCCEEDED(logins[i]->GetUsername(username)) &&
590         username.Equals(serverUsername)) {
591       // If this fails, just continue, we'll still want to remove the password
592       // from our local cache.
593       loginMgr->RemoveLogin(logins[i]);
594     }
595   }
596 
597   rv = SetPassword(EmptyString());
598   m_logonFailed = true;
599   return rv;
600 }
601 
602 NS_IMETHODIMP
GetServerURI(nsACString & aResult)603 nsSmtpServer::GetServerURI(nsACString& aResult) {
604   aResult = GetServerURIInternal(true);
605   return NS_OK;
606 }
607 
GetServerURIInternal(const bool aIncludeUsername)608 nsCString nsSmtpServer::GetServerURIInternal(const bool aIncludeUsername) {
609   nsCString uri("smtp://"_ns);
610   nsresult rv;
611 
612   if (aIncludeUsername) {
613     nsCString username;
614     rv = GetUsername(username);
615 
616     if (NS_SUCCEEDED(rv) && !username.IsEmpty()) {
617       nsCString escapedUsername;
618       MsgEscapeString(username, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
619       // not all servers have a username
620       uri.Append(escapedUsername);
621       uri.Append('@');
622     }
623   }
624 
625   nsCString hostname;
626   rv = GetHostname(hostname);
627 
628   if (NS_SUCCEEDED(rv) && !hostname.IsEmpty()) {
629     nsCString escapedHostname;
630     MsgEscapeString(hostname, nsINetUtil::ESCAPE_URL_PATH, escapedHostname);
631     // not all servers have a hostname
632     uri.Append(escapedHostname);
633   }
634 
635   return uri;
636 }
637 
638 NS_IMETHODIMP
ClearAllValues()639 nsSmtpServer::ClearAllValues() {
640   nsTArray<nsCString> prefNames;
641   nsresult rv = mPrefBranch->GetChildList("", prefNames);
642   NS_ENSURE_SUCCESS(rv, rv);
643 
644   for (auto& prefName : prefNames) {
645     mPrefBranch->ClearUserPref(prefName.get());
646   }
647 
648   return NS_OK;
649 }
650