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