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 "prmem.h"
7 #include "plstr.h"
8 #include "prprf.h"
9
10 #include "nsCOMPtr.h"
11 #include "nsIPop3IncomingServer.h"
12 #include "nsPop3IncomingServer.h"
13 #include "nsIPop3Service.h"
14 #include "nsMsgBaseCID.h"
15 #include "nsMsgLocalCID.h"
16 #include "nsMsgFolderFlags.h"
17 #include "nsPop3Protocol.h"
18 #include "nsIMsgLocalMailFolder.h"
19 #include "nsIMsgAccountManager.h"
20 #include "nsServiceManagerUtils.h"
21 #include "nsMsgUtils.h"
22 #include "nsMsgDBFolder.h"
23 #include "nsComponentManagerUtils.h"
24 #include "mozilla/Likely.h"
25
26 static NS_DEFINE_CID(kCPop3ServiceCID, NS_POP3SERVICE_CID);
27
28 class nsPop3GetMailChainer final : public nsIUrlListener {
29 public:
30 NS_DECL_ISUPPORTS
31 NS_DECL_NSIURLLISTENER
32
33 nsPop3GetMailChainer();
34 nsresult GetNewMailForServers(
35 const nsTArray<RefPtr<nsIPop3IncomingServer>>& servers,
36 nsIMsgWindow* msgWindow, nsIMsgFolder* folderToDownloadTo,
37 nsIUrlListener* listener);
38 nsresult RunNextGetNewMail();
39
40 protected:
41 ~nsPop3GetMailChainer();
42 nsCOMPtr<nsIMsgFolder> m_folderToDownloadTo;
43 nsCOMPtr<nsIMsgWindow> m_downloadingMsgWindow;
44 nsTArray<RefPtr<nsIPop3IncomingServer>> m_serversToGetNewMailFor;
45 nsCOMPtr<nsIUrlListener> m_listener;
46 };
47
NS_IMPL_ISUPPORTS_INHERITED(nsPop3IncomingServer,nsMsgIncomingServer,nsIPop3IncomingServer,nsILocalMailIncomingServer)48 NS_IMPL_ISUPPORTS_INHERITED(nsPop3IncomingServer, nsMsgIncomingServer,
49 nsIPop3IncomingServer, nsILocalMailIncomingServer)
50
51 nsPop3IncomingServer::nsPop3IncomingServer() {
52 m_capabilityFlags = POP3_AUTH_MECH_UNDEFINED |
53 POP3_HAS_AUTH_USER | // should be always there
54 POP3_GURL_UNDEFINED | POP3_UIDL_UNDEFINED |
55 POP3_TOP_UNDEFINED | POP3_XTND_XLST_UNDEFINED;
56
57 m_canHaveFilters = true;
58 m_authenticated = false;
59 }
60
~nsPop3IncomingServer()61 nsPop3IncomingServer::~nsPop3IncomingServer() {}
62
63 NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, LeaveMessagesOnServer,
64 "leave_on_server")
65
66 NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, HeadersOnly, "headers_only")
67
68 NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, DeleteMailLeftOnServer,
69 "delete_mail_left_on_server")
70
71 NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, DotFix, "dot_fix")
72
73 NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, DeleteByAgeFromServer,
74 "delete_by_age_from_server")
75
76 NS_IMPL_SERVERPREF_INT(nsPop3IncomingServer, NumDaysToLeaveOnServer,
77 "num_days_to_leave_on_server")
78
79 NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, DeferGetNewMail,
80 "defer_get_new_mail")
81
GetDeferredToAccount(nsACString & aRetVal)82 NS_IMETHODIMP nsPop3IncomingServer::GetDeferredToAccount(nsACString& aRetVal) {
83 nsresult rv = GetCharValue("deferred_to_account", aRetVal);
84 if (aRetVal.IsEmpty()) return rv;
85 // We need to repair broken profiles that defer to hidden or invalid servers,
86 // so find out if the deferred to account has a valid non-hidden server, and
87 // if not, defer to the local folders inbox.
88 nsCOMPtr<nsIMsgAccountManager> acctMgr =
89 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
90 bool invalidAccount = true;
91 if (acctMgr) {
92 nsCOMPtr<nsIMsgAccount> account;
93 nsCOMPtr<nsIMsgIncomingServer> server;
94 rv = acctMgr->GetAccount(aRetVal, getter_AddRefs(account));
95 if (account) {
96 account->GetIncomingServer(getter_AddRefs(server));
97 if (server) server->GetHidden(&invalidAccount);
98 }
99 if (invalidAccount) {
100 nsCOMPtr<nsIMsgIncomingServer> localServer;
101 nsCOMPtr<nsIMsgAccount> localAccount;
102
103 rv = acctMgr->GetLocalFoldersServer(getter_AddRefs(localServer));
104 NS_ENSURE_SUCCESS(rv, rv);
105 // Try to copy any folders that have been stranded in the hidden account
106 // into the local folders account.
107 if (server) {
108 nsCOMPtr<nsIMsgFolder> hiddenRootFolder;
109 nsCOMPtr<nsIMsgFolder> localFoldersRoot;
110 server->GetRootFolder(getter_AddRefs(hiddenRootFolder));
111 localServer->GetRootFolder(getter_AddRefs(localFoldersRoot));
112 if (hiddenRootFolder && localFoldersRoot) {
113 // We're going to iterate over the folders in Local Folders-1,
114 // though I suspect only the Inbox will have messages. I don't
115 // think Sent Mail could end up here, but if any folders have
116 // messages, might as well copy them to the real Local Folders
117 // account.
118 nsTArray<RefPtr<nsIMsgFolder>> subFolders;
119 rv = hiddenRootFolder->GetSubFolders(subFolders);
120 if (NS_SUCCEEDED(rv)) {
121 for (nsIMsgFolder* subFolder : subFolders) {
122 nsCOMPtr<nsIMsgDatabase> subFolderDB;
123 subFolder->GetMsgDatabase(getter_AddRefs(subFolderDB));
124 if (!subFolderDB) {
125 continue;
126 }
127 // Copy any messages in this sub-folder of the hidden
128 // account to the corresponding folder in Local Folders.
129 nsTArray<nsMsgKey> keys;
130 rv = subFolderDB->ListAllKeys(keys);
131 if (NS_FAILED(rv)) {
132 continue; // Next subfolder.
133 }
134 nsTArray<RefPtr<nsIMsgDBHdr>> hdrsToCopy;
135 MsgGetHeadersFromKeys(subFolderDB, keys, hdrsToCopy);
136 if (!hdrsToCopy.IsEmpty()) {
137 // Look for a folder with the same name in Local Folders.
138 nsCOMPtr<nsIMsgFolder> dest;
139 nsString folderName;
140 subFolder->GetName(folderName);
141 localFoldersRoot->GetChildNamed(folderName,
142 getter_AddRefs(dest));
143 if (dest) {
144 dest->CopyMessages(subFolder, hdrsToCopy, false, nullptr,
145 nullptr, false, false);
146 }
147 // Should we copy the folder if the dest doesn't exist?
148 }
149 }
150 }
151 }
152 }
153 rv = acctMgr->FindAccountForServer(localServer,
154 getter_AddRefs(localAccount));
155 NS_ENSURE_SUCCESS(rv, rv);
156 if (!localAccount) return NS_ERROR_NOT_AVAILABLE;
157
158 localAccount->GetKey(aRetVal);
159 // Can't call SetDeferredToAccount because it calls GetDeferredToAccount.
160 return SetCharValue("deferred_to_account", aRetVal);
161 }
162 }
163 return rv;
164 }
165
SetDeferredToAccount(const nsACString & aAccountKey)166 NS_IMETHODIMP nsPop3IncomingServer::SetDeferredToAccount(
167 const nsACString& aAccountKey) {
168 nsCString deferredToAccount;
169 GetDeferredToAccount(deferredToAccount);
170 m_rootMsgFolder = nullptr; // clear this so we'll recalculate it on demand.
171 // Notify listeners who listen to every folder
172
173 nsresult rv = SetCharValue("deferred_to_account", aAccountKey);
174 NS_ENSURE_SUCCESS(rv, rv);
175 nsCOMPtr<nsIFolderListener> folderListenerManager =
176 do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
177 if (NS_SUCCEEDED(rv)) {
178 nsCOMPtr<nsIMsgFolder> rootFolder;
179 // use GetRootFolder, because that returns the real
180 // root, not the deferred to root.
181 rv = GetRootFolder(getter_AddRefs(rootFolder));
182 if (rootFolder) {
183 // if isDeferred state has changed, send notification
184 if (aAccountKey.IsEmpty() != deferredToAccount.IsEmpty()) {
185 folderListenerManager->OnItemBoolPropertyChanged(
186 rootFolder, kIsDeferred, !deferredToAccount.IsEmpty(),
187 deferredToAccount.IsEmpty());
188 folderListenerManager->OnItemBoolPropertyChanged(
189 rootFolder, kCanFileMessages, deferredToAccount.IsEmpty(),
190 !deferredToAccount.IsEmpty());
191
192 // this hack causes the account manager ds to send notifications to the
193 // xul content builder that make the changed acct appear or disappear
194 // from the folder pane and related menus.
195 nsCOMPtr<nsIMsgAccountManager> acctMgr =
196 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
197 if (acctMgr) {
198 acctMgr->NotifyServerUnloaded(this);
199 acctMgr->NotifyServerLoaded(this);
200 // check if this newly deferred to account is the local folders
201 // account and needs to have a newly created INBOX.
202 if (!aAccountKey.IsEmpty()) {
203 nsCOMPtr<nsIMsgAccount> account;
204 acctMgr->GetAccount(aAccountKey, getter_AddRefs(account));
205 if (account) {
206 nsCOMPtr<nsIMsgIncomingServer> server;
207 account->GetIncomingServer(getter_AddRefs(server));
208 if (server) {
209 nsCOMPtr<nsILocalMailIncomingServer> incomingLocalServer =
210 do_QueryInterface(server);
211 if (incomingLocalServer) {
212 nsCOMPtr<nsIMsgFolder> rootFolder;
213 rv = server->GetRootFolder(getter_AddRefs(rootFolder));
214 NS_ENSURE_SUCCESS(rv, rv);
215 // this will fail if it already exists, which is fine.
216 rootFolder->CreateSubfolder(u"Inbox"_ns, nullptr);
217 }
218 }
219 }
220 }
221 }
222 }
223 }
224 }
225 return rv;
226 }
227
228 // NS_IMPL_GETSET(nsPop3IncomingServer, Authenticated, bool, m_authenticated);
229
GetAuthenticated(bool * aAuthenticated)230 NS_IMETHODIMP nsPop3IncomingServer::GetAuthenticated(bool* aAuthenticated) {
231 NS_ENSURE_ARG_POINTER(aAuthenticated);
232 *aAuthenticated = m_authenticated;
233 return NS_OK;
234 }
235
SetAuthenticated(bool aAuthenticated)236 NS_IMETHODIMP nsPop3IncomingServer::SetAuthenticated(bool aAuthenticated) {
237 m_authenticated = aAuthenticated;
238 return NS_OK;
239 }
240
GetPop3CapabilityFlags(uint32_t * flags)241 nsresult nsPop3IncomingServer::GetPop3CapabilityFlags(uint32_t* flags) {
242 *flags = m_capabilityFlags;
243 return NS_OK;
244 }
245
SetPop3CapabilityFlags(uint32_t flags)246 nsresult nsPop3IncomingServer::SetPop3CapabilityFlags(uint32_t flags) {
247 m_capabilityFlags = flags;
248 return NS_OK;
249 }
250
251 NS_IMETHODIMP
GetRootMsgFolder(nsIMsgFolder ** aRootMsgFolder)252 nsPop3IncomingServer::GetRootMsgFolder(nsIMsgFolder** aRootMsgFolder) {
253 NS_ENSURE_ARG_POINTER(aRootMsgFolder);
254 nsresult rv = NS_OK;
255 if (!m_rootMsgFolder) {
256 nsCString deferredToAccount;
257 GetDeferredToAccount(deferredToAccount);
258 if (deferredToAccount.IsEmpty()) {
259 rv = CreateRootFolder();
260 m_rootMsgFolder = m_rootFolder;
261 } else {
262 nsCOMPtr<nsIMsgAccountManager> accountManager =
263 do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
264 NS_ENSURE_SUCCESS(rv, rv);
265 nsCOMPtr<nsIMsgAccount> account;
266 rv = accountManager->GetAccount(deferredToAccount,
267 getter_AddRefs(account));
268 NS_ENSURE_SUCCESS(rv, rv);
269 if (account) {
270 nsCOMPtr<nsIMsgIncomingServer> incomingServer;
271 rv = account->GetIncomingServer(getter_AddRefs(incomingServer));
272 NS_ENSURE_SUCCESS(rv, rv);
273 // make sure we're not deferred to ourself...
274 if (incomingServer && incomingServer != this)
275 rv =
276 incomingServer->GetRootMsgFolder(getter_AddRefs(m_rootMsgFolder));
277 else
278 rv = NS_ERROR_FAILURE;
279 }
280 }
281 }
282
283 NS_IF_ADDREF(*aRootMsgFolder = m_rootMsgFolder);
284 return m_rootMsgFolder ? rv : NS_ERROR_FAILURE;
285 }
286
GetInbox(nsIMsgWindow * msgWindow,nsIMsgFolder ** inbox)287 nsresult nsPop3IncomingServer::GetInbox(nsIMsgWindow* msgWindow,
288 nsIMsgFolder** inbox) {
289 NS_ENSURE_ARG_POINTER(inbox);
290 nsCOMPtr<nsIMsgFolder> rootFolder;
291 nsresult rv = GetRootMsgFolder(getter_AddRefs(rootFolder));
292 if (NS_SUCCEEDED(rv) && rootFolder) {
293 rootFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox, inbox);
294 }
295
296 nsCOMPtr<nsIMsgLocalMailFolder> localInbox = do_QueryInterface(*inbox, &rv);
297 if (NS_SUCCEEDED(rv) && localInbox) {
298 nsCOMPtr<nsIMsgDatabase> db;
299 rv = (*inbox)->GetMsgDatabase(getter_AddRefs(db));
300 if (NS_FAILED(rv)) {
301 (*inbox)->SetMsgDatabase(nullptr);
302 (void)localInbox->SetCheckForNewMessagesAfterParsing(true);
303 // this will cause a reparse of the mail folder.
304 localInbox->GetDatabaseWithReparse(nullptr, msgWindow,
305 getter_AddRefs(db));
306 rv = NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE;
307 }
308 }
309 return rv;
310 }
311
PerformBiff(nsIMsgWindow * aMsgWindow)312 NS_IMETHODIMP nsPop3IncomingServer::PerformBiff(nsIMsgWindow* aMsgWindow) {
313 nsresult rv;
314 nsCOMPtr<nsIPop3Service> pop3Service(do_GetService(kCPop3ServiceCID, &rv));
315 NS_ENSURE_SUCCESS(rv, rv);
316
317 nsCOMPtr<nsIMsgFolder> inbox;
318 nsCOMPtr<nsIMsgFolder> rootMsgFolder;
319 nsCOMPtr<nsIUrlListener> urlListener;
320 rv = GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
321 NS_ENSURE_TRUE(rootMsgFolder, NS_ERROR_FAILURE);
322
323 rootMsgFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox,
324 getter_AddRefs(inbox));
325 if (!inbox) return NS_ERROR_FAILURE;
326
327 nsCOMPtr<nsIMsgIncomingServer> server;
328 inbox->GetServer(getter_AddRefs(server));
329
330 server->SetPerformingBiff(true);
331
332 urlListener = do_QueryInterface(inbox);
333
334 bool downloadOnBiff = false;
335 rv = GetDownloadOnBiff(&downloadOnBiff);
336 if (downloadOnBiff) {
337 nsCOMPtr<nsIMsgLocalMailFolder> localInbox = do_QueryInterface(inbox, &rv);
338 if (localInbox && NS_SUCCEEDED(rv)) {
339 bool valid = false;
340 nsCOMPtr<nsIMsgDatabase> db;
341 rv = inbox->GetMsgDatabase(getter_AddRefs(db));
342 if (NS_SUCCEEDED(rv) && db) rv = db->GetSummaryValid(&valid);
343 if (NS_SUCCEEDED(rv) && valid)
344 rv = pop3Service->GetNewMail(aMsgWindow, urlListener, inbox, this,
345 nullptr);
346 else {
347 bool isLocked;
348 inbox->GetLocked(&isLocked);
349 if (!isLocked)
350 rv = localInbox->GetDatabaseWithReparse(urlListener, aMsgWindow,
351 getter_AddRefs(db));
352 if (NS_SUCCEEDED(rv))
353 rv = localInbox->SetCheckForNewMessagesAfterParsing(true);
354 }
355 }
356 } else
357 rv = pop3Service->CheckForNewMail(aMsgWindow, urlListener, inbox, this,
358 nullptr);
359 return NS_OK;
360 }
361
362 NS_IMETHODIMP
SetFlagsOnDefaultMailboxes()363 nsPop3IncomingServer::SetFlagsOnDefaultMailboxes() {
364 nsCOMPtr<nsIMsgFolder> rootFolder;
365 nsresult rv = GetRootFolder(getter_AddRefs(rootFolder));
366 NS_ENSURE_SUCCESS(rv, rv);
367
368 nsCOMPtr<nsIMsgLocalMailFolder> localFolder =
369 do_QueryInterface(rootFolder, &rv);
370 NS_ENSURE_SUCCESS(rv, rv);
371
372 // pop3 gets an inbox, but no queue (unsent messages)
373 localFolder->SetFlagsOnDefaultMailboxes(nsMsgFolderFlags::SpecialUse &
374 ~nsMsgFolderFlags::Queue);
375 return NS_OK;
376 }
377
CreateDefaultMailboxes()378 NS_IMETHODIMP nsPop3IncomingServer::CreateDefaultMailboxes() {
379 nsresult rv = CreateLocalFolder(u"Inbox"_ns);
380 NS_ENSURE_SUCCESS(rv, rv);
381
382 return CreateLocalFolder(u"Trash"_ns);
383 }
384
385 // override this so we can say that deferred accounts can't have messages
386 // filed to them, which will remove them as targets of all the move/copy
387 // menu items.
388 NS_IMETHODIMP
GetCanFileMessagesOnServer(bool * aCanFileMessagesOnServer)389 nsPop3IncomingServer::GetCanFileMessagesOnServer(
390 bool* aCanFileMessagesOnServer) {
391 NS_ENSURE_ARG_POINTER(aCanFileMessagesOnServer);
392
393 nsCString deferredToAccount;
394 GetDeferredToAccount(deferredToAccount);
395 *aCanFileMessagesOnServer = deferredToAccount.IsEmpty();
396 return NS_OK;
397 }
398
399 NS_IMETHODIMP
GetCanCreateFoldersOnServer(bool * aCanCreateFoldersOnServer)400 nsPop3IncomingServer::GetCanCreateFoldersOnServer(
401 bool* aCanCreateFoldersOnServer) {
402 NS_ENSURE_ARG_POINTER(aCanCreateFoldersOnServer);
403
404 nsCString deferredToAccount;
405 GetDeferredToAccount(deferredToAccount);
406 *aCanCreateFoldersOnServer = deferredToAccount.IsEmpty();
407 return NS_OK;
408 }
409
410 NS_IMETHODIMP
VerifyLogon(nsIUrlListener * aUrlListener,nsIMsgWindow * aMsgWindow,nsIURI ** aURL)411 nsPop3IncomingServer::VerifyLogon(nsIUrlListener* aUrlListener,
412 nsIMsgWindow* aMsgWindow, nsIURI** aURL) {
413 nsresult rv;
414 nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
415 NS_ENSURE_SUCCESS(rv, rv);
416 return pop3Service->VerifyLogon(this, aUrlListener, aMsgWindow, aURL);
417 }
418
DownloadMailFromServers(const nsTArray<RefPtr<nsIPop3IncomingServer>> & aServers,nsIMsgWindow * aMsgWindow,nsIMsgFolder * aFolder,nsIUrlListener * aUrlListener)419 NS_IMETHODIMP nsPop3IncomingServer::DownloadMailFromServers(
420 const nsTArray<RefPtr<nsIPop3IncomingServer>>& aServers,
421 nsIMsgWindow* aMsgWindow, nsIMsgFolder* aFolder,
422 nsIUrlListener* aUrlListener) {
423 RefPtr<nsPop3GetMailChainer> getMailChainer = new nsPop3GetMailChainer;
424 return getMailChainer->GetNewMailForServers(aServers, aMsgWindow, aFolder,
425 aUrlListener);
426 }
427
GetNewMail(nsIMsgWindow * aMsgWindow,nsIUrlListener * aUrlListener,nsIMsgFolder * aInbox,nsIURI ** aResult)428 NS_IMETHODIMP nsPop3IncomingServer::GetNewMail(nsIMsgWindow* aMsgWindow,
429 nsIUrlListener* aUrlListener,
430 nsIMsgFolder* aInbox,
431 nsIURI** aResult) {
432 nsresult rv;
433 nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
434 NS_ENSURE_SUCCESS(rv, rv);
435 return pop3Service->GetNewMail(aMsgWindow, aUrlListener, aInbox, this,
436 aResult);
437 }
438
439 // user has clicked get new messages on this server. If other servers defer to
440 // this server, we need to get new mail for them. But if this server defers to
441 // an other server, I think we only get new mail for this server.
442 NS_IMETHODIMP
GetNewMessages(nsIMsgFolder * aFolder,nsIMsgWindow * aMsgWindow,nsIUrlListener * aUrlListener)443 nsPop3IncomingServer::GetNewMessages(nsIMsgFolder* aFolder,
444 nsIMsgWindow* aMsgWindow,
445 nsIUrlListener* aUrlListener) {
446 nsresult rv;
447
448 nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
449 NS_ENSURE_SUCCESS(rv, rv);
450
451 nsCOMPtr<nsIMsgFolder> inbox;
452 rv = GetInbox(aMsgWindow, getter_AddRefs(inbox));
453 NS_ENSURE_SUCCESS(rv, rv);
454 nsCOMPtr<nsIURI> url;
455 nsCOMPtr<nsIMsgIncomingServer> server;
456 nsTArray<RefPtr<nsIPop3IncomingServer>> deferredServers;
457 nsCString deferredToAccount;
458 GetDeferredToAccount(deferredToAccount);
459
460 if (deferredToAccount.IsEmpty()) {
461 aFolder->GetServer(getter_AddRefs(server));
462 GetDeferredServers(server, deferredServers);
463 }
464 if (deferredToAccount.IsEmpty() && !deferredServers.IsEmpty()) {
465 RefPtr<nsPop3GetMailChainer> getMailChainer = new nsPop3GetMailChainer;
466 deferredServers.InsertElementAt(0, this);
467 return getMailChainer->GetNewMailForServers(deferredServers, aMsgWindow,
468 inbox, aUrlListener);
469 }
470 if (m_runningProtocol) return NS_MSG_FOLDER_BUSY;
471
472 return pop3Service->GetNewMail(aMsgWindow, aUrlListener, inbox, this,
473 getter_AddRefs(url));
474 }
475
476 NS_IMETHODIMP
GetDownloadMessagesAtStartup(bool * getMessagesAtStartup)477 nsPop3IncomingServer::GetDownloadMessagesAtStartup(bool* getMessagesAtStartup) {
478 NS_ENSURE_ARG_POINTER(getMessagesAtStartup);
479 // GetMessages is not automatically done for pop servers at startup.
480 // We need to trigger that action. Return true.
481 *getMessagesAtStartup = true;
482 return NS_OK;
483 }
484
485 NS_IMETHODIMP
GetCanBeDefaultServer(bool * canBeDefaultServer)486 nsPop3IncomingServer::GetCanBeDefaultServer(bool* canBeDefaultServer) {
487 NS_ENSURE_ARG_POINTER(canBeDefaultServer);
488 *canBeDefaultServer = true;
489 return NS_OK;
490 }
491
492 NS_IMETHODIMP
GetCanSearchMessages(bool * canSearchMessages)493 nsPop3IncomingServer::GetCanSearchMessages(bool* canSearchMessages) {
494 // this will return false if this server is deferred, which is what we want.
495 return GetCanFileMessagesOnServer(canSearchMessages);
496 }
497
498 NS_IMETHODIMP
CloseCachedConnections()499 nsPop3IncomingServer::CloseCachedConnections() {
500 nsCOMPtr<nsIRequest> channel = do_QueryInterface(m_runningProtocol);
501 if (channel) channel->Cancel(NS_ERROR_ABORT);
502 return NS_OK;
503 }
504
505 NS_IMETHODIMP
GetOfflineSupportLevel(int32_t * aSupportLevel)506 nsPop3IncomingServer::GetOfflineSupportLevel(int32_t* aSupportLevel) {
507 NS_ENSURE_ARG_POINTER(aSupportLevel);
508
509 nsresult rv;
510 rv = GetIntValue("offline_support_level", aSupportLevel);
511 if (*aSupportLevel != OFFLINE_SUPPORT_LEVEL_UNDEFINED) return rv;
512
513 // set default value
514 *aSupportLevel = OFFLINE_SUPPORT_LEVEL_NONE;
515 return NS_OK;
516 }
517
518 NS_IMETHODIMP
SetRunningProtocol(nsIPop3Protocol * aProtocol)519 nsPop3IncomingServer::SetRunningProtocol(nsIPop3Protocol* aProtocol) {
520 NS_ASSERTION(!aProtocol || !m_runningProtocol, "overriding running protocol");
521 m_runningProtocol = aProtocol;
522 return NS_OK;
523 }
524
GetRunningProtocol(nsIPop3Protocol ** aProtocol)525 NS_IMETHODIMP nsPop3IncomingServer::GetRunningProtocol(
526 nsIPop3Protocol** aProtocol) {
527 NS_ENSURE_ARG_POINTER(aProtocol);
528 NS_IF_ADDREF(*aProtocol = m_runningProtocol);
529 return NS_OK;
530 }
531
AddUidlToMark(const char * aUidl,int32_t aMark)532 NS_IMETHODIMP nsPop3IncomingServer::AddUidlToMark(const char* aUidl,
533 int32_t aMark) {
534 NS_ENSURE_ARG_POINTER(aUidl);
535
536 Pop3UidlEntry* uidlEntry = PR_NEWZAP(Pop3UidlEntry);
537 NS_ENSURE_TRUE(uidlEntry, NS_ERROR_OUT_OF_MEMORY);
538
539 uidlEntry->uidl = strdup(aUidl);
540 if (MOZ_UNLIKELY(!uidlEntry->uidl)) {
541 PR_Free(uidlEntry);
542 return NS_ERROR_OUT_OF_MEMORY;
543 }
544
545 uidlEntry->status = (aMark == POP3_DELETE) ? DELETE_CHAR
546 : (aMark == POP3_FETCH_BODY) ? FETCH_BODY
547 : KEEP;
548 m_uidlsToMark.AppendElement(uidlEntry);
549 return NS_OK;
550 }
551
MarkMessages()552 NS_IMETHODIMP nsPop3IncomingServer::MarkMessages() {
553 nsresult rv;
554 if (m_runningProtocol)
555 rv = m_runningProtocol->MarkMessages(&m_uidlsToMark);
556 else {
557 nsCString hostName;
558 nsCString userName;
559 nsCOMPtr<nsIFile> localPath;
560
561 GetLocalPath(getter_AddRefs(localPath));
562
563 GetHostName(hostName);
564 GetUsername(userName);
565 // do it all in one fell swoop
566 rv = nsPop3Protocol::MarkMsgForHost(hostName.get(), userName.get(),
567 localPath, m_uidlsToMark);
568 }
569 uint32_t count = m_uidlsToMark.Length();
570 for (uint32_t i = 0; i < count; i++) {
571 Pop3UidlEntry* ue = m_uidlsToMark[i];
572 PR_Free(ue->uidl);
573 PR_Free(ue);
574 }
575 m_uidlsToMark.Clear();
576 return rv;
577 }
578
NS_IMPL_ISUPPORTS(nsPop3GetMailChainer,nsIUrlListener)579 NS_IMPL_ISUPPORTS(nsPop3GetMailChainer, nsIUrlListener)
580
581 nsPop3GetMailChainer::nsPop3GetMailChainer() {}
~nsPop3GetMailChainer()582 nsPop3GetMailChainer::~nsPop3GetMailChainer() {}
583
GetNewMailForServers(const nsTArray<RefPtr<nsIPop3IncomingServer>> & servers,nsIMsgWindow * msgWindow,nsIMsgFolder * folderToDownloadTo,nsIUrlListener * listener)584 nsresult nsPop3GetMailChainer::GetNewMailForServers(
585 const nsTArray<RefPtr<nsIPop3IncomingServer>>& servers,
586 nsIMsgWindow* msgWindow, nsIMsgFolder* folderToDownloadTo,
587 nsIUrlListener* listener) {
588 NS_ENSURE_ARG_POINTER(folderToDownloadTo);
589
590 m_serversToGetNewMailFor = servers.Clone();
591 m_serversToGetNewMailFor.Reverse();
592 m_folderToDownloadTo = folderToDownloadTo;
593 m_downloadingMsgWindow = msgWindow;
594 m_listener = listener;
595 nsCOMPtr<nsIMsgDatabase> destFolderDB;
596
597 nsresult rv =
598 folderToDownloadTo->GetMsgDatabase(getter_AddRefs(destFolderDB));
599 if (NS_FAILED(rv) || !destFolderDB) {
600 nsCOMPtr<nsIMsgLocalMailFolder> localFolder =
601 do_QueryInterface(folderToDownloadTo);
602 if (localFolder) {
603 localFolder->GetDatabaseWithReparse(this, msgWindow,
604 getter_AddRefs(destFolderDB));
605 return NS_OK;
606 }
607 }
608 return RunNextGetNewMail();
609 }
610
611 NS_IMETHODIMP
OnStartRunningUrl(nsIURI * url)612 nsPop3GetMailChainer::OnStartRunningUrl(nsIURI* url) { return NS_OK; }
613
614 NS_IMETHODIMP
OnStopRunningUrl(nsIURI * aUrl,nsresult aExitCode)615 nsPop3GetMailChainer::OnStopRunningUrl(nsIURI* aUrl, nsresult aExitCode) {
616 return RunNextGetNewMail();
617 }
618
RunNextGetNewMail()619 nsresult nsPop3GetMailChainer::RunNextGetNewMail() {
620 nsresult rv;
621
622 while (!m_serversToGetNewMailFor.IsEmpty()) {
623 RefPtr<nsIPop3IncomingServer> popServer(
624 m_serversToGetNewMailFor.PopLastElement());
625 if (popServer) {
626 bool deferGetNewMail = false;
627 nsCOMPtr<nsIMsgIncomingServer> downloadingToServer;
628 m_folderToDownloadTo->GetServer(getter_AddRefs(downloadingToServer));
629 popServer->GetDeferGetNewMail(&deferGetNewMail);
630 nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(popServer);
631 nsCOMPtr<nsIPop3Protocol> protocol;
632 popServer->GetRunningProtocol(getter_AddRefs(protocol));
633 if ((deferGetNewMail || downloadingToServer == server) && !protocol) {
634 // have to call routine that just gets mail for one server,
635 // and ignores deferred servers...
636 if (server) {
637 nsCOMPtr<nsIURI> url;
638 nsCOMPtr<nsIPop3Service> pop3Service =
639 do_GetService(kCPop3ServiceCID, &rv);
640 NS_ENSURE_SUCCESS(rv, rv);
641 return pop3Service->GetNewMail(m_downloadingMsgWindow, this,
642 m_folderToDownloadTo, popServer,
643 getter_AddRefs(url));
644 }
645 }
646 }
647 }
648 rv = m_listener ? m_listener->OnStopRunningUrl(nullptr, NS_OK) : NS_OK;
649 return rv;
650 }
651