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