1 #include "filezilla.h"
2 #include "filter_manager.h"
3 #include "filteredit.h"
4 #include "filezillaapp.h"
5 #include "inputdialog.h"
6 #include "Mainfrm.h"
7 #include "Options.h"
8 #include "state.h"
9 #include "xmlfunctions.h"
10 
11 #include "../commonui/ipcmutex.h"
12 
13 #include <libfilezilla/local_filesys.hpp>
14 
15 #include <wx/statline.h>
16 #include <wx/statbox.h>
17 
18 bool CFilterManager::m_loaded = false;
19 filter_data CFilterManager::global_filters_;
20 bool CFilterManager::m_filters_disabled = false;
21 
BEGIN_EVENT_TABLE(CFilterDialog,wxDialogEx)22 BEGIN_EVENT_TABLE(CFilterDialog, wxDialogEx)
23 EVT_BUTTON(XRCID("wxID_OK"), CFilterDialog::OnOkOrApply)
24 EVT_BUTTON(XRCID("wxID_CANCEL"), CFilterDialog::OnCancel)
25 EVT_BUTTON(XRCID("wxID_APPLY"), CFilterDialog::OnOkOrApply)
26 EVT_BUTTON(XRCID("ID_EDIT"), CFilterDialog::OnEdit)
27 EVT_CHECKLISTBOX(wxID_ANY, CFilterDialog::OnFilterSelect)
28 EVT_BUTTON(XRCID("ID_SAVESET"), CFilterDialog::OnSaveAs)
29 EVT_BUTTON(XRCID("ID_RENAMESET"), CFilterDialog::OnRename)
30 EVT_BUTTON(XRCID("ID_DELETESET"), CFilterDialog::OnDeleteSet)
31 EVT_CHOICE(XRCID("ID_SETS"), CFilterDialog::OnSetSelect)
32 
33 EVT_BUTTON(XRCID("ID_LOCAL_ENABLEALL"), CFilterDialog::OnChangeAll)
34 EVT_BUTTON(XRCID("ID_LOCAL_DISABLEALL"), CFilterDialog::OnChangeAll)
35 EVT_BUTTON(XRCID("ID_REMOTE_ENABLEALL"), CFilterDialog::OnChangeAll)
36 EVT_BUTTON(XRCID("ID_REMOTE_DISABLEALL"), CFilterDialog::OnChangeAll)
37 END_EVENT_TABLE()
38 
39 
40 CFilterDialog::CFilterDialog()
41 	: m_filters(global_filters_.filters)
42 	, m_filterSets(global_filters_.filter_sets)
43 	, m_currentFilterSet(global_filters_.current_filter_set)
44 {
45 }
46 
Create(CMainFrame * parent)47 bool CFilterDialog::Create(CMainFrame* parent)
48 {
49 	m_pMainFrame = parent;
50 
51 	wxDialogEx::Create(parent, -1, _("Directory listing filters"));
52 
53 	auto & lay = layout();
54 
55 	auto main = lay.createMain(this, 1);
56 	main->AddGrowableCol(0);
57 
58 	{
59 		auto row = lay.createFlex(0, 1);
60 		main->Add(row);
61 
62 		row->Add(new wxStaticText(this, -1, _("&Filter sets:")), lay.valign);
63 		auto choice = new wxChoice(this, XRCID("ID_SETS"));
64 		choice->SetFocus();
65 		row->Add(choice, lay.valign);
66 		row->Add(new wxButton(this, XRCID("ID_SAVESET"), _("&Save as...")), lay.valign);
67 		row->Add(new wxButton(this, XRCID("ID_RENAMESET"), _("&Rename...")), lay.valign);
68 		row->Add(new wxButton(this, XRCID("ID_DELETESET"), _("&Delete...")), lay.valign);
69 
70 		wxString name = _("Custom filter set");
71 		choice->Append(_T("<") + name + _T(">"));
72 		for (size_t i = 1; i < m_filterSets.size(); ++i) {
73 			choice->Append(m_filterSets[i].name);
74 		}
75 		choice->SetSelection(m_currentFilterSet);
76 	}
77 
78 	auto sides = lay.createGrid(2);
79 	main->Add(sides, lay.grow);
80 
81 	{
82 		auto [box, inner] = lay.createStatBox(sides, _("Local filters:"), 1);
83 		inner->AddGrowableCol(0);
84 		auto filters = new wxCheckListBox(box, XRCID("ID_LOCALFILTERS"), wxDefaultPosition, wxSize(-1, lay.dlgUnits(100)));
85 		inner->Add(filters, 1, wxGROW);
86 		auto row = lay.createFlex(0, 1);
87 		inner->Add(row, 0, wxALIGN_CENTER_HORIZONTAL);
88 		row->Add(new wxButton(box, XRCID("ID_LOCAL_ENABLEALL"), _("E&nable all")), lay.valign);
89 		row->Add(new wxButton(box, XRCID("ID_LOCAL_DISABLEALL"), _("D&isable all")), lay.valign);
90 
91 		filters->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(CFilterDialog::OnMouseEvent), 0, this);
92 		filters->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(CFilterDialog::OnKeyEvent), 0, this);
93 
94 	}
95 	{
96 		auto [box, inner] = lay.createStatBox(sides, _("Remote filters:"), 1);
97 		inner->AddGrowableCol(0);
98 		auto filters = new wxCheckListBox(box, XRCID("ID_REMOTEFILTERS"), wxDefaultPosition, wxSize(-1, lay.dlgUnits(100)));
99 		inner->Add(filters, 1, wxGROW);
100 		auto row = lay.createFlex(0, 1);
101 		inner->Add(row, 0, wxALIGN_CENTER_HORIZONTAL);
102 		row->Add(new wxButton(box, XRCID("ID_REMOTE_ENABLEALL"), _("En&able all")), lay.valign);
103 		row->Add(new wxButton(box, XRCID("ID_REMOTE_DISABLEALL"), _("Disa&ble all")), lay.valign);
104 
105 		filters->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(CFilterDialog::OnMouseEvent), 0, this);
106 		filters->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(CFilterDialog::OnKeyEvent), 0, this);
107 	}
108 
109 
110 	main->Add(new wxStaticText(this, -1, _("Hold the shift key to toggle the filter state on both sides simultaneously.")));
111 
112 	main->Add(new wxStaticLine(this), lay.grow);
113 
114 	{
115 		auto row = lay.createFlex(0, 1);
116 		row->AddGrowableCol(0);
117 		main->Add(row, lay.grow);
118 		row->Add(new wxButton(this, XRCID("ID_EDIT"), _("&Edit filter rules...")), lay.valign);
119 		row->AddStretchSpacer();
120 
121 		auto buttons = lay.createGrid(0, 1);
122 		row->Add(buttons, lay.valign);
123 		auto ok = new wxButton(this, wxID_OK, _("OK"));
124 		ok->SetDefault();
125 		buttons->Add(ok, lay.valigng);
126 		buttons->Add(new wxButton(this, wxID_CANCEL, _("Cancel")), lay.valigng);
127 		buttons->Add(new wxButton(this, wxID_APPLY, _("Apply")), lay.valigng);
128 	}
129 
130 	DisplayFilters();
131 
132 	SetCtrlState();
133 
134 	GetSizer()->Fit(this);
135 
136 	return true;
137 }
138 
OnOkOrApply(wxCommandEvent & event)139 void CFilterDialog::OnOkOrApply(wxCommandEvent& event)
140 {
141 	global_filters_.filters = m_filters;
142 	global_filters_.filter_sets = m_filterSets;
143 	global_filters_.current_filter_set = m_currentFilterSet;
144 
145 	SaveFilters();
146 	m_filters_disabled = false;
147 
148 	CContextManager::Get()->NotifyAllHandlers(STATECHANGE_APPLYFILTER);
149 
150 	if (event.GetId() == wxID_OK) {
151 		EndModal(wxID_OK);
152 	}
153 }
154 
OnCancel(wxCommandEvent &)155 void CFilterDialog::OnCancel(wxCommandEvent&)
156 {
157 	EndModal(wxID_CANCEL);
158 }
159 
OnEdit(wxCommandEvent &)160 void CFilterDialog::OnEdit(wxCommandEvent&)
161 {
162 	CFilterEditDialog dlg;
163 	if (!dlg.Create(this, m_filters, m_filterSets)) {
164 		return;
165 	}
166 
167 	if (dlg.ShowModal() != wxID_OK) {
168 		return;
169 	}
170 
171 	m_filters = dlg.GetFilters();
172 	m_filterSets = dlg.GetFilterSets();
173 
174 	DisplayFilters();
175 }
176 
DisplayFilters()177 void CFilterDialog::DisplayFilters()
178 {
179 	wxCheckListBox* pLocalFilters = XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox);
180 	wxCheckListBox* pRemoteFilters = XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox);
181 
182 	pLocalFilters->Clear();
183 	pRemoteFilters->Clear();
184 
185 	for (unsigned int i = 0; i < m_filters.size(); ++i) {
186 		const CFilter& filter = m_filters[i];
187 
188 		const bool localOnly = filter.IsLocalFilter();
189 
190 		pLocalFilters->Append(filter.name);
191 		pRemoteFilters->Append(filter.name);
192 
193 		pLocalFilters->Check(i, m_filterSets[m_currentFilterSet].local[i]);
194 		pRemoteFilters->Check(i, localOnly ? false : m_filterSets[m_currentFilterSet].remote[i]);
195 	}
196 }
197 
OnMouseEvent(wxMouseEvent & event)198 void CFilterDialog::OnMouseEvent(wxMouseEvent& event)
199 {
200 	m_shiftClick = event.ShiftDown();
201 	event.Skip();
202 }
203 
OnKeyEvent(wxKeyEvent & event)204 void CFilterDialog::OnKeyEvent(wxKeyEvent& event)
205 {
206 	m_shiftClick = event.ShiftDown();
207 	event.Skip();
208 }
209 
OnFilterSelect(wxCommandEvent & event)210 void CFilterDialog::OnFilterSelect(wxCommandEvent& event)
211 {
212 	wxCheckListBox* pLocal = XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox);
213 	wxCheckListBox* pRemote = XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox);
214 
215 	int item = event.GetSelection();
216 
217 	const CFilter& filter = m_filters[item];
218 	const bool localOnly = filter.IsLocalFilter();
219 	if (localOnly && event.GetEventObject() != pLocal) {
220 		pRemote->Check(item, false);
221 		wxMessageBoxEx(_("Selected filter only works for local files."), _("Cannot select filter"), wxICON_INFORMATION);
222 		return;
223 	}
224 
225 
226 	if (m_shiftClick) {
227 		if (event.GetEventObject() == pLocal) {
228 			if (!localOnly) {
229 				pRemote->Check(item, pLocal->IsChecked(event.GetSelection()));
230 			}
231 		}
232 		else {
233 			pLocal->Check(item, pRemote->IsChecked(event.GetSelection()));
234 		}
235 	}
236 
237 	if (m_currentFilterSet) {
238 		m_filterSets[0] = m_filterSets[m_currentFilterSet];
239 		m_currentFilterSet = 0;
240 		wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
241 		pChoice->SetSelection(0);
242 	}
243 
244 	bool localChecked = pLocal->IsChecked(event.GetSelection());
245 	bool remoteChecked = pRemote->IsChecked(event.GetSelection());
246 	m_filterSets[0].local[item] = localChecked;
247 	m_filterSets[0].remote[item] = remoteChecked;
248 }
249 
OnSaveAs(wxCommandEvent &)250 void CFilterDialog::OnSaveAs(wxCommandEvent&)
251 {
252 	CInputDialog dlg;
253 	dlg.Create(this, _("Enter name for filterset"), _("Please enter a unique name for this filter set"), 255);
254 	if (dlg.ShowModal() != wxID_OK) {
255 		return;
256 	}
257 
258 	std::wstring name = dlg.GetValue().ToStdWstring();
259 	if (name.empty()) {
260 		wxMessageBoxEx(_("No name for the filterset given."), _("Cannot save filterset"), wxICON_INFORMATION);
261 		return;
262 	}
263 	wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
264 
265 	CFilterSet set;
266 	int old_pos = pChoice->GetSelection();
267 	if (old_pos > 0) {
268 		set = m_filterSets[old_pos];
269 	}
270 	else {
271 		set = m_filterSets[0];
272 	}
273 
274 	int pos = pChoice->FindString(name);
275 	if (pos != wxNOT_FOUND) {
276 		if (wxMessageBoxEx(_("Given filterset name already exists, overwrite filter set?"), _("Filter set already exists"), wxICON_QUESTION | wxYES_NO) != wxYES) {
277 			return;
278 		}
279 	}
280 
281 	if (pos == wxNOT_FOUND) {
282 		pos = m_filterSets.size();
283 		m_filterSets.push_back(set);
284 		pChoice->Append(name);
285 	}
286 	else {
287 		m_filterSets[pos] = set;
288 	}
289 
290 	m_filterSets[pos].name = name;
291 
292 	pChoice->SetSelection(pos);
293 	m_currentFilterSet = pos;
294 
295 	SetCtrlState();
296 
297 	GetSizer()->Fit(this);
298 }
299 
OnRename(wxCommandEvent &)300 void CFilterDialog::OnRename(wxCommandEvent&)
301 {
302 	wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
303 	int old_pos = pChoice->GetSelection();
304 	if (old_pos == -1) {
305 		return;
306 	}
307 
308 	if (!old_pos) {
309 		wxMessageBoxEx(_("This filter set cannot be renamed."));
310 		return;
311 	}
312 
313 	CInputDialog dlg;
314 
315 	wxString msg = wxString::Format(_("Please enter a new name for the filter set \"%s\""), pChoice->GetStringSelection());
316 
317 	dlg.Create(this, _("Enter new name for filterset"), msg, 255);
318 	if (dlg.ShowModal() != wxID_OK) {
319 		return;
320 	}
321 
322 	std::wstring name = dlg.GetValue().ToStdWstring();
323 
324 	if (name == pChoice->GetStringSelection()) {
325 		// Nothing changed
326 		return;
327 	}
328 
329 	if (name.empty()) {
330 		wxMessageBoxEx(_("No name for the filterset given."), _("Cannot save filterset"), wxICON_INFORMATION);
331 		return;
332 	}
333 
334 	int pos = pChoice->FindString(name);
335 	if (pos != wxNOT_FOUND) {
336 		if (wxMessageBoxEx(_("Given filterset name already exists, overwrite filter set?"), _("Filter set already exists"), wxICON_QUESTION | wxYES_NO) != wxYES) {
337 			return;
338 		}
339 	}
340 
341 	// Remove old entry
342 	pChoice->Delete(old_pos);
343 	CFilterSet set = m_filterSets[old_pos];
344 	m_filterSets.erase(m_filterSets.begin() + old_pos);
345 
346 	pos = pChoice->FindString(name);
347 	if (pos == wxNOT_FOUND) {
348 		pos = m_filterSets.size();
349 		m_filterSets.push_back(set);
350 		pChoice->Append(name);
351 	}
352 	else {
353 		m_filterSets[pos] = set;
354 	}
355 
356 	m_filterSets[pos].name = name;
357 
358 	pChoice->SetSelection(pos);
359 	m_currentFilterSet = pos;
360 
361 	GetSizer()->Fit(this);
362 }
363 
OnDeleteSet(wxCommandEvent &)364 void CFilterDialog::OnDeleteSet(wxCommandEvent&)
365 {
366 	wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
367 	int pos = pChoice->GetSelection();
368 	if (pos < 0) {
369 		return;
370 	}
371 
372 	if (!pos || static_cast<size_t>(pos) >= m_filterSets.size()) {
373 		wxMessageBoxEx(_("This filter set cannot be removed."));
374 		return;
375 	}
376 
377 	m_filterSets[0] = m_filterSets[pos];
378 
379 	pChoice->Delete(pos);
380 	m_filterSets.erase(m_filterSets.begin() + pos);
381 
382 	pChoice->SetSelection(0);
383 	m_currentFilterSet = 0;
384 
385 	SetCtrlState();
386 }
387 
OnSetSelect(wxCommandEvent & event)388 void CFilterDialog::OnSetSelect(wxCommandEvent& event)
389 {
390 	m_currentFilterSet = event.GetSelection();
391 	DisplayFilters();
392 	SetCtrlState();
393 }
394 
OnChangeAll(wxCommandEvent & event)395 void CFilterDialog::OnChangeAll(wxCommandEvent& event)
396 {
397 	bool check = true;
398 	if (event.GetId() == XRCID("ID_LOCAL_DISABLEALL") || event.GetId() == XRCID("ID_REMOTE_DISABLEALL")) {
399 		check = false;
400 	}
401 
402 	bool local;
403 	std::vector<unsigned char>* pValues;
404 	wxCheckListBox* pListBox;
405 	if (event.GetId() == XRCID("ID_LOCAL_ENABLEALL") || event.GetId() == XRCID("ID_LOCAL_DISABLEALL")) {
406 		pListBox = XRCCTRL(*this, "ID_LOCALFILTERS", wxCheckListBox);
407 		pValues = &m_filterSets[0].local;
408 		local = true;
409 	}
410 	else {
411 		pListBox = XRCCTRL(*this, "ID_REMOTEFILTERS", wxCheckListBox);
412 		pValues = &m_filterSets[0].remote;
413 		local = false;
414 	}
415 
416 	if (m_currentFilterSet) {
417 		m_filterSets[0] = m_filterSets[m_currentFilterSet];
418 		m_currentFilterSet = 0;
419 		wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
420 		pChoice->SetSelection(0);
421 	}
422 
423 	for (size_t i = 0; i < pListBox->GetCount(); ++i) {
424 		if (!local && (m_filters[i].IsLocalFilter())) {
425 			pListBox->Check(i, false);
426 			(*pValues)[i] = false;
427 		}
428 		else {
429 			pListBox->Check(i, check);
430 			(*pValues)[i] = check;
431 		}
432 	}
433 }
434 
SetCtrlState()435 void CFilterDialog::SetCtrlState()
436 {
437 	wxChoice* pChoice = XRCCTRL(*this, "ID_SETS", wxChoice);
438 
439 	int sel = pChoice->GetSelection();
440 	XRCCTRL(*this, "ID_RENAMESET", wxButton)->Enable(sel > 0);
441 	XRCCTRL(*this, "ID_DELETESET", wxButton)->Enable(sel > 0);
442 }
443 
CFilterManager()444 CFilterManager::CFilterManager()
445 {
446 	LoadFilters();
447 }
448 
HasActiveFilters(bool ignore_disabled)449 bool CFilterManager::HasActiveFilters(bool ignore_disabled)
450 {
451 	if (!m_loaded) {
452 		LoadFilters();
453 	}
454 
455 	if (global_filters_.filter_sets.empty()) {
456 		return false;
457 	}
458 
459 	if (m_filters_disabled && !ignore_disabled) {
460 		return false;
461 	}
462 
463 	const CFilterSet& set = global_filters_.filter_sets[global_filters_.current_filter_set];
464 	for (unsigned int i = 0; i < global_filters_.filters.size(); ++i) {
465 		if (set.local[i]) {
466 			return true;
467 		}
468 
469 		if (set.remote[i]) {
470 			return true;
471 		}
472 	}
473 
474 	return false;
475 }
476 
HasSameLocalAndRemoteFilters() const477 bool CFilterManager::HasSameLocalAndRemoteFilters() const
478 {
479 	CFilterSet const& set = global_filters_.filter_sets[global_filters_.current_filter_set];
480 	return set.local == set.remote;
481 
482 	return true;
483 }
484 
FilenameFiltered(std::wstring const & name,std::wstring const & path,bool dir,int64_t size,bool local,int attributes,fz::datetime const & date) const485 bool CFilterManager::FilenameFiltered(std::wstring const& name, std::wstring const& path, bool dir, int64_t size, bool local, int attributes, fz::datetime const& date) const
486 {
487 	if (m_filters_disabled) {
488 		return false;
489 	}
490 
491 	CFilterSet const& set = global_filters_.filter_sets[global_filters_.current_filter_set];
492 	auto const& active = local ? set.local : set.remote;
493 
494 	// Check active filters
495 	for (unsigned int i = 0; i < global_filters_.filters.size(); ++i) {
496 		if (active[i]) {
497 			if (FilenameFilteredByFilter(global_filters_.filters[i], name, path, dir, size, attributes, date)) {
498 				return true;
499 			}
500 		}
501 	}
502 
503 	return false;
504 }
505 
LoadFilters()506 void CFilterManager::LoadFilters()
507 {
508 	if (m_loaded) {
509 		return;
510 	}
511 
512 	m_loaded = true;
513 
514 	CReentrantInterProcessMutexLocker mutex(MUTEX_FILTERS);
515 
516 	std::wstring file(wxGetApp().GetSettingsFile(L"filters"));
517 	if (fz::local_filesys::get_size(fz::to_native(file)) < 1) {
518 		file = wxGetApp().GetResourceDir().GetPath() + L"defaultfilters.xml";
519 	}
520 
521 	CXmlFile xml(file);
522 	auto element = xml.Load();
523 	load_filters(element, global_filters_);
524 
525 	if (!element) {
526 		wxString msg = xml.GetError() + _T("\n\n") + _("Any changes made to the filters will not be saved.");
527 		wxMessageBoxEx(msg, _("Error loading xml file"), wxICON_ERROR);
528 	}
529 }
530 
Import(pugi::xml_node & element)531 void CFilterManager::Import(pugi::xml_node& element)
532 {
533 	if (!element) {
534 		return;
535 	}
536 
537 	global_filters_.filters.clear();
538 	global_filters_.filter_sets.clear();
539 	global_filters_.current_filter_set = 0;
540 	m_filters_disabled = false;
541 
542 	CReentrantInterProcessMutexLocker mutex(MUTEX_FILTERS);
543 
544 	LoadFilters(element);
545 	SaveFilters();
546 
547 	CContextManager::Get()->NotifyAllHandlers(STATECHANGE_APPLYFILTER);
548 }
549 
LoadFilters(pugi::xml_node & element)550 void CFilterManager::LoadFilters(pugi::xml_node& element)
551 {
552 	load_filters(element, global_filters_);
553 	if (global_filters_.filter_sets.empty()) {
554 		CFilterSet set;
555 		set.local.resize(global_filters_.filters.size(), false);
556 		set.remote.resize(global_filters_.filters.size(), false);
557 
558 		global_filters_.filter_sets.push_back(set);
559 	}
560 }
561 
SaveFilters()562 void CFilterManager::SaveFilters()
563 {
564 	CReentrantInterProcessMutexLocker mutex(MUTEX_FILTERS);
565 
566 	CXmlFile xml(wxGetApp().GetSettingsFile(_T("filters")));
567 	auto element = xml.Load();
568 	if (!element) {
569 		wxString msg = xml.GetError() + _T("\n\n") + _("Any changes made to the filters could not be saved.");
570 		wxMessageBoxEx(msg, _("Error loading xml file"), wxICON_ERROR);
571 
572 		return;
573 	}
574 
575 	save_filters(element, global_filters_);
576 
577 	SaveWithErrorDialog(xml);
578 }
579 
ToggleFilters()580 void CFilterManager::ToggleFilters()
581 {
582 	if (m_filters_disabled) {
583 		m_filters_disabled = false;
584 		return;
585 	}
586 
587 	if (HasActiveFilters(true)) {
588 		m_filters_disabled = true;
589 	}
590 }
591 
HasActiveLocalFilters() const592 bool CFilterManager::HasActiveLocalFilters() const
593 {
594 	if (!m_filters_disabled) {
595 		CFilterSet const& set = global_filters_.filter_sets[global_filters_.current_filter_set];
596 		// Check active filters
597 		for (unsigned int i = 0; i < global_filters_.filters.size(); ++i) {
598 			if (set.local[i]) {
599 				return true;
600 			}
601 		}
602 	}
603 
604 	return false;
605 }
606 
HasActiveRemoteFilters() const607 bool CFilterManager::HasActiveRemoteFilters() const
608 {
609 	if (!m_filters_disabled) {
610 		CFilterSet const& set = global_filters_.filter_sets[global_filters_.current_filter_set];
611 		// Check active filters
612 		for (unsigned int i = 0; i < global_filters_.filters.size(); ++i) {
613 			if (set.remote[i]) {
614 				return true;
615 			}
616 		}
617 	}
618 
619 	return false;
620 }
621 
GetActiveFilters()622 ActiveFilters CFilterManager::GetActiveFilters()
623 {
624 	ActiveFilters filters;
625 
626 	if (m_filters_disabled) {
627 		return filters;
628 	}
629 
630 	const CFilterSet& set = global_filters_.filter_sets[global_filters_.current_filter_set];
631 
632 	// Check active filters
633 	for (unsigned int i = 0; i < global_filters_.filters.size(); ++i) {
634 		if (set.local[i]) {
635 			filters.first.push_back(global_filters_.filters[i]);
636 		}
637 		if (set.remote[i]) {
638 			filters.second.push_back(global_filters_.filters[i]);
639 		}
640 	}
641 
642 	return filters;
643 }
644