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 "nsILineInputStream.h"
7 #include "nsComponentManagerUtils.h"
8 #include "nsServiceManagerUtils.h"
9 #include "nsIMsgFilter.h"
10 #include "nsIMsgFilterList.h"
11 #include "nsIMsgAccountManager.h"
12 #include "nsIMsgAccount.h"
13 #include "nsIMsgSearchTerm.h"
14 #include "nsIMsgFolder.h"
15 #include "nsCOMPtr.h"
16 #include "nsMsgSearchCore.h"
17 #include "nsMsgBaseCID.h"
18 #include "nsMsgUtils.h"
19 #include "msgCore.h"
20 
21 #include "nsBeckyFilters.h"
22 #include "nsBeckyStringBundle.h"
23 #include "nsBeckyUtils.h"
24 
NS_IMPL_ISUPPORTS(nsBeckyFilters,nsIImportFilters)25 NS_IMPL_ISUPPORTS(nsBeckyFilters, nsIImportFilters)
26 
27 nsresult nsBeckyFilters::Create(nsIImportFilters** aImport) {
28   NS_ENSURE_ARG_POINTER(aImport);
29   NS_ADDREF(*aImport = new nsBeckyFilters());
30   return NS_OK;
31 }
32 
nsBeckyFilters()33 nsBeckyFilters::nsBeckyFilters()
34     : mLocation(nullptr), mServer(nullptr), mConvertedFile(nullptr) {}
35 
~nsBeckyFilters()36 nsBeckyFilters::~nsBeckyFilters() {}
37 
GetDefaultFilterLocation(nsIFile ** aFile)38 nsresult nsBeckyFilters::GetDefaultFilterLocation(nsIFile** aFile) {
39   NS_ENSURE_ARG_POINTER(aFile);
40 
41   nsresult rv;
42   nsCOMPtr<nsIFile> filterDir;
43   rv = nsBeckyUtils::GetDefaultMailboxDirectory(getter_AddRefs(filterDir));
44   NS_ENSURE_SUCCESS(rv, rv);
45 
46   filterDir.forget(aFile);
47   return NS_OK;
48 }
49 
GetFilterFile(bool aIncoming,nsIFile * aLocation,nsIFile ** aFile)50 nsresult nsBeckyFilters::GetFilterFile(bool aIncoming, nsIFile* aLocation,
51                                        nsIFile** aFile) {
52   NS_ENSURE_ARG_POINTER(aLocation);
53   NS_ENSURE_ARG_POINTER(aFile);
54 
55   // We assume the caller has already checked that aLocation is a directory,
56   // otherwise it would not make sense to call us.
57 
58   nsresult rv;
59   nsCOMPtr<nsIFile> filter;
60   aLocation->Clone(getter_AddRefs(filter));
61   if (aIncoming)
62     rv = filter->Append(u"IFilter.def"_ns);
63   else
64     rv = filter->Append(u"OFilter.def"_ns);
65   NS_ENSURE_SUCCESS(rv, rv);
66 
67   bool exists = false;
68   rv = filter->Exists(&exists);
69   NS_ENSURE_SUCCESS(rv, rv);
70   if (!exists) return NS_ERROR_FILE_NOT_FOUND;
71 
72   filter.forget(aFile);
73   return NS_OK;
74 }
75 
76 NS_IMETHODIMP
AutoLocate(char16_t ** aDescription,nsIFile ** aLocation,bool * _retval)77 nsBeckyFilters::AutoLocate(char16_t** aDescription, nsIFile** aLocation,
78                            bool* _retval) {
79   NS_ENSURE_ARG_POINTER(aLocation);
80   NS_ENSURE_ARG_POINTER(_retval);
81 
82   if (aDescription) {
83     *aDescription =
84         nsBeckyStringBundle::GetStringByName("BeckyImportDescription");
85   }
86   *aLocation = nullptr;
87   *_retval = false;
88 
89   nsresult rv;
90   nsCOMPtr<nsIFile> location;
91   rv = GetDefaultFilterLocation(getter_AddRefs(location));
92   if (NS_FAILED(rv))
93     location = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
94   else
95     *_retval = true;
96 
97   location.forget(aLocation);
98   return NS_OK;
99 }
100 
101 NS_IMETHODIMP
SetLocation(nsIFile * aLocation)102 nsBeckyFilters::SetLocation(nsIFile* aLocation) {
103   NS_ENSURE_ARG_POINTER(aLocation);
104 
105   bool exists = false;
106   nsresult rv = aLocation->Exists(&exists);
107   NS_ENSURE_SUCCESS(rv, rv);
108   if (!exists) return NS_ERROR_FILE_NOT_FOUND;
109 
110   mLocation = aLocation;
111   return NS_OK;
112 }
113 
ConvertSearchKeyToAttrib(const nsACString & aKey)114 static nsMsgSearchAttribValue ConvertSearchKeyToAttrib(const nsACString& aKey) {
115   if (aKey.EqualsLiteral("From") || aKey.EqualsLiteral("Sender") ||
116       aKey.EqualsLiteral("From, Sender, X-Sender")) {
117     return nsMsgSearchAttrib::Sender;
118   } else if (aKey.EqualsLiteral("Subject")) {
119     return nsMsgSearchAttrib::Subject;
120   } else if (aKey.EqualsLiteral("[body]")) {
121     return nsMsgSearchAttrib::Body;
122   } else if (aKey.EqualsLiteral("Date")) {
123     return nsMsgSearchAttrib::Date;
124   } else if (aKey.EqualsLiteral("To")) {
125     return nsMsgSearchAttrib::To;
126   } else if (aKey.EqualsLiteral("Cc")) {
127     return nsMsgSearchAttrib::CC;
128   } else if (aKey.EqualsLiteral("To,  Cc,  Bcc:")) {
129     return nsMsgSearchAttrib::ToOrCC;
130   }
131   return -1;
132 }
133 
ConvertSearchFlagsToOperator(const nsACString & aFlags)134 static nsMsgSearchOpValue ConvertSearchFlagsToOperator(
135     const nsACString& aFlags) {
136   nsCString flags(aFlags);
137   int32_t lastTabPosition = flags.RFindChar('\t');
138   if ((lastTabPosition == -1) ||
139       ((int32_t)aFlags.Length() == lastTabPosition - 1)) {
140     return -1;
141   }
142 
143   switch (aFlags.CharAt(0)) {
144     case 'X':
145       return nsMsgSearchOp::DoesntContain;
146     case 'O':
147       if (aFlags.FindChar('T', lastTabPosition + 1) >= 0)
148         return nsMsgSearchOp::BeginsWith;
149       return nsMsgSearchOp::Contains;
150     default:
151       return -1;
152   }
153 }
154 
ParseRuleLine(const nsCString & aLine,nsMsgSearchAttribValue * aSearchAttribute,nsMsgSearchOpValue * aSearchOperator,nsString & aSearchKeyword)155 nsresult nsBeckyFilters::ParseRuleLine(const nsCString& aLine,
156                                        nsMsgSearchAttribValue* aSearchAttribute,
157                                        nsMsgSearchOpValue* aSearchOperator,
158                                        nsString& aSearchKeyword) {
159   int32_t firstColonPosition = aLine.FindChar(':');
160   if (firstColonPosition == -1 ||
161       (int32_t)aLine.Length() == firstColonPosition - 1) {
162     return NS_ERROR_FAILURE;
163   }
164 
165   int32_t secondColonPosition = aLine.FindChar(':', firstColonPosition + 1);
166   if (secondColonPosition == -1 ||
167       (int32_t)aLine.Length() == secondColonPosition - 1) {
168     return NS_ERROR_FAILURE;
169   }
170 
171   int32_t length = secondColonPosition - firstColonPosition - 1;
172   nsMsgSearchAttribValue searchAttribute;
173   searchAttribute = ConvertSearchKeyToAttrib(
174       Substring(aLine, firstColonPosition + 1, length));
175   if (searchAttribute < 0) return NS_ERROR_FAILURE;
176 
177   int32_t tabPosition = aLine.FindChar('\t');
178   if (tabPosition == -1 || (int32_t)aLine.Length() == tabPosition - 1) {
179     return NS_ERROR_FAILURE;
180   }
181 
182   nsMsgSearchOpValue searchOperator;
183   searchOperator =
184       ConvertSearchFlagsToOperator(Substring(aLine, tabPosition + 1));
185   if (searchOperator < 0) return NS_ERROR_FAILURE;
186 
187   *aSearchOperator = searchOperator;
188   *aSearchAttribute = searchAttribute;
189   length = tabPosition - secondColonPosition - 1;
190   CopyUTF8toUTF16(Substring(aLine, secondColonPosition + 1, length),
191                   aSearchKeyword);
192   return NS_OK;
193 }
194 
SetSearchTerm(const nsCString & aLine,nsIMsgFilter * aFilter)195 nsresult nsBeckyFilters::SetSearchTerm(const nsCString& aLine,
196                                        nsIMsgFilter* aFilter) {
197   NS_ENSURE_ARG_POINTER(aFilter);
198 
199   nsresult rv;
200   nsMsgSearchAttribValue searchAttribute = -1;
201   nsMsgSearchOpValue searchOperator = -1;
202   nsAutoString searchKeyword;
203   rv = ParseRuleLine(aLine, &searchAttribute, &searchOperator, searchKeyword);
204   NS_ENSURE_SUCCESS(rv, rv);
205 
206   nsCOMPtr<nsIMsgSearchTerm> term;
207   rv = aFilter->CreateTerm(getter_AddRefs(term));
208   NS_ENSURE_SUCCESS(rv, rv);
209 
210   rv = term->SetAttrib(searchAttribute);
211   NS_ENSURE_SUCCESS(rv, rv);
212   rv = term->SetOp(searchOperator);
213   NS_ENSURE_SUCCESS(rv, rv);
214 
215   nsCOMPtr<nsIMsgSearchValue> value;
216   rv = term->GetValue(getter_AddRefs(value));
217   NS_ENSURE_SUCCESS(rv, rv);
218 
219   rv = value->SetAttrib(searchAttribute);
220   NS_ENSURE_SUCCESS(rv, rv);
221   rv = value->SetStr(searchKeyword);
222   NS_ENSURE_SUCCESS(rv, rv);
223   rv = term->SetValue(value);
224   NS_ENSURE_SUCCESS(rv, rv);
225   rv = term->SetBooleanAnd(false);
226   NS_ENSURE_SUCCESS(rv, rv);
227 
228   if (!searchKeyword.IsEmpty())
229     rv = aFilter->SetFilterName(searchKeyword);
230   else
231     rv = aFilter->SetFilterName(u"No name"_ns);
232   NS_ENSURE_SUCCESS(rv, rv);
233 
234   return aFilter->AppendTerm(term);
235 }
236 
CreateRuleAction(nsIMsgFilter * aFilter,nsMsgRuleActionType actionType,nsIMsgRuleAction ** _retval)237 nsresult nsBeckyFilters::CreateRuleAction(nsIMsgFilter* aFilter,
238                                           nsMsgRuleActionType actionType,
239                                           nsIMsgRuleAction** _retval) {
240   nsresult rv;
241   nsCOMPtr<nsIMsgRuleAction> action;
242   rv = aFilter->CreateAction(getter_AddRefs(action));
243   NS_ENSURE_SUCCESS(rv, rv);
244   rv = action->SetType(actionType);
245   NS_ENSURE_SUCCESS(rv, rv);
246 
247   action.forget(_retval);
248 
249   return NS_OK;
250 }
251 
GetActionTarget(const nsCString & aLine,nsCString & aTarget)252 nsresult nsBeckyFilters::GetActionTarget(const nsCString& aLine,
253                                          nsCString& aTarget) {
254   int32_t firstColonPosition = aLine.FindChar(':');
255   if (firstColonPosition < -1 ||
256       aLine.Length() == static_cast<uint32_t>(firstColonPosition)) {
257     return NS_ERROR_FAILURE;
258   }
259 
260   aTarget.Assign(Substring(aLine, firstColonPosition + 1));
261 
262   return NS_OK;
263 }
264 
GetResendTarget(const nsCString & aLine,nsCString & aTemplate,nsCString & aTargetAddress)265 nsresult nsBeckyFilters::GetResendTarget(const nsCString& aLine,
266                                          nsCString& aTemplate,
267                                          nsCString& aTargetAddress) {
268   nsresult rv;
269   nsAutoCString target;
270   rv = GetActionTarget(aLine, target);
271   NS_ENSURE_SUCCESS(rv, rv);
272 
273   int32_t asteriskPosition = target.FindChar('*');
274   if (asteriskPosition < 0) {
275     aTemplate.Assign(target);
276     return NS_OK;
277   }
278 
279   if (target.Length() == static_cast<uint32_t>(asteriskPosition))
280     return NS_ERROR_FAILURE;
281 
282   aTemplate.Assign(StringHead(target, asteriskPosition - 1));
283   aTargetAddress.Assign(Substring(target, asteriskPosition + 1));
284 
285   return NS_OK;
286 }
287 
CreateResendAction(const nsCString & aLine,nsIMsgFilter * aFilter,const nsMsgRuleActionType & aActionType,nsIMsgRuleAction ** _retval)288 nsresult nsBeckyFilters::CreateResendAction(
289     const nsCString& aLine, nsIMsgFilter* aFilter,
290     const nsMsgRuleActionType& aActionType, nsIMsgRuleAction** _retval) {
291   nsresult rv;
292   nsCOMPtr<nsIMsgRuleAction> action;
293   rv = CreateRuleAction(aFilter, aActionType, getter_AddRefs(action));
294   NS_ENSURE_SUCCESS(rv, rv);
295 
296   nsAutoCString templateString;
297   nsAutoCString targetAddress;
298   rv = GetResendTarget(aLine, templateString, targetAddress);
299   NS_ENSURE_SUCCESS(rv, rv);
300 
301   if (aActionType == nsMsgFilterAction::Forward)
302     rv = action->SetStrValue(targetAddress);
303   else
304     rv = action->SetStrValue(templateString);
305   NS_ENSURE_SUCCESS(rv, rv);
306 
307   action.forget(_retval);
308 
309   return NS_OK;
310 }
311 
GetFolderNameFromTarget(const nsCString & aTarget,nsAString & aName)312 nsresult nsBeckyFilters::GetFolderNameFromTarget(const nsCString& aTarget,
313                                                  nsAString& aName) {
314   int32_t backslashPosition = aTarget.RFindChar('\\');
315   if (backslashPosition > 0) {
316     NS_ConvertUTF8toUTF16 utf16String(
317         Substring(aTarget, backslashPosition + 1));
318     nsBeckyUtils::TranslateFolderName(utf16String, aName);
319   }
320 
321   return NS_OK;
322 }
323 
GetDistributeTarget(const nsCString & aLine,nsCString & aTargetFolder)324 nsresult nsBeckyFilters::GetDistributeTarget(const nsCString& aLine,
325                                              nsCString& aTargetFolder) {
326   nsresult rv;
327   nsAutoCString target;
328   rv = GetActionTarget(aLine, target);
329   NS_ENSURE_SUCCESS(rv, rv);
330 
331   target.Trim("\\", false, true);
332   nsAutoString folderName;
333   rv = GetFolderNameFromTarget(target, folderName);
334   NS_ENSURE_SUCCESS(rv, rv);
335 
336   nsCOMPtr<nsIMsgFolder> folder;
337   rv = GetMessageFolder(folderName, getter_AddRefs(folder));
338   NS_ENSURE_SUCCESS(rv, rv);
339 
340   if (!folder) {
341     rv = mServer->GetRootMsgFolder(getter_AddRefs(folder));
342     NS_ENSURE_SUCCESS(rv, rv);
343   }
344   return folder->GetURI(aTargetFolder);
345 }
346 
CreateDistributeAction(const nsCString & aLine,nsIMsgFilter * aFilter,const nsMsgRuleActionType & aActionType,nsIMsgRuleAction ** _retval)347 nsresult nsBeckyFilters::CreateDistributeAction(
348     const nsCString& aLine, nsIMsgFilter* aFilter,
349     const nsMsgRuleActionType& aActionType, nsIMsgRuleAction** _retval) {
350   nsresult rv;
351   nsCOMPtr<nsIMsgRuleAction> action;
352   rv = CreateRuleAction(aFilter, aActionType, getter_AddRefs(action));
353   NS_ENSURE_SUCCESS(rv, rv);
354   nsAutoCString targetFolder;
355   rv = GetDistributeTarget(aLine, targetFolder);
356   NS_ENSURE_SUCCESS(rv, rv);
357   rv = action->SetTargetFolderUri(targetFolder);
358   NS_ENSURE_SUCCESS(rv, rv);
359 
360   action.forget(_retval);
361 
362   return NS_OK;
363 }
364 
CreateLeaveOrDeleteAction(const nsCString & aLine,nsIMsgFilter * aFilter,nsIMsgRuleAction ** _retval)365 nsresult nsBeckyFilters::CreateLeaveOrDeleteAction(const nsCString& aLine,
366                                                    nsIMsgFilter* aFilter,
367                                                    nsIMsgRuleAction** _retval) {
368   nsresult rv;
369   nsMsgRuleActionType actionType;
370   if (aLine.CharAt(3) == '0') {
371     actionType = nsMsgFilterAction::LeaveOnPop3Server;
372   } else if (aLine.CharAt(3) == '1') {
373     if (aLine.CharAt(5) == '1')
374       actionType = nsMsgFilterAction::Delete;
375     else
376       actionType = nsMsgFilterAction::DeleteFromPop3Server;
377   } else {
378     return NS_ERROR_FAILURE;
379   }
380   nsCOMPtr<nsIMsgRuleAction> action;
381   rv = CreateRuleAction(aFilter, actionType, getter_AddRefs(action));
382   NS_ENSURE_SUCCESS(rv, rv);
383 
384   action.forget(_retval);
385 
386   return NS_OK;
387 }
388 
SetRuleAction(const nsCString & aLine,nsIMsgFilter * aFilter)389 nsresult nsBeckyFilters::SetRuleAction(const nsCString& aLine,
390                                        nsIMsgFilter* aFilter) {
391   if (!aFilter || aLine.Length() < 4) return NS_ERROR_FAILURE;
392 
393   nsresult rv = NS_OK;
394   nsCOMPtr<nsIMsgRuleAction> action;
395   switch (aLine.CharAt(1)) {
396     case 'R':  // Reply
397       rv = CreateResendAction(aLine, aFilter, nsMsgFilterAction::Reply,
398                               getter_AddRefs(action));
399       break;
400     case 'F':  // Forward
401       rv = CreateResendAction(aLine, aFilter, nsMsgFilterAction::Forward,
402                               getter_AddRefs(action));
403       break;
404     case 'L':  // Leave or delete
405       rv = CreateLeaveOrDeleteAction(aLine, aFilter, getter_AddRefs(action));
406       break;
407     case 'Y':  // Copy
408       rv = CreateDistributeAction(aLine, aFilter,
409                                   nsMsgFilterAction::CopyToFolder,
410                                   getter_AddRefs(action));
411       break;
412     case 'M':  // Move
413       rv = CreateDistributeAction(aLine, aFilter,
414                                   nsMsgFilterAction::MoveToFolder,
415                                   getter_AddRefs(action));
416       break;
417     case 'G':                      // Set flag
418       if (aLine.CharAt(3) == 'R')  // Read
419         rv = CreateRuleAction(aFilter, nsMsgFilterAction::MarkRead,
420                               getter_AddRefs(action));
421       break;
422     default:
423       return NS_OK;
424   }
425   NS_ENSURE_SUCCESS(rv, rv);
426 
427   if (action) {
428     rv = aFilter->AppendAction(action);
429     NS_ENSURE_SUCCESS(rv, rv);
430   }
431 
432   return NS_OK;
433 }
434 
CreateFilter(bool aIncoming,nsIMsgFilter ** _retval)435 nsresult nsBeckyFilters::CreateFilter(bool aIncoming, nsIMsgFilter** _retval) {
436   NS_ENSURE_STATE(mServer);
437 
438   nsCOMPtr<nsIMsgFilterList> filterList;
439   nsresult rv = mServer->GetFilterList(nullptr, getter_AddRefs(filterList));
440   NS_ENSURE_SUCCESS(rv, rv);
441 
442   nsCOMPtr<nsIMsgFilter> filter;
443   rv = filterList->CreateFilter(EmptyString(), getter_AddRefs(filter));
444   NS_ENSURE_SUCCESS(rv, rv);
445 
446   if (aIncoming)
447     filter->SetFilterType(nsMsgFilterType::InboxRule | nsMsgFilterType::Manual);
448   else
449     filter->SetFilterType(nsMsgFilterType::PostOutgoing |
450                           nsMsgFilterType::Manual);
451 
452   filter->SetEnabled(true);
453   filter.forget(_retval);
454 
455   return NS_OK;
456 }
457 
AppendFilter(nsIMsgFilter * aFilter)458 nsresult nsBeckyFilters::AppendFilter(nsIMsgFilter* aFilter) {
459   NS_ENSURE_STATE(mServer);
460 
461   nsCOMPtr<nsIMsgFilterList> filterList;
462   nsresult rv = mServer->GetFilterList(nullptr, getter_AddRefs(filterList));
463   NS_ENSURE_SUCCESS(rv, rv);
464 
465   uint32_t count;
466   rv = filterList->GetFilterCount(&count);
467   NS_ENSURE_SUCCESS(rv, rv);
468 
469   return filterList->InsertFilterAt(count, aFilter);
470 }
471 
ParseFilterFile(nsIFile * aFile,bool aIncoming)472 nsresult nsBeckyFilters::ParseFilterFile(nsIFile* aFile, bool aIncoming) {
473   nsresult rv;
474   nsCOMPtr<nsILineInputStream> lineStream;
475   rv = nsBeckyUtils::CreateLineInputStream(aFile, getter_AddRefs(lineStream));
476   NS_ENSURE_SUCCESS(rv, rv);
477 
478   bool more = true;
479   nsAutoCString line;
480 
481   nsCOMPtr<nsIMsgFilter> filter;
482   while (NS_SUCCEEDED(rv) && more) {
483     rv = lineStream->ReadLine(line, &more);
484 
485     switch (line.CharAt(0)) {
486       case ':':
487         if (line.EqualsLiteral(":Begin \"\"")) {
488           CreateFilter(aIncoming, getter_AddRefs(filter));
489         } else if (line.EqualsLiteral(":End \"\"")) {
490           if (filter) AppendFilter(filter);
491           filter = nullptr;
492         }
493         break;
494       case '!':
495         SetRuleAction(line, filter);
496         break;
497       case '@':
498         SetSearchTerm(line, filter);
499         break;
500       case '$':  // $X: disabled
501         if (StringBeginsWith(line, "$X"_ns) && filter) {
502           filter->SetEnabled(false);
503         }
504         break;
505       default:
506         break;
507     }
508   }
509 
510   return NS_OK;
511 }
512 
513 NS_IMETHODIMP
Import(char16_t ** aError,bool * _retval)514 nsBeckyFilters::Import(char16_t** aError, bool* _retval) {
515   NS_ENSURE_ARG_POINTER(aError);
516   NS_ENSURE_ARG_POINTER(_retval);
517 
518   // If mLocation is null, set it to the default filter directory.
519   // If mLocation is a file, we import it as incoming folder.
520   // If mLocation is a directory, we try to import incoming and outgoing folders
521   // from it (in default files).
522 
523   *_retval = false;
524   nsresult rv;
525   nsCOMPtr<nsIFile> filterFile;
526 
527   bool haveFile = false;
528 
529   if (!mLocation) {
530     bool retval = false;
531     rv = AutoLocate(nullptr, getter_AddRefs(mLocation), &retval);
532     NS_ENSURE_SUCCESS(rv, rv);
533     if (!retval) return NS_ERROR_FILE_NOT_FOUND;
534   }
535 
536   // What type of location do we have?
537   bool isDirectory = false;
538   rv = mLocation->IsDirectory(&isDirectory);
539   NS_ENSURE_SUCCESS(rv, rv);
540   if (isDirectory) {
541     haveFile = false;
542   } else {
543     bool isFile = false;
544     rv = mLocation->IsFile(&isFile);
545     NS_ENSURE_SUCCESS(rv, rv);
546     if (isFile) {
547       haveFile = true;
548       mLocation->Clone(getter_AddRefs(filterFile));
549     } else {
550       // mLocation is neither file nor directory.
551       return NS_ERROR_UNEXPECTED;
552     }
553   }
554 
555   bool haveIncoming = true;
556   if (haveFile) {
557     // If the passed filename equals OFilter.def, import as outgoing filters.
558     // Everything else is considered incoming.
559     nsAutoString fileName;
560     rv = mLocation->GetLeafName(fileName);
561     NS_ENSURE_SUCCESS(rv, rv);
562     if (fileName.EqualsLiteral("OFilter.def")) haveIncoming = false;
563   }
564 
565   // Try importing from the passed in file or the default incoming filters file.
566   if ((haveFile && haveIncoming) ||
567       (!haveFile && NS_SUCCEEDED(GetFilterFile(true, mLocation,
568                                                getter_AddRefs(filterFile))))) {
569     rv = CollectServers();
570     NS_ENSURE_SUCCESS(rv, rv);
571 
572     rv = nsBeckyUtils::ConvertToUTF8File(filterFile,
573                                          getter_AddRefs(mConvertedFile));
574     NS_ENSURE_SUCCESS(rv, rv);
575 
576     rv = ParseFilterFile(mConvertedFile, true);
577     if (NS_SUCCEEDED(rv)) *_retval = true;
578 
579     (void)RemoveConvertedFile();
580   }
581 
582   // If we didn't have a file passed (but a directory), try finding also
583   // outgoing filters.
584   if ((haveFile && !haveIncoming) ||
585       (!haveFile && NS_SUCCEEDED(GetFilterFile(false, mLocation,
586                                                getter_AddRefs(filterFile))))) {
587     rv = CollectServers();
588     NS_ENSURE_SUCCESS(rv, rv);
589 
590     rv = nsBeckyUtils::ConvertToUTF8File(filterFile,
591                                          getter_AddRefs(mConvertedFile));
592     NS_ENSURE_SUCCESS(rv, rv);
593 
594     rv = ParseFilterFile(mConvertedFile, false);
595     if (NS_SUCCEEDED(rv)) *_retval = true;
596 
597     (void)RemoveConvertedFile();
598   }
599 
600   return rv;
601 }
602 
FindMessageFolder(const nsAString & aName,nsIMsgFolder * aParentFolder,nsIMsgFolder ** _retval)603 nsresult nsBeckyFilters::FindMessageFolder(const nsAString& aName,
604                                            nsIMsgFolder* aParentFolder,
605                                            nsIMsgFolder** _retval) {
606   nsresult rv;
607 
608   nsCOMPtr<nsIMsgFolder> found;
609   rv = aParentFolder->GetChildNamed(aName, getter_AddRefs(found));
610   if (found) {
611     NS_ADDREF(*_retval = found);
612     return NS_OK;
613   }
614 
615   nsTArray<RefPtr<nsIMsgFolder>> children;
616   rv = aParentFolder->GetSubFolders(children);
617   NS_ENSURE_SUCCESS(rv, rv);
618 
619   for (nsIMsgFolder* child : children) {
620     rv = FindMessageFolder(aName, child, getter_AddRefs(found));
621     if (found) {
622       NS_ADDREF(*_retval = found);
623       return NS_OK;
624     }
625   }
626 
627   return NS_MSG_ERROR_INVALID_FOLDER_NAME;
628 }
629 
FindMessageFolderInServer(const nsAString & aName,nsIMsgIncomingServer * aServer,nsIMsgFolder ** _retval)630 nsresult nsBeckyFilters::FindMessageFolderInServer(
631     const nsAString& aName, nsIMsgIncomingServer* aServer,
632     nsIMsgFolder** _retval) {
633   nsresult rv;
634   nsCOMPtr<nsIMsgFolder> rootFolder;
635   rv = aServer->GetRootMsgFolder(getter_AddRefs(rootFolder));
636   NS_ENSURE_SUCCESS(rv, rv);
637 
638   return FindMessageFolder(aName, rootFolder, _retval);
639 }
640 
GetMessageFolder(const nsAString & aName,nsIMsgFolder ** _retval)641 nsresult nsBeckyFilters::GetMessageFolder(const nsAString& aName,
642                                           nsIMsgFolder** _retval) {
643   nsresult rv;
644 
645   nsCOMPtr<nsIMsgAccountManager> accountManager;
646   accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
647   NS_ENSURE_SUCCESS(rv, rv);
648 
649   nsTArray<RefPtr<nsIMsgAccount>> accounts;
650   rv = accountManager->GetAccounts(accounts);
651   NS_ENSURE_SUCCESS(rv, rv);
652 
653   nsCOMPtr<nsIMsgFolder> found;
654   for (auto account : accounts) {
655     if (!account) continue;
656 
657     nsCOMPtr<nsIMsgIncomingServer> server;
658     account->GetIncomingServer(getter_AddRefs(server));
659     if (!server) continue;
660     FindMessageFolderInServer(aName, server, getter_AddRefs(found));
661     if (found) break;
662   }
663 
664   if (!found) {
665     nsCOMPtr<nsIMsgIncomingServer> server;
666     rv = accountManager->GetLocalFoldersServer(getter_AddRefs(server));
667     NS_ENSURE_SUCCESS(rv, rv);
668 
669     FindMessageFolderInServer(aName, server, getter_AddRefs(found));
670   }
671 
672   if (!found) return NS_MSG_ERROR_INVALID_FOLDER_NAME;
673 
674   found.forget(_retval);
675 
676   return NS_OK;
677 }
678 
CollectServers()679 nsresult nsBeckyFilters::CollectServers() {
680   nsresult rv;
681   nsCOMPtr<nsIMsgAccountManager> accountManager;
682   accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
683   NS_ENSURE_SUCCESS(rv, rv);
684 
685   nsCOMPtr<nsIMsgAccount> defaultAccount;
686   rv = accountManager->GetDefaultAccount(getter_AddRefs(defaultAccount));
687   NS_ENSURE_SUCCESS(rv, rv);
688   if (defaultAccount)
689     return defaultAccount->GetIncomingServer(getter_AddRefs(mServer));
690 
691   // We can also import filters into the Local Folders account.
692   rv = accountManager->GetLocalFoldersServer(getter_AddRefs(mServer));
693   NS_ENSURE_SUCCESS(rv, rv);
694   if (!mServer) return NS_ERROR_UNEXPECTED;
695 
696   return NS_OK;
697 }
698 
RemoveConvertedFile()699 nsresult nsBeckyFilters::RemoveConvertedFile() {
700   nsresult rv = NS_OK;
701   if (mConvertedFile) {
702     bool exists = false;
703     mConvertedFile->Exists(&exists);
704     if (exists) {
705       rv = mConvertedFile->Remove(false);
706       if (NS_SUCCEEDED(rv)) mConvertedFile = nullptr;
707     }
708   }
709   return rv;
710 }
711