1 /* vim: set ts=2 et sw=2 tw=80: */
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 "nsString.h"
7 #include "nsCOMPtr.h"
8 #include "nsIFile.h"
9 #include "nsIInputStream.h"
10 #include "nsIOutputStream.h"
11 #include "nsILineInputStream.h"
12 #include "nsNetUtil.h"
13 #include "nsIImportService.h"
14 #include "nsIImportMailboxDescriptor.h"
15 #include "nsIMsgHdr.h"
16 #include "nsIMsgFolder.h"
17 #include "nsIMsgPluggableStore.h"
18 #include "nsMsgUtils.h"
19 #include "nsMsgLocalFolderHdrs.h"
20 #include "nsMsgMessageFlags.h"
21 #include "nsTArray.h"
22 #include "nspr.h"
23 #include "nsThreadUtils.h"
24 #include "nsIDirectoryEnumerator.h"
25 
26 #include "nsBeckyMail.h"
27 #include "nsBeckyUtils.h"
28 #include "nsBeckyStringBundle.h"
29 
30 #define FROM_LINE "From - Mon Jan 1 00:00:00 1965" MSG_LINEBREAK
31 #define X_BECKY_STATUS_HEADER "X-Becky-Status"
32 #define X_BECKY_INCLUDE_HEADER "X-Becky-Include"
33 
34 enum {
35   BECKY_STATUS_READ = 1 << 0,
36   BECKY_STATUS_FORWARDED = 1 << 1,
37   BECKY_STATUS_REPLIED = 1 << 2
38 };
39 
NS_IMPL_ISUPPORTS(nsBeckyMail,nsIImportMail)40 NS_IMPL_ISUPPORTS(nsBeckyMail, nsIImportMail)
41 
42 nsresult nsBeckyMail::Create(nsIImportMail** aImport) {
43   NS_ENSURE_ARG_POINTER(aImport);
44   NS_ADDREF(*aImport = new nsBeckyMail());
45   return NS_OK;
46 }
47 
nsBeckyMail()48 nsBeckyMail::nsBeckyMail() : mReadBytes(0) {}
49 
~nsBeckyMail()50 nsBeckyMail::~nsBeckyMail() {}
51 
52 NS_IMETHODIMP
GetDefaultLocation(nsIFile ** aLocation,bool * aFound,bool * aUserVerify)53 nsBeckyMail::GetDefaultLocation(nsIFile** aLocation, bool* aFound,
54                                 bool* aUserVerify) {
55   NS_ENSURE_ARG_POINTER(aFound);
56   NS_ENSURE_ARG_POINTER(aLocation);
57   NS_ENSURE_ARG_POINTER(aUserVerify);
58 
59   *aLocation = nullptr;
60   *aUserVerify = true;
61   *aFound = false;
62   if (NS_SUCCEEDED(nsBeckyUtils::GetDefaultMailboxDirectory(aLocation)))
63     *aFound = true;
64 
65   return NS_OK;
66 }
67 
CreateMailboxDescriptor(nsIImportMailboxDescriptor ** aDescriptor)68 nsresult nsBeckyMail::CreateMailboxDescriptor(
69     nsIImportMailboxDescriptor** aDescriptor) {
70   nsresult rv;
71   nsCOMPtr<nsIImportService> importService;
72   importService = do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv);
73   NS_ENSURE_SUCCESS(rv, rv);
74 
75   return importService->CreateNewMailboxDescriptor(aDescriptor);
76 }
77 
GetMailboxName(nsIFile * aMailbox,nsAString & aName)78 nsresult nsBeckyMail::GetMailboxName(nsIFile* aMailbox, nsAString& aName) {
79   nsCOMPtr<nsIFile> iniFile;
80   nsBeckyUtils::GetMailboxINIFile(aMailbox, getter_AddRefs(iniFile));
81   if (iniFile) {
82     nsCOMPtr<nsIFile> convertedFile;
83     nsBeckyUtils::ConvertToUTF8File(iniFile, getter_AddRefs(convertedFile));
84     if (convertedFile) {
85       nsAutoCString utf8Name;
86       nsBeckyUtils::GetMailboxNameFromINIFile(convertedFile, utf8Name);
87       convertedFile->Remove(false);
88       CopyUTF8toUTF16(utf8Name, aName);
89     }
90   }
91 
92   if (aName.IsEmpty()) {
93     nsAutoString name;
94     aMailbox->GetLeafName(name);
95     name.Trim("!", true, false);
96     aName.Assign(name);
97   }
98 
99   return NS_OK;
100 }
101 
AppendMailboxDescriptor(nsIFile * aEntry,const nsString & aName,uint32_t aDepth,nsTArray<RefPtr<nsIImportMailboxDescriptor>> & aCollected)102 nsresult nsBeckyMail::AppendMailboxDescriptor(
103     nsIFile* aEntry, const nsString& aName, uint32_t aDepth,
104     nsTArray<RefPtr<nsIImportMailboxDescriptor>>& aCollected) {
105   nsresult rv;
106   nsCOMPtr<nsIImportMailboxDescriptor> descriptor;
107   rv = CreateMailboxDescriptor(getter_AddRefs(descriptor));
108   NS_ENSURE_SUCCESS(rv, rv);
109 
110   int64_t size;
111   rv = aEntry->GetFileSize(&size);
112   NS_ENSURE_SUCCESS(rv, rv);
113 
114   rv = descriptor->SetSize(size);
115   NS_ENSURE_SUCCESS(rv, rv);
116 
117   rv = descriptor->SetDisplayName(aName.get());
118   NS_ENSURE_SUCCESS(rv, rv);
119 
120   nsCOMPtr<nsIFile> mailboxFile;
121   rv = descriptor->GetFile(getter_AddRefs(mailboxFile));
122   NS_ENSURE_SUCCESS(rv, rv);
123 
124   descriptor->SetDepth(aDepth);
125 
126   mailboxFile->InitWithFile(aEntry);
127   aCollected.AppendElement(descriptor);
128 
129   return NS_OK;
130 }
131 
CollectMailboxesInFolderListFile(nsIFile * aListFile,uint32_t aDepth,nsTArray<RefPtr<nsIImportMailboxDescriptor>> & aCollected)132 nsresult nsBeckyMail::CollectMailboxesInFolderListFile(
133     nsIFile* aListFile, uint32_t aDepth,
134     nsTArray<RefPtr<nsIImportMailboxDescriptor>>& aCollected) {
135   nsresult rv;
136   nsCOMPtr<nsILineInputStream> lineStream;
137   rv = nsBeckyUtils::CreateLineInputStream(aListFile,
138                                            getter_AddRefs(lineStream));
139   NS_ENSURE_SUCCESS(rv, rv);
140 
141   nsCOMPtr<nsIFile> parent;
142   rv = aListFile->GetParent(getter_AddRefs(parent));
143   NS_ENSURE_SUCCESS(rv, rv);
144 
145   bool more = true;
146   nsAutoCString folderName;
147   bool isEmpty = true;
148   while (more && NS_SUCCEEDED(rv)) {
149     rv = lineStream->ReadLine(folderName, &more);
150     NS_ENSURE_SUCCESS(rv, rv);
151 
152     if (folderName.IsEmpty()) continue;
153 
154     nsCOMPtr<nsIFile> folder;
155     rv = parent->Clone(getter_AddRefs(folder));
156     NS_ENSURE_SUCCESS(rv, rv);
157 
158     rv = folder->AppendNative(folderName);
159     NS_ENSURE_SUCCESS(rv, rv);
160 
161     isEmpty = false;
162     rv = CollectMailboxesInDirectory(folder, aDepth + 1, aCollected);
163   }
164 
165   return isEmpty ? NS_ERROR_FILE_NOT_FOUND : NS_OK;
166 }
167 
CollectMailboxesInDirectory(nsIFile * aDirectory,uint32_t aDepth,nsTArray<RefPtr<nsIImportMailboxDescriptor>> & aCollected)168 nsresult nsBeckyMail::CollectMailboxesInDirectory(
169     nsIFile* aDirectory, uint32_t aDepth,
170     nsTArray<RefPtr<nsIImportMailboxDescriptor>>& aCollected) {
171   nsAutoString mailboxName;
172   nsresult rv = GetMailboxName(aDirectory, mailboxName);
173   NS_ENSURE_SUCCESS(rv, rv);
174 
175   if (aDepth != 0)
176     AppendMailboxDescriptor(aDirectory, mailboxName, aDepth, aCollected);
177 
178   nsCOMPtr<nsIFile> folderListFile;
179   rv = nsBeckyUtils::GetFolderListFile(aDirectory,
180                                        getter_AddRefs(folderListFile));
181   bool folderListExists = false;
182 
183   if (NS_SUCCEEDED(rv)) {
184     rv = CollectMailboxesInFolderListFile(folderListFile, aDepth, aCollected);
185     folderListExists = true;
186   }
187 
188   nsCOMPtr<nsIDirectoryEnumerator> entries;
189   rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
190   NS_ENSURE_SUCCESS(rv, rv);
191 
192   bool more;
193   while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
194     nsCOMPtr<nsIFile> file;
195     rv = entries->GetNextFile(getter_AddRefs(file));
196     NS_ENSURE_SUCCESS(rv, rv);
197 
198     nsAutoString name;
199     rv = file->GetLeafName(name);
200     NS_ENSURE_SUCCESS(rv, rv);
201 
202     if (StringEndsWith(name, u".bmf"_ns)) {
203       AppendMailboxDescriptor(file, mailboxName, aDepth, aCollected);
204     }
205 
206     // The Folder.lst file is not created if there is only one sub folder,
207     // so we need to find the sub folder by our hands.
208     // The folder name does not begin with # or ! maybe. Yes, maybe...
209     if (!folderListExists) {
210       if (StringBeginsWith(name, u"#"_ns) || StringBeginsWith(name, u"!"_ns))
211         continue;
212 
213       bool isDirectory = false;
214       rv = file->IsDirectory(&isDirectory);
215       if (isDirectory) {
216         CollectMailboxesInDirectory(file, aDepth + 1, aCollected);
217         continue;
218       }
219     }
220   }
221 
222   return NS_OK;
223 }
224 
225 NS_IMETHODIMP
FindMailboxes(nsIFile * aLocation,nsTArray<RefPtr<nsIImportMailboxDescriptor>> & boxes)226 nsBeckyMail::FindMailboxes(
227     nsIFile* aLocation, nsTArray<RefPtr<nsIImportMailboxDescriptor>>& boxes) {
228   NS_ENSURE_ARG_POINTER(aLocation);
229 
230   boxes.Clear();
231   nsresult rv = CollectMailboxesInDirectory(aLocation, 0, boxes);
232   NS_ENSURE_SUCCESS(rv, rv);
233   return NS_OK;
234 }
235 
GetBeckyStatusValue(const nsCString & aHeader,nsACString & aValue)236 static nsresult GetBeckyStatusValue(const nsCString& aHeader,
237                                     nsACString& aValue) {
238   int32_t valueStartPosition;
239 
240   valueStartPosition = aHeader.FindChar(':');
241   if (valueStartPosition < 0) return NS_ERROR_UNEXPECTED;
242 
243   valueStartPosition++;
244 
245   int32_t commaPosition = aHeader.FindChar(',', valueStartPosition);
246   if (commaPosition < 0) return NS_ERROR_UNEXPECTED;
247 
248   nsAutoCString value(Substring(aHeader, valueStartPosition,
249                                 commaPosition - valueStartPosition));
250   value.Trim(" \t");
251 
252   aValue.Assign(value);
253 
254   return NS_OK;
255 }
256 
GetBeckyIncludeValue(const nsCString & aHeader,nsACString & aValue)257 static nsresult GetBeckyIncludeValue(const nsCString& aHeader,
258                                      nsACString& aValue) {
259   int32_t valueStartPosition;
260 
261   valueStartPosition = aHeader.FindChar(':');
262   if (valueStartPosition < 0) return NS_ERROR_FAILURE;
263 
264   valueStartPosition++;
265   nsAutoCString value(Substring(aHeader, valueStartPosition));
266   value.Trim(" \t");
267 
268   aValue.Assign(value);
269 
270   return NS_OK;
271 }
272 
ConvertBeckyStatusToMozillaStatus(const nsCString & aHeader,nsMsgMessageFlagType * aMozillaStatusFlag)273 static bool ConvertBeckyStatusToMozillaStatus(
274     const nsCString& aHeader, nsMsgMessageFlagType* aMozillaStatusFlag) {
275   nsresult rv;
276   nsAutoCString statusString;
277   rv = GetBeckyStatusValue(aHeader, statusString);
278   NS_ENSURE_SUCCESS(rv, false);
279 
280   nsresult errorCode;
281   uint32_t beckyStatusFlag =
282       static_cast<uint32_t>(statusString.ToInteger(&errorCode, 16));
283   if (NS_FAILED(errorCode)) return false;
284 
285   if (beckyStatusFlag & BECKY_STATUS_READ)
286     *aMozillaStatusFlag |= nsMsgMessageFlags::Read;
287   if (beckyStatusFlag & BECKY_STATUS_FORWARDED)
288     *aMozillaStatusFlag |= nsMsgMessageFlags::Forwarded;
289   if (beckyStatusFlag & BECKY_STATUS_REPLIED)
290     *aMozillaStatusFlag |= nsMsgMessageFlags::Replied;
291 
292   return true;
293 }
294 
CheckHeaderKey(const nsCString & aHeader,const char * aKeyString)295 static inline bool CheckHeaderKey(const nsCString& aHeader,
296                                   const char* aKeyString) {
297   nsAutoCString key(StringHead(aHeader, aHeader.FindChar(':')));
298   key.Trim(" \t");
299   return key.Equals(aKeyString);
300 }
301 
IsBeckyStatusHeader(const nsCString & aHeader)302 static inline bool IsBeckyStatusHeader(const nsCString& aHeader) {
303   return CheckHeaderKey(aHeader, X_BECKY_STATUS_HEADER);
304 }
305 
IsBeckyIncludeLine(const nsCString & aLine)306 static inline bool IsBeckyIncludeLine(const nsCString& aLine) {
307   return CheckHeaderKey(aLine, X_BECKY_INCLUDE_HEADER);
308 }
309 
IsEndOfHeaders(const nsCString & aLine)310 static inline bool IsEndOfHeaders(const nsCString& aLine) {
311   return aLine.IsEmpty();
312 }
313 
IsEndOfMessage(const nsCString & aLine)314 static inline bool IsEndOfMessage(const nsCString& aLine) {
315   return aLine.EqualsLiteral(".");
316 }
317 
318 class ImportMessageRunnable : public mozilla::Runnable {
319  public:
320   ImportMessageRunnable(nsIFile* aMessageFile, nsIMsgFolder* aFolder);
321   NS_DECL_NSIRUNNABLE
322   nsresult mResult;
323 
324  private:
325   nsresult WriteHeaders(nsCString& aHeaders, nsIOutputStream* aOutputStream);
326   nsresult HandleHeaderLine(const nsCString& aHeaderLine, nsACString& aHeaders);
327   nsresult GetAttachmentFile(nsIFile* aMailboxFile, const nsCString& aHeader,
328                              nsIFile** _retval);
329   nsresult WriteAttachmentFile(nsIFile* aMailboxFile, const nsCString& aHeader,
330                                nsIOutputStream* aOutputStream);
331 
332   nsCOMPtr<nsIFile> mMessageFile;
333   nsCOMPtr<nsIMsgFolder> mFolder;
334 };
335 
ImportMessageRunnable(nsIFile * aMessageFile,nsIMsgFolder * aFolder)336 ImportMessageRunnable::ImportMessageRunnable(nsIFile* aMessageFile,
337                                              nsIMsgFolder* aFolder)
338     : mozilla::Runnable("ImportMessageRunnable"),
339       mMessageFile(aMessageFile),
340       mFolder(aFolder) {}
341 
WriteHeaders(nsCString & aHeaders,nsIOutputStream * aOutputStream)342 nsresult ImportMessageRunnable::WriteHeaders(nsCString& aHeaders,
343                                              nsIOutputStream* aOutputStream) {
344   nsresult rv;
345   uint32_t writtenBytes = 0;
346 
347   rv = aOutputStream->Write(FROM_LINE, strlen(FROM_LINE), &writtenBytes);
348   NS_ENSURE_SUCCESS(rv, rv);
349   rv = aOutputStream->Write(aHeaders.get(), aHeaders.Length(), &writtenBytes);
350   NS_ENSURE_SUCCESS(rv, rv);
351   rv =
352       aOutputStream->Write(MSG_LINEBREAK, strlen(MSG_LINEBREAK), &writtenBytes);
353   NS_ENSURE_SUCCESS(rv, rv);
354   aHeaders.Truncate();
355 
356   return NS_OK;
357 }
358 
HandleHeaderLine(const nsCString & aHeaderLine,nsACString & aHeaders)359 nsresult ImportMessageRunnable::HandleHeaderLine(const nsCString& aHeaderLine,
360                                                  nsACString& aHeaders) {
361   aHeaders.Append(aHeaderLine);
362   aHeaders.AppendLiteral(MSG_LINEBREAK);
363 
364   nsMsgMessageFlagType flag = 0;
365   if (IsBeckyStatusHeader(aHeaderLine) &&
366       ConvertBeckyStatusToMozillaStatus(aHeaderLine, &flag)) {
367     char* statusLine;
368     statusLine = PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, flag);
369     aHeaders.Append(statusLine);
370     PR_smprintf_free(statusLine);
371     aHeaders.AppendLiteral(X_MOZILLA_KEYWORDS);
372   }
373 
374   return NS_OK;
375 }
376 
GetAttachmentFile(nsIFile * aMailboxFile,const nsCString & aHeader,nsIFile ** _retval)377 nsresult ImportMessageRunnable::GetAttachmentFile(nsIFile* aMailboxFile,
378                                                   const nsCString& aHeader,
379                                                   nsIFile** _retval) {
380   nsresult rv;
381   nsCOMPtr<nsIFile> attachmentFile;
382 
383   rv = aMailboxFile->Clone(getter_AddRefs(attachmentFile));
384   NS_ENSURE_SUCCESS(rv, rv);
385 
386   rv = attachmentFile->Append(u"#Attach"_ns);
387   NS_ENSURE_SUCCESS(rv, rv);
388 
389   nsAutoCString nativeAttachmentPath;
390   rv = GetBeckyIncludeValue(aHeader, nativeAttachmentPath);
391   NS_ENSURE_SUCCESS(rv, rv);
392 
393   rv = attachmentFile->AppendRelativeNativePath(nativeAttachmentPath);
394   NS_ENSURE_SUCCESS(rv, rv);
395 
396   bool exists = false;
397   attachmentFile->Exists(&exists);
398   if (!exists) return NS_ERROR_FILE_NOT_FOUND;
399 
400   attachmentFile.forget(_retval);
401   return NS_OK;
402 }
403 
WriteAttachmentFile(nsIFile * aMailboxFile,const nsCString & aHeader,nsIOutputStream * aOutputStream)404 nsresult ImportMessageRunnable::WriteAttachmentFile(
405     nsIFile* aMailboxFile, const nsCString& aHeader,
406     nsIOutputStream* aOutputStream) {
407   nsresult rv;
408   nsCOMPtr<nsIFile> parentDirectory;
409   rv = aMailboxFile->GetParent(getter_AddRefs(parentDirectory));
410   NS_ENSURE_SUCCESS(rv, rv);
411 
412   nsCOMPtr<nsIFile> attachmentFile;
413   rv = GetAttachmentFile(parentDirectory, aHeader,
414                          getter_AddRefs(attachmentFile));
415   NS_ENSURE_SUCCESS(rv, rv);
416 
417   nsCOMPtr<nsIInputStream> inputStream;
418   rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), attachmentFile);
419   NS_ENSURE_SUCCESS(rv, rv);
420 
421   char buffer[FILE_IO_BUFFER_SIZE];
422   uint32_t readBytes = 0;
423   uint32_t writtenBytes = 0;
424   rv =
425       aOutputStream->Write(MSG_LINEBREAK, strlen(MSG_LINEBREAK), &writtenBytes);
426   while (NS_SUCCEEDED(inputStream->Read(buffer, sizeof(buffer), &readBytes)) &&
427          readBytes > 0) {
428     rv = aOutputStream->Write(buffer, readBytes, &writtenBytes);
429     if (NS_FAILED(rv)) break;
430   }
431 
432   return rv;
433 }
434 
Run()435 NS_IMETHODIMP ImportMessageRunnable::Run() {
436   nsCOMPtr<nsIMsgPluggableStore> msgStore;
437   mResult = mFolder->GetMsgStore(getter_AddRefs(msgStore));
438   NS_ENSURE_SUCCESS(mResult, NS_OK);
439 
440   nsCOMPtr<nsILineInputStream> lineStream;
441   mResult = nsBeckyUtils::CreateLineInputStream(mMessageFile,
442                                                 getter_AddRefs(lineStream));
443   NS_ENSURE_SUCCESS(mResult, NS_OK);
444 
445   bool reusable;
446   nsCOMPtr<nsIMsgDBHdr> msgHdr;
447   nsCOMPtr<nsIOutputStream> outputStream;
448   mResult = msgStore->GetNewMsgOutputStream(
449       mFolder, getter_AddRefs(msgHdr), &reusable, getter_AddRefs(outputStream));
450   NS_ENSURE_SUCCESS(mResult, NS_OK);
451 
452   bool inHeader = true;
453   bool more = true;
454   nsAutoCString headers;
455   while (NS_SUCCEEDED(mResult) && more) {
456     nsAutoCString line;
457     mResult = lineStream->ReadLine(line, &more);
458     if (NS_FAILED(mResult)) break;
459 
460     if (inHeader) {
461       if (IsEndOfHeaders(line)) {
462         inHeader = false;
463         mResult = WriteHeaders(headers, outputStream);
464       } else {
465         mResult = HandleHeaderLine(line, headers);
466       }
467     } else if (IsEndOfMessage(line)) {
468       inHeader = true;
469       mResult = msgStore->FinishNewMessage(outputStream, msgHdr);
470       if (!reusable) outputStream->Close();
471       mResult = msgStore->GetNewMsgOutputStream(mFolder, getter_AddRefs(msgHdr),
472                                                 &reusable,
473                                                 getter_AddRefs(outputStream));
474     } else if (IsBeckyIncludeLine(line)) {
475       mResult = WriteAttachmentFile(mMessageFile, line, outputStream);
476     } else {
477       uint32_t writtenBytes = 0;
478       if (StringBeginsWith(line, ".."_ns))
479         line.Cut(0, 1);
480       else if (CheckHeaderKey(line, "From"))
481         line.Insert('>', 0);
482 
483       line.AppendLiteral(MSG_LINEBREAK);
484       mResult = outputStream->Write(line.get(), line.Length(), &writtenBytes);
485     }
486   }
487 
488   if (outputStream) {
489     if (NS_FAILED(mResult)) msgStore->DiscardNewMessage(outputStream, msgHdr);
490     outputStream->Close();
491   }
492 
493   return NS_OK;
494 }
495 
ProxyImportMessage(nsIFile * aMessageFile,nsIMsgFolder * aFolder)496 static nsresult ProxyImportMessage(nsIFile* aMessageFile,
497                                    nsIMsgFolder* aFolder) {
498   RefPtr<ImportMessageRunnable> importMessage =
499       new ImportMessageRunnable(aMessageFile, aFolder);
500   nsresult rv = NS_DispatchToMainThread(importMessage, NS_DISPATCH_SYNC);
501   NS_ENSURE_SUCCESS(rv, rv);
502   return importMessage->mResult;
503 }
504 
ImportMailFile(nsIFile * aMailFile,nsIMsgFolder * aDestination)505 nsresult nsBeckyMail::ImportMailFile(nsIFile* aMailFile,
506                                      nsIMsgFolder* aDestination) {
507   int64_t size;
508   aMailFile->GetFileSize(&size);
509   if (size == 0) return NS_OK;
510 
511   return ProxyImportMessage(aMailFile, aDestination);
512 }
513 
514 NS_IMETHODIMP
ImportMailbox(nsIImportMailboxDescriptor * aSource,nsIMsgFolder * aDestination,char16_t ** aErrorLog,char16_t ** aSuccessLog,bool * aFatalError)515 nsBeckyMail::ImportMailbox(nsIImportMailboxDescriptor* aSource,
516                            nsIMsgFolder* aDestination, char16_t** aErrorLog,
517                            char16_t** aSuccessLog, bool* aFatalError) {
518   NS_ENSURE_ARG_POINTER(aSource);
519   NS_ENSURE_ARG_POINTER(aDestination);
520   NS_ENSURE_ARG_POINTER(aErrorLog);
521   NS_ENSURE_ARG_POINTER(aSuccessLog);
522   NS_ENSURE_ARG_POINTER(aFatalError);
523 
524   mReadBytes = 0;
525 
526   nsresult rv;
527   nsCOMPtr<nsIFile> mailboxFolder;
528   rv = aSource->GetFile(getter_AddRefs(mailboxFolder));
529   NS_ENSURE_SUCCESS(rv, rv);
530 
531   rv = ImportMailFile(mailboxFolder, aDestination);
532   NS_ENSURE_SUCCESS(rv, rv);
533 
534   uint32_t finalSize;
535   aSource->GetSize(&finalSize);
536   mReadBytes = finalSize;
537 
538   nsAutoString name;
539   aSource->GetDisplayName(getter_Copies(name));
540 
541   nsAutoString successMessage;
542   AutoTArray<nsString, 1> format = {name};
543   rv = nsBeckyStringBundle::FormatStringFromName("BeckyImportMailboxSuccess",
544                                                  format, successMessage);
545   successMessage.AppendLiteral("\n");
546   *aSuccessLog = ToNewUnicode(successMessage);
547 
548   return rv;
549 }
550 
551 NS_IMETHODIMP
GetImportProgress(uint32_t * _retval)552 nsBeckyMail::GetImportProgress(uint32_t* _retval) {
553   NS_ENSURE_ARG_POINTER(_retval);
554   *_retval = mReadBytes;
555   return NS_OK;
556 }
557 
558 NS_IMETHODIMP
TranslateFolderName(const nsAString & aFolderName,nsAString & _retval)559 nsBeckyMail::TranslateFolderName(const nsAString& aFolderName,
560                                  nsAString& _retval) {
561   return nsBeckyUtils::TranslateFolderName(aFolderName, _retval);
562 }
563