1 /*
2
3 Firewall Builder
4
5 Copyright (C) 2008 NetCitadel, LLC
6
7 Author: alek@codeminders.com
8 refactoring and bugfixes: vadim@fwbuilder.org
9
10
11 Copyright (C) 2013 UNINETT AS
12
13 Author: Sirius Bakke <sirius.bakke@uninett.no>
14
15 $Id$
16
17 This program is free software which we release under the GNU General Public
18 License. You may redistribute and/or modify this program under the terms
19 of that license as published by the Free Software Foundation; either
20 version 2 of the License, or (at your option) any later version.
21
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 To get a copy of the GNU General Public License, write to the Free Software
28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
30 */
31
32 #include "config.h"
33 #include "global.h"
34 #include "utils.h"
35
36 #include <fwbuilder/Cluster.h>
37 #include <fwbuilder/Firewall.h>
38 #include <fwbuilder/RuleSet.h>
39 #include <fwbuilder/Policy.h>
40 #include <fwbuilder/NAT.h>
41 #include <fwbuilder/Routing.h>
42 #include "fwbuilder/RuleSet.h"
43 #include "fwbuilder/Rule.h"
44 #include "fwbuilder/RuleElement.h"
45
46 #include "FWBSettings.h"
47 #include "FWBTree.h"
48 #include "FWObjectPropertiesFactory.h"
49 #include "FWWindow.h"
50 #include "ProjectPanel.h"
51 #include "RCS.h"
52 #include "RuleSetView.h"
53 #include "findDialog.h"
54 #include "events.h"
55 #include "ObjectTreeView.h"
56 #include "FWObjectClipboard.h"
57 #include "WorkflowIcons.h"
58 #include "FirewallCodeViewer.h"
59
60 #include "RuleSetDiffDialog.h"
61 #include "temporarydir.h"
62
63 #include <QtDebug>
64 #include <QMdiSubWindow>
65 #include <QMdiArea>
66 #include <QTimer>
67 #include <QStatusBar>
68 #include <QFileInfo>
69 #include <QApplication>
70 #include <QUndoStack>
71 #include <QUndoGroup>
72 #include <QScrollBar>
73 #include <QMessageBox>
74
75 #include <iostream>
76
77
78 using namespace Ui;
79 using namespace libfwbuilder;
80 using namespace std;
81
82
83
initMain(FWWindow * main)84 void ProjectPanel::initMain(FWWindow *main)
85 {
86 mainW = main;
87 mdiWindow = NULL;
88 treeReloadPending = false;
89
90 // mdiWindow changes state several times right after it is opened,
91 // but we call saveState to store splitter position and its geometry
92 // when state changes. Flag "ready" is false after ProjectPanel is created
93 // and until FWWindow decides that ProjectPanel is ready for operation.
94 // Do not load or save state if flag ready is false.
95 ready = false;
96
97 int total_width = DEFAULT_H_SPLITTER_POSITION;
98 //int total_height = DEFAULT_V_SPLITTER_POSITION; //UNUSED
99
100 if (mainW)
101 {
102 total_width = mainW->width();
103 //total_height = mainW->height(); //UNUSED
104 }
105
106 setMainSplitterPosition(DEFAULT_H_SPLITTER_POSITION,
107 total_width - DEFAULT_H_SPLITTER_POSITION);
108
109 loading_state = false;
110 oldState=-1;
111
112 main->undoGroup->addStack(undoStack);
113
114 fd = new findDialog(this, this);
115 fd->hide();
116
117 m_panel->icons->setUpSignals(this);
118
119 }
120
reset()121 void ProjectPanel::reset()
122 {
123 undoStack->clear();
124 delete rcs;
125 rcs = NULL;
126 firewalls.clear();
127 visibleFirewall = NULL;
128 visibleRuleSet = NULL;
129 clearFirewallTabs();
130 clearObjects();
131 FWObjectClipboard::obj_clipboard->clear();
132 }
133
ProjectPanel(QWidget * parent)134 ProjectPanel::ProjectPanel(QWidget *parent):
135 QWidget(parent), // , Qt::WindowSystemMenuHint|Qt::Window),
136 mainW(0),
137 rcs(0),
138 systemFile(true),
139 safeMode(false),
140 editingStandardLib(false),
141 editingTemplateLib(false),
142 ruleSetRedrawPending(false),
143 objdb(0),
144 origObjdb(0),
145 fd(0),
146 autosaveTimer(new QTimer(static_cast<QObject*>(this))), ruleSetTabIndex(0),
147 visibleFirewall(0),
148 visibleRuleSet(0),
149 lastFirewallIdx(-2),
150 changingTabs(false),
151 noFirewalls(tr("No firewalls defined")),
152 m_panel(0),
153 undoStack(0)
154 {
155 if (fwbdebug) qDebug("ProjectPanel constructor");
156 m_panel = new Ui::ProjectPanel_q();
157 m_panel->setupUi(this);
158 m_panel->om->setupProject(this);
159
160 m_panel->toolbar->hide();
161
162 undoStack = new QUndoStack(this);
163
164 setWindowTitle(getPageTitle());
165
166 if (fwbdebug) qDebug("New ProjectPanel %p", this);
167
168 connect(m_panel->topSplitter, SIGNAL(splitterMoved(int,int)),
169 this, SLOT(splitterPositionChanged(int,int)));
170
171 m_diffLog = QHash<int, int>();
172 m_renamedGroups = QHash<QString, QString>();
173 m_statistics = QHash<QPair<int, DiffType::Type>, int>();
174 }
175
~ProjectPanel()176 ProjectPanel::~ProjectPanel()
177 {
178 if (fwbdebug) qDebug() << "ProjectPanel::~ProjectPanel()";
179
180 undoStack->clear();
181 if (rcs) delete rcs;
182 if (objdb) delete objdb;
183 if (origObjdb) delete origObjdb;
184 delete m_panel;
185
186 if (fwbdebug) qDebug() << "ProjectPanel::~ProjectPanel() done";
187 }
188
getPageTitle(bool file_path)189 QString ProjectPanel::getPageTitle(bool file_path)
190 {
191 QString default_caption = tr("Untitled");
192 if (rcs)
193 {
194 QString caption;
195 if (file_path) caption = rcs->getFileName(); // full path
196 else
197 {
198 QFileInfo fi(rcs->getFileName());
199 caption = fi.fileName();
200 }
201 if (rcs->isInRCS()) caption= caption + ", rev " + rcs->getSelectedRev();
202 if (rcs->isRO()) caption = caption + " " + tr("(read-only)");
203 if (caption.isEmpty()) return default_caption;
204 return caption;
205 }
206 else return default_caption;
207 }
208
restoreRuleSetTab()209 void ProjectPanel::restoreRuleSetTab()
210 {
211 if (fwbdebug) qDebug("ProjectPanel::()");
212 m_panel->ruleSets->setCurrentIndex(ruleSetTabIndex);
213 m_panel->toolbar->show();
214 }
215
loadObjects()216 void ProjectPanel::loadObjects()
217 {
218 m_panel->om->loadObjects();
219 }
220
loadObjects(FWObjectDatabase *)221 void ProjectPanel::loadObjects(FWObjectDatabase*)
222 {
223 m_panel->om->loadObjects();
224 }
225
clearObjects()226 void ProjectPanel::clearObjects()
227 {
228 m_panel->om->clearObjects();
229 }
230
getTemporaryDirPath() const231 const QString ProjectPanel::getTemporaryDirPath() const
232 {
233 if (mainW->getTemporaryDirPath() != QString()) {
234 if (!rcs->getFileName().isEmpty()) {
235 QFileInfo fi(rcs->getFileName());
236 return QString(mainW->getTemporaryDirPath())
237 .append("/").append(fi.baseName());
238 }
239 return mainW->getTemporaryDirPath();
240 }
241 return QString();
242 }
243
clearFirewallTabs()244 void ProjectPanel::clearFirewallTabs()
245 {
246 if (fwbdebug) qDebug() << "ProjectPanel::clearFirewallTabs";
247
248 m_panel->ruleSets->hide();
249
250 while (m_panel->ruleSets->count()!=0)
251 {
252 QWidget *p = m_panel->ruleSets->widget(0);
253 m_panel->ruleSets->removeWidget(
254 m_panel->ruleSets->widget(m_panel->ruleSets->indexOf(p)));
255 delete p;
256 }
257 m_panel->rulesetname->setText("");
258 m_panel->ruleSets->show();
259 ruleSetViews.clear();
260 }
261
closeRuleSetPanel()262 void ProjectPanel::closeRuleSetPanel()
263 {
264 if (fwbdebug) qDebug() << "ProjectPanel::closeRuleSetPanel";
265 clearFirewallTabs();
266 visibleRuleSet = NULL;
267 }
268
ensureObjectVisibleInRules(FWReference * obj)269 void ProjectPanel::ensureObjectVisibleInRules(FWReference *obj)
270 {
271 if (fwbdebug) qDebug() << "ProjectPanel::ensureObjectVisibleInRules";
272 FWObject *p=obj;
273 while (p && RuleSet::cast(p)==NULL ) p=p->getParent();
274 if (p==NULL) return; // something is broken
275 // p is a pointer to RuleSet object @obj belongs to
276 if (p != getCurrentRuleSet()) openRuleSet(p);
277 getCurrentRuleSetView()->setFocus();
278 getCurrentRuleSetView()->selectRE( obj );
279 }
280
getCurrentRuleSetView()281 RuleSetView * ProjectPanel::getCurrentRuleSetView()
282 {
283 return dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
284 }
285
286
reopenFirewall()287 void ProjectPanel::reopenFirewall()
288 {
289 if (fwbdebug) qDebug("ProjectPanel::reopenFirewall()");
290
291 time_t last_modified = db()->getTimeLastModified();
292 if (fwbdebug)
293 qDebug("ProjectPanel::reopenFirewall(): checkpoint 1: "
294 "dirty=%d last_modified=%s",
295 db()->isDirty(), ctime(&last_modified));
296
297 if (ruleSetRedrawPending) return;
298
299 int currentPage = m_panel->ruleSets->currentIndex();
300
301 SelectionMemento memento;
302
303 RuleSetView* rv = dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
304 if (rv) rv->saveCurrentRowColumn(memento);
305
306 last_modified = db()->getTimeLastModified();
307 if (fwbdebug)
308 qDebug("ProjectPanel::reopenFirewall(): checkpoint 2: "
309 "dirty=%d last_modified=%s",
310 db()->isDirty(), ctime(&last_modified));
311
312 // since reopenFirewall deletes and recreates all RuleSetView
313 // widgets, it causes significant amount of repaint and
314 // flicker. Disable updates for the duration of operation to avoid
315 // that.
316 m_panel->ruleSets->setUpdatesEnabled(false);
317
318 changingTabs = true;
319
320 clearFirewallTabs();
321
322 last_modified = db()->getTimeLastModified();
323 if (fwbdebug)
324 qDebug("ProjectPanel::reopenFirewall(): checkpoint 3: "
325 "dirty=%d last_modified=%s",
326 db()->isDirty(), ctime(&last_modified));
327
328 if (visibleRuleSet==NULL) return ;
329
330 for (int i =0 ; i < m_panel->ruleSets->count (); i++)
331 m_panel->ruleSets->removeWidget(m_panel->ruleSets->widget(i));
332
333 m_panel->rulesetname->setTextFormat(Qt::RichText);
334 updateFirewallName();
335
336 last_modified = db()->getTimeLastModified();
337 if (fwbdebug)
338 qDebug("ProjectPanel::reopenFirewall(): checkpoint 4: "
339 "dirty=%d last_modified=%s",
340 db()->isDirty(), ctime(&last_modified));
341
342 RuleSetView* rulesetview =
343 RuleSetView::getRuleSetViewByType(this, visibleRuleSet, NULL);
344 if (rulesetview)
345 {
346 m_panel->ruleSets->addWidget(rulesetview);
347
348 last_modified = db()->getTimeLastModified();
349 if (fwbdebug)
350 qDebug("ProjectPanel::reopenFirewall(): checkpoint 5: "
351 "dirty=%d last_modified=%s",
352 db()->isDirty(), ctime(&last_modified));
353
354 m_panel->ruleSets->setCurrentIndex(currentPage);
355 m_panel->toolbar->show();
356 rv = dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
357 rv->restoreCurrentRowColumn(memento);
358
359 changingTabs = false;
360
361 mainW->updateGlobalToolbar();
362
363 m_panel->ruleSets->setUpdatesEnabled(true);
364 m_panel->ruleSets->show();
365 }
366 }
367
findFirewallInList(FWObject * f)368 int ProjectPanel::findFirewallInList(FWObject *f)
369 {
370 vector<FWObject*>::iterator i;
371 int n=0;
372 for (i=firewalls.begin(); i!=firewalls.end(); i++,n++)
373 {
374 if ( (*i)->getId()==f->getId() ) return n;
375 }
376 return -1;
377 }
378
updateFirewallName()379 void ProjectPanel::updateFirewallName()
380 {
381 if (visibleRuleSet==NULL) return ;
382 QString name;
383 // mw->buildEditorTitleAndIcon(visibleRuleSet, ObjectEditor::optNone,
384 // &name, NULL, false);
385 // name = "<b>" + name + "</b>";
386 FWObject *fw = visibleRuleSet->getParent();
387 name = QString("%1 / %2")
388 .arg(QString::fromUtf8(fw->getName().c_str()))
389 .arg(QString::fromUtf8(visibleRuleSet->getName().c_str()));
390 m_panel->rulesetname->setText(name );
391 }
392
openRuleSet(FWObject * obj,bool immediately)393 void ProjectPanel::openRuleSet(FWObject * obj, bool immediately)
394 {
395 //mw->blankEditor();
396 visibleRuleSet = RuleSet::cast(obj);
397 if (immediately) redrawRuleSets();
398 else registerRuleSetRedrawRequest();
399 }
400
selectRules()401 void ProjectPanel::selectRules()
402 {
403 // `unselect();
404 RuleSetView* rv = dynamic_cast<RuleSetView*>(
405 m_panel->ruleSets->currentWidget());
406 if (rv) rv->setFocus();
407 }
408
unselectRules()409 void ProjectPanel::unselectRules()
410 {
411 bool havePolicies = (m_panel->ruleSets->count()!=0);
412
413 /* commented this out so that when I hit "Edit" in the object's pop-down
414 * menu in a rule, ruleset wont lose focus when object editor is opened.
415 * If rule set loses focus, the object's background turns from "selected" color
416 * to white and user loses context (which object is shown in the object editor)
417 */
418 if (havePolicies)
419 {
420 RuleSetView* rv=dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
421
422 if (rv && rv->getSelectedObject()!=getSelectedObject())
423 {
424 rv->clearFocus();
425 }
426 }
427 mainW->disableActions(havePolicies);
428 }
429
editCopy()430 void ProjectPanel::editCopy()
431 {
432 if (fwbdebug)
433 qDebug() << "ProjectPanel::editCopy() isManipulatorSelected()="
434 << isManipulatorSelected();
435
436 if (isManipulatorSelected()) copyObj();
437 else
438 {
439 if (m_panel->ruleSets->count()!=0)
440 {
441 RuleSetView *rsv = dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
442 if (rsv)
443 rsv->copySelectedObject();
444 }
445 }
446 }
447
editCut()448 void ProjectPanel::editCut()
449 {
450 if (fwbdebug)
451 qDebug() << "ProjectPanel::editCut() isManipulatorSelected()="
452 << isManipulatorSelected();
453
454 if (isManipulatorSelected()) cutObj();
455 else
456 {
457 if (m_panel->ruleSets->count()!=0)
458 {
459 RuleSetView *rsv = dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
460 if (rsv)
461 rsv->cutSelectedObject();
462 }
463 }
464 }
465
editDelete()466 void ProjectPanel::editDelete()
467 {
468 if (fwbdebug)
469 qDebug() << "ProjectPanel::editDelete() isManipulatorSelected()="
470 << isManipulatorSelected();
471
472 if (isManipulatorSelected()) deleteObj();
473 }
474
editPaste()475 void ProjectPanel::editPaste()
476 {
477 if (fwbdebug)
478 qDebug() << "ProjectPanel::editPaste() isManipulatorSelected()="
479 << isManipulatorSelected();
480
481 if (isManipulatorSelected()) pasteObj();
482 else
483 {
484 if (m_panel->ruleSets->count()!=0)
485 {
486 RuleSetView *rsv = dynamic_cast<RuleSetView*>(m_panel->ruleSets->currentWidget());
487 if (rsv)
488 rsv->pasteObject();
489 }
490 }
491 }
492
setFileName(const QString & fname)493 void ProjectPanel::setFileName(const QString &fname)
494 {
495 systemFile = false;
496 rcs->setFileName(fname);
497 db()->setFileName(fname.toLatin1().constData());
498
499 //setWindowTitle(getPageTitle());
500 QCoreApplication::postEvent(mw, new updateSubWindowTitlesEvent());
501 }
502
503 //wrapers for some ObjectManipulator functions
504
getCurrentLib()505 FWObject* ProjectPanel::getCurrentLib()
506 {
507 return m_panel->om->getCurrentLib();
508 }
509
updateObjectInTree(FWObject * obj,bool subtree)510 void ProjectPanel::updateObjectInTree(FWObject *obj, bool subtree)
511 {
512 m_panel->om->updateObjectInTree(obj, subtree);
513 }
514
createObject(const QString & objType,const QString & objName,FWObject * copyFrom)515 FWObject* ProjectPanel::createObject(const QString &objType,
516 const QString &objName,
517 FWObject *copyFrom)
518 {
519 return m_panel->om->createObject(objType, objName, copyFrom);
520 }
521
createObject(FWObject * parent,const QString & objType,const QString & objName,FWObject * copyFrom)522 FWObject* ProjectPanel::createObject(FWObject *parent,
523 const QString &objType,
524 const QString &objName,
525 FWObject *copyFrom)
526 {
527 return m_panel->om->createObject(parent, objType, objName, copyFrom);
528 }
529
moveObject(FWObject * target,FWObject * obj)530 void ProjectPanel::moveObject(FWObject *target,
531 FWObject *obj)
532 {
533 m_panel->om->moveObject(target, obj);
534 }
535
moveObject(const QString & targetLibName,FWObject * obj)536 void ProjectPanel::moveObject(const QString &targetLibName,
537 FWObject *obj)
538 {
539 m_panel->om->moveObject(targetLibName, obj);
540 }
541
pasteTo(FWObject * target,FWObject * obj)542 FWObject* ProjectPanel::pasteTo(FWObject *target, FWObject *obj)
543 {
544 return m_panel->om->pasteTo(target, obj);
545 }
546
getCurrentObjectTree()547 ObjectTreeView* ProjectPanel::getCurrentObjectTree()
548 {
549 return m_panel->om->getCurrentObjectTree();
550 }
551
findAllFirewalls(std::list<Firewall * > & fws)552 void ProjectPanel::findAllFirewalls (std::list<Firewall *> &fws)
553 {
554 m_panel->om->findAllFirewalls(fws);
555 }
556
showDeletedObjects(bool f)557 void ProjectPanel::showDeletedObjects(bool f)
558 {
559 m_panel->om->showDeletedObjects(f);
560 }
561
select()562 void ProjectPanel::select()
563 {
564 m_panel->om->select();
565 }
566
unselect()567 void ProjectPanel::unselect()
568 {
569 m_panel->om->unselect();
570 }
571
clearManipulatorFocus()572 void ProjectPanel::clearManipulatorFocus()
573 {
574 m_panel->om->clearFocus();
575 }
576
copyObj()577 void ProjectPanel::copyObj()
578 {
579 m_panel->om->copyObj();
580 }
581
isManipulatorSelected()582 bool ProjectPanel::isManipulatorSelected()
583 {
584 return m_panel->om->getCurrentObjectTree()->hasFocus();
585 }
586
cutObj()587 void ProjectPanel::cutObj()
588 {
589 m_panel->om->cutObj();
590 }
591
pasteObj()592 void ProjectPanel::pasteObj()
593 {
594 m_panel->om->pasteObj();
595 }
596
597
newObject()598 void ProjectPanel::newObject()
599 {
600 m_panel->om->newObject();
601 }
602
deleteObj()603 void ProjectPanel::deleteObj()
604 {
605 m_panel->om->delObj();
606 }
607
getSelectedObject()608 FWObject* ProjectPanel::getSelectedObject()
609 {
610 return m_panel->om->getSelectedObject();
611 }
612
reopenCurrentItemParent()613 void ProjectPanel::reopenCurrentItemParent()
614 {
615 m_panel->om->reopenCurrentItemParent();
616 }
617
lockObject()618 void ProjectPanel::lockObject()
619 {
620 m_panel->om->lockObject();
621 }
622
unlockObject()623 void ProjectPanel::unlockObject()
624 {
625 m_panel->om->unlockObject();
626 }
627
setFDObject(FWObject * o)628 void ProjectPanel::setFDObject(FWObject *o)
629 {
630 fd->setObject(o);
631 fd->show();
632 }
resetFD()633 void ProjectPanel::resetFD()
634 {
635 fd->reset();
636 }
637
insertRule()638 void ProjectPanel::insertRule()
639 {
640 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
641 getCurrentRuleSetView()->insertRule();
642 }
643
addRuleAfterCurrent()644 void ProjectPanel::addRuleAfterCurrent()
645 {
646 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
647 getCurrentRuleSetView()->addRuleAfterCurrent();
648 }
649
removeRule()650 void ProjectPanel::removeRule()
651 {
652 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
653 getCurrentRuleSetView()->removeRule();
654 }
655
moveRule()656 void ProjectPanel::moveRule()
657 {
658 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
659 getCurrentRuleSetView()->moveRule();
660 }
661
moveRuleUp()662 void ProjectPanel::moveRuleUp()
663 {
664 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
665 getCurrentRuleSetView()->moveRuleUp();
666 }
667
moveRuleDown()668 void ProjectPanel::moveRuleDown()
669 {
670 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
671 getCurrentRuleSetView()->moveRuleDown();
672 }
673
copyRule()674 void ProjectPanel::copyRule()
675 {
676 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
677 getCurrentRuleSetView()->copyRule();
678 }
679
cutRule()680 void ProjectPanel::cutRule()
681 {
682 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
683 getCurrentRuleSetView()->cutRule();
684 }
685
pasteRuleAbove()686 void ProjectPanel::pasteRuleAbove()
687 {
688 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
689 getCurrentRuleSetView()->pasteRuleAbove();
690 }
691
pasteRuleBelow()692 void ProjectPanel::pasteRuleBelow()
693 {
694 if (visibleRuleSet==NULL || m_panel->ruleSets->count()==0) return;
695 getCurrentRuleSetView()->pasteRuleBelow();
696 }
697
editingLibrary()698 bool ProjectPanel::editingLibrary()
699 {
700 return (rcs!=NULL &&
701 ( rcs->getFileName().endsWith(".fwl")) );
702 }
703
createRCS(const QString & filename)704 void ProjectPanel::createRCS(const QString &filename)
705 {
706 rcs = new RCS(filename);
707 systemFile = true;
708 }
709
getRCS()710 RCS * ProjectPanel::getRCS()
711 {
712 return rcs;
713 }
714
715 /*
716 * This slot is connected to the "add rule" button in the mini-toolbar
717 * at the top of the rule set view
718 */
addRule()719 void ProjectPanel::addRule()
720 {
721 if (visibleRuleSet==NULL || getCurrentRuleSetView()==NULL) return ;
722 getCurrentRuleSetView()->insertRule();
723 }
724
725 /*
726 * This slot is connected to the "diff rule" button in the mini-toolbar
727 * at the top of the rule set view
728 */
diffThis()729 void ProjectPanel::diffThis()
730 {
731 RuleSetDiffDialog rdd(this);
732 rdd.exec();
733 }
734
compileThis()735 void ProjectPanel::compileThis()
736 {
737 if (visibleRuleSet==NULL) return ;
738
739 save();
740 // see comment in FWWindow::compile()
741 if (db()->isDirty()) return;
742
743 set<Firewall*> fw;
744 Firewall *f = Firewall::cast(visibleRuleSet->getParent());
745 if (f)
746 {
747 fw.insert(f);
748 mainW->compile(fw);
749 }
750 }
751
installThis()752 void ProjectPanel::installThis()
753 {
754 if (visibleRuleSet==NULL) return ;
755
756 save();
757 // see comment in FWWindow::compile()
758 if (db()->isDirty()) return;
759
760 set<Firewall*> fw;
761 Firewall *f = Firewall::cast(visibleRuleSet->getParent());
762 if (f)
763 {
764 fw.insert(f);
765 mainW->install(fw);
766 }
767 }
768
inspectThis()769 void ProjectPanel::inspectThis()
770 {
771 if (visibleRuleSet==NULL) return;
772
773 save();
774 // see comment in FWWindow::compile()
775 if (db()->isDirty()) return;
776
777 Firewall *f = Firewall::cast(visibleRuleSet->getParent());
778 set<Firewall*> fwlist;
779 if (Cluster::isA(f))
780 {
781 std::list<Firewall*> cfws;
782 Cluster::cast(f)->getMembersList(cfws);
783 foreach(Firewall *fw, cfws)
784 fwlist.insert(fw);
785 }
786 else
787 {
788 fwlist.insert(f);
789 }
790
791 this->inspect(fwlist);
792 }
793
inspectAll()794 void ProjectPanel::inspectAll()
795 {
796 ObjectManipulator *om = this->findChild<ObjectManipulator*>();
797 list<Firewall*> fws;
798 om->findAllFirewalls(fws);
799 set<Firewall*> fwset;
800 foreach(Firewall *fw, fws)
801 {
802 if (Cluster::isA(fw))
803 {
804 std::list<Firewall*> cfws;
805 Cluster::cast(fw)->getMembersList(cfws);
806 foreach(Firewall *f, cfws)
807 fwset.insert(f);
808 }
809 else
810 {
811 fwset.insert(fw);
812 }
813 }
814
815 this->inspect(fwset);
816 }
817
compile()818 void ProjectPanel::compile()
819 {
820 if (mw->isEditorVisible() &&
821 !mw->requestEditorOwnership(NULL,NULL,ObjectEditor::optNone,true))
822 return;
823
824 save();
825 // see comment in FWWindow::compile()
826 if (db()->isDirty()) return;
827
828 //fileSave();
829 mainW->compile();
830 }
831
compile(set<Firewall * > vf)832 void ProjectPanel::compile(set<Firewall*> vf)
833 {
834 if (mw->isEditorVisible() &&
835 !mw->requestEditorOwnership(NULL, NULL, ObjectEditor::optNone, true))
836 return;
837
838 save();
839 // see comment in FWWindow::compile()
840 if (db()->isDirty()) return;
841
842 //fileSave();
843 mainW->compile(vf);
844 }
845
install(set<Firewall * > vf)846 void ProjectPanel::install(set<Firewall*> vf)
847 {
848 save();
849 // see comment in FWWindow::compile()
850 if (db()->isDirty()) return;
851
852 mainW->install(vf);
853 }
854
install()855 void ProjectPanel::install()
856 {
857 save();
858 // see comment in FWWindow::compile()
859 if (db()->isDirty()) return;
860
861 mainW->install();
862 }
863
864
inspect(set<Firewall * > fws)865 void ProjectPanel::inspect(set<Firewall *> fws)
866 {
867 if (fws.empty())
868 return;
869
870 QMessageBox messageBox(this);
871 messageBox.addButton(tr("Cancel"), QMessageBox::RejectRole);
872 messageBox.addButton(tr("Compile and Inspect files"), QMessageBox::AcceptRole);
873 messageBox.setIcon(QMessageBox::Critical);
874
875 set<Firewall*> needCompile;
876 foreach(Firewall *fw, fws)
877 if (fw->needsCompile())
878 needCompile.insert(fw);
879
880 if (!needCompile.empty())
881 {
882 QString text;
883 QStringList names;
884 foreach(Firewall *fw, needCompile)
885 names.append(fw->getName().c_str());
886
887 if (needCompile.size() > 1 && needCompile.size() < 5)
888 {
889 QString last = names.last();
890 names.pop_back();
891 QString firewalls = "\"" + names.join("\", \"") + "\" " + tr("and") + " \"" + last + "\"";
892 text = tr("Firewall objects %1 have been modified and need to be recompiled.").arg(firewalls);
893 }
894 else
895 if (needCompile.size() == 1)
896 text = tr("Firewall object \"%1\" has been modified and needs to be recompiled.").arg(names.first());
897 else
898 {
899 text = tr("%1 firewall objects have been modified and need to be recompiled.").arg(needCompile.size());
900 }
901
902 messageBox.setText(text);
903 messageBox.exec();
904 if (messageBox.result() == QMessageBox::Accepted)
905 {
906 this->compile(needCompile);
907 }
908 return;
909 }
910
911 QStringList files;
912
913 QSet<Firewall*> filesMissing;
914 Firewall *first_fw = NULL;
915 foreach(Firewall *fw, fws)
916 {
917 if (first_fw == NULL) first_fw = fw;
918
919 /*
920 * get full path to the generated file. The path is built from
921 * the file name returned by
922 * FirewallInstaller::getGeneratedFileName() and directory
923 * path from the .fwb file. Note that we use the same
924 * algorithm when GUI launches policy compiler, except there
925 * the path is passed to it via "-d" command line option.
926 */
927 QString mainFile = FirewallInstaller::getGeneratedFileFullPath(fw);
928 // QString mainFile = FirewallInstaller::getGeneratedFileName(fw);
929
930 if (QFile::exists(mainFile))
931 {
932 instConf cnf;
933 cnf.fwobj = fw;
934 cnf.script = mainFile;
935 QMap<QString, QString> res;
936 FirewallInstaller(NULL, &cnf, "").readManifest(mainFile, &res);
937 QStringList current_files = res.keys();
938 foreach(QString file, current_files)
939 {
940 if (!QFile::exists(file))
941 filesMissing.insert(fw);
942 else
943 files.append(file);
944 }
945 }
946 else
947 filesMissing.insert(fw);
948 }
949
950 if (!filesMissing.isEmpty())
951 {
952 QString text;
953 QStringList names;
954 foreach(Firewall *fw, filesMissing)
955 names.append(fw->getName().c_str());
956
957 if (filesMissing.size() > 1 && filesMissing.size() < 5)
958 {
959 QString last = names.last();
960 names.pop_back();
961 QString firewalls = "\"" + names.join("\", \"") + "\" " + tr("and") + " \"" + last + "\"";
962 text = tr("Can not read generated files for the firewall objects %1. You need to compile them to create the files.").arg(firewalls);
963 }
964 else
965 if (filesMissing.size() == 1)
966 text = tr("Can not read generated files for the firewall objects %1. You need to compile it to create the files.").arg(names.first());
967 else
968 {
969 text = tr("Can not read generated files for the %1 firewall objects. You need to compile then to create the files.").arg(filesMissing.size());
970 }
971 messageBox.setText(text);
972 messageBox.exec();
973 if (messageBox.result() == QMessageBox::Accepted)
974 {
975 this->compile(fws);
976 }
977 return;
978 }
979
980 if (files.empty())
981 return;
982
983 QString viewer_title;
984 if (fws.size() > 1) viewer_title = tr("<b>Multiple firewalls</b>");
985 else viewer_title = QString("<b>%1</b>").arg(first_fw->getName().c_str());
986
987 FirewallCodeViewer *viewer =
988 new FirewallCodeViewer(files, viewer_title, this, this);
989 viewer->show();
990 }
991
printHeader()992 QString ProjectPanel::printHeader()
993 {
994 QString headerText = rcs->getFileName().section("/",-1,-1);
995 if (rcs->isInRCS())
996 headerText = headerText + ", rev " + rcs->getSelectedRev();
997 return headerText;
998 }
999
registerRuleSetRedrawRequest()1000 void ProjectPanel::registerRuleSetRedrawRequest()
1001 {
1002 if (!ruleSetRedrawPending)
1003 {
1004 ruleSetRedrawPending = true;
1005 //redrawRuleSets();
1006 QTimer::singleShot( 0, this, SLOT(redrawRuleSets()) );
1007 }
1008 }
1009
redrawRuleSets()1010 void ProjectPanel::redrawRuleSets()
1011 {
1012 ruleSetRedrawPending = false;
1013 reopenFirewall();
1014 }
1015
aboutToActivate()1016 void ProjectPanel::aboutToActivate()
1017 {
1018 if (fwbdebug) qDebug() << "ProjectPanel::aboutToActivate " << this;
1019 }
1020
showEvent(QShowEvent * ev)1021 void ProjectPanel::showEvent(QShowEvent *ev)
1022 {
1023 if (fwbdebug) qDebug() << "ProjectPanel::showEvent " << this
1024 << "title " << mdiWindow->windowTitle();
1025
1026 QWidget::showEvent(ev);
1027
1028 // we get this event when MDI window is maximized or restored
1029 // loadState();
1030
1031 // visibilityChangedForTreePanel(true);
1032 }
1033
hideEvent(QHideEvent * ev)1034 void ProjectPanel::hideEvent(QHideEvent *ev)
1035 {
1036 if (fwbdebug) qDebug() << "ProjectPanel::hideEvent " << this
1037 << "title " << mdiWindow->windowTitle();
1038
1039 QWidget::hideEvent(ev);
1040 }
1041
closeEvent(QCloseEvent * ev)1042 void ProjectPanel::closeEvent(QCloseEvent * ev)
1043 {
1044 if (fwbdebug) qDebug() << "ProjectPanel::closeEvent " << this
1045 << "title " << mdiWindow->windowTitle();
1046
1047 if (!saveIfModified() || !checkin(true))
1048 {
1049 ev->ignore();
1050 return;
1051 }
1052
1053 saveState();
1054 fileClose();
1055
1056 mw->updateWindowTitle();
1057
1058 //QCoreApplication::postEvent(mw, new closeEditorPanelEvent());
1059 QCoreApplication::postEvent(mw, new clearEditorPanelEvent());
1060
1061 QTimer::singleShot( 0, mw, SLOT(projectWindowClosed()) );
1062 }
1063
getFileName()1064 QString ProjectPanel::getFileName()
1065 {
1066 if (rcs!=NULL) return rcs->getFileName();
1067 else return "";
1068 }
1069
splitterMoved(int,int)1070 void ProjectPanel::splitterMoved(int , int)
1071 {
1072 }
1073
resizeEvent(QResizeEvent *)1074 void ProjectPanel::resizeEvent(QResizeEvent*)
1075 {
1076 }
1077
registerTreeReloadRequest()1078 void ProjectPanel::registerTreeReloadRequest()
1079 {
1080 treeReloadPending = true;
1081 QTimer::singleShot(0, this, SLOT(reloadTree()));
1082 }
1083
reloadTree()1084 void ProjectPanel::reloadTree()
1085 {
1086 if (treeReloadPending)
1087 {
1088 m_panel->om->reload();
1089 treeReloadPending = false;
1090 }
1091 }
1092
registerObjectToUpdateInTree(FWObject * o,bool update_subtree)1093 void ProjectPanel::registerObjectToUpdateInTree(FWObject *o, bool update_subtree)
1094 {
1095 if (fwbdebug)
1096 qDebug() << "ProjectPanel::registerObjectToUpdateInTree()"
1097 << "o=" << o->getName().c_str()
1098 << "update_subtree=" << update_subtree
1099 << "updateObjectsInTreePool.size()="
1100 << updateObjectsInTreePool.size();
1101
1102 if (updateObjectsInTreePool.find(o->getId()) == updateObjectsInTreePool.end())
1103 {
1104 updateObjectsInTreePool[o->getId()] = update_subtree;
1105 QTimer::singleShot(0, this, SLOT(updateObjectInTree()));
1106 }
1107 }
1108
updateObjectInTree()1109 void ProjectPanel::updateObjectInTree()
1110 {
1111 if (fwbdebug)
1112 qDebug() << "ProjectPanel::updateObjectInTree()"
1113 << "updateObjectsInTreePool.size()="
1114 << updateObjectsInTreePool.size();
1115
1116 while (updateObjectsInTreePool.size() > 0)
1117 {
1118 map<int, bool>::iterator it = updateObjectsInTreePool.begin();
1119 FWObject *obj = db()->findInIndex(it->first);
1120 m_panel->om->updateObjectInTree(obj, it->second);
1121 updateObjectsInTreePool.erase(it);
1122 }
1123 mdiWindow->update();
1124 }
1125
registerModifiedObject(FWObject * o)1126 void ProjectPanel::registerModifiedObject(FWObject *o)
1127 {
1128 if (fwbdebug)
1129 qDebug() << "ProjectPanel::registerModifiedObject "
1130 << "lastModifiedTimestampChangePool.size()="
1131 << lastModifiedTimestampChangePool.size()
1132 << "o=" << o->getName().c_str()
1133 << "(" << o->getTypeName().c_str() << ")"
1134 << "id=" << o->getId();
1135
1136 FWObject *modified_object = o;
1137
1138 /*
1139 * a bit of optimization: the purpose of registering modified
1140 * object here is to update "last modified" timestamp in the
1141 * firewall object it belongs to. One of the frequent cases is
1142 * when @o is rule element because user made some change to
1143 * it. Massive find and replace operations can cause waves of
1144 * registrations of rule elements, all of which belong to the
1145 * same rule set. If I register rule set instead, there will be
1146 * just one object to register.
1147 */
1148
1149 if (RuleElement::cast(o))
1150 {
1151 while (RuleSet::cast(modified_object) == NULL)
1152 modified_object = modified_object->getParent();
1153 }
1154
1155 if (lastModifiedTimestampChangePool.find(modified_object->getId()) ==
1156 lastModifiedTimestampChangePool.end())
1157 {
1158 if (fwbdebug)
1159 qDebug() << "ProjectPanel::registerModifiedObject "
1160 << "Add object" << modified_object->getName().c_str()
1161 << "id=" << modified_object->getId();
1162
1163 lastModifiedTimestampChangePool.insert(modified_object->getId());
1164 QTimer::singleShot(
1165 0, this, SLOT(updateLastModifiedTimestampForAllFirewalls()));
1166 }
1167 }
1168
updateLastModifiedTimestampForAllFirewalls()1169 void ProjectPanel::updateLastModifiedTimestampForAllFirewalls()
1170 {
1171 if (fwbdebug)
1172 qDebug() << "ProjectPanel::updateLastModifiedTimestampForAllFirewalls"
1173 << "lastModifiedTimestampChangePool.size()="
1174 << lastModifiedTimestampChangePool.size();
1175
1176 if (lastModifiedTimestampChangePool.size() == 0) return;
1177
1178 mw->showStatusBarMessage(
1179 tr("Searching for firewalls affected by the change..."));
1180
1181 //QApplication::processEvents(QEventLoop::ExcludeUserInputEvents,100);
1182
1183 QApplication::setOverrideCursor(QCursor( Qt::WaitCursor));
1184
1185 set<Firewall*> firewalls_to_update;
1186
1187 while (lastModifiedTimestampChangePool.size() > 0)
1188 {
1189 set<int>::iterator it = lastModifiedTimestampChangePool.begin();
1190 FWObject *obj = db()->findInIndex(*it);
1191 lastModifiedTimestampChangePool.erase(it);
1192
1193 if (fwbdebug)
1194 qDebug() << "Modified object: " << obj->getName().c_str();
1195
1196 if (FWBTree().isSystem(obj)) continue;
1197
1198 list<Firewall *> fws = m_panel->om->findFirewallsForObject(obj);
1199 if (fws.size())
1200 {
1201 Firewall *f;
1202 for (list<Firewall *>::iterator i=fws.begin();
1203 i!=fws.end();
1204 ++i)
1205 {
1206 f = *i;
1207 if (f==obj) continue;
1208
1209 firewalls_to_update.insert(f);
1210 }
1211 }
1212 }
1213
1214 if (fwbdebug)
1215 qDebug() << "Will update " << firewalls_to_update.size() << " firewalls";
1216
1217 for (set<Firewall*>::iterator it=firewalls_to_update.begin();
1218 it!=firewalls_to_update.end(); ++it)
1219 {
1220 Firewall *f = *it;
1221 // when user locks firewall object, this code tries to
1222 // update last_modified timestamp in it because it
1223 // depends on itself. Dont.
1224 if (f->isReadOnly()) continue;
1225
1226 f->updateLastModifiedTimestamp();
1227 QCoreApplication::postEvent(
1228 mw, new updateObjectInTreeEvent(getFileName(), f->getId()));
1229
1230 list<Cluster*> clusters = m_panel->om->findClustersUsingFirewall(f);
1231 if (clusters.size() != 0)
1232 {
1233 list<Cluster*>::iterator it;
1234 for (it=clusters.begin(); it!=clusters.end(); ++it)
1235 {
1236 Cluster *cl = *it;
1237 if (cl->isReadOnly()) continue;
1238 cl->updateLastModifiedTimestamp();
1239 QCoreApplication::postEvent(
1240 mw, new updateObjectInTreeEvent(getFileName(), cl->getId()));
1241 }
1242 }
1243 }
1244
1245 QApplication::restoreOverrideCursor();
1246 }
1247
toggleViewTree(bool f)1248 void ProjectPanel::toggleViewTree(bool f)
1249 {
1250 if (f) m_panel->treePanelFrame->show();
1251 else m_panel->treePanelFrame->hide();
1252 }
1253
setActive()1254 void ProjectPanel::setActive()
1255 {
1256 undoStack->setActive(true);
1257 }
1258
splitterPositionChanged(int,int)1259 void ProjectPanel::splitterPositionChanged(int,int)
1260 {
1261 saveMainSplitter();
1262 }
1263
1264