1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-06-24 01:49:36 +02:00
Files
fwbuilder/src/libgui/utils.cpp
2019-07-22 17:08:51 +00:00

630 lines
17 KiB
C++

/*
Firewall Builder
Copyright (C) 2003 NetCitadel, LLC
Author: Vadim Kurland vadim@fwbuilder.org
$Id$
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "global.h"
#include "utils.h"
#include "utils_no_qt.h"
#include <qobject.h>
#include <qmenu.h>
#include <qcombobox.h>
#include <qlistwidget.h>
#include <qmessagebox.h>
#include <qpalette.h>
#include <qnamespace.h>
#include <QHostInfo>
#include <qhostaddress.h>
#include <qpixmapcache.h>
#include <QList>
#include <QStringList>
#include <QRegExp>
#include <QPixmap>
#include <QApplication>
#include <QFileInfo>
#include <QDir>
#include <QtDebug>
#include "FWBSettings.h"
#include "fwbuilder/dns.h"
#include "fwbuilder/FWObject.h"
#include "fwbuilder/FWReference.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Library.h"
#include "fwbuilder/Resources.h"
#if defined(_WIN32)
# include <stdio.h>
# include <sys/timeb.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <time.h>
# include <windows.h>
#else
# include <unistd.h>
# include <string.h>
# include <errno.h>
# include <pwd.h>
#endif
#include <iostream>
#include <algorithm>
#include <cctype>
#include "FWBTree.h"
using namespace std;
using namespace libfwbuilder;
QAction* addPopupMenuItem(QObject *res,
QMenu* menu,
const QString &resourceIconPath,
const QString itemName,
const char* member,
const QKeySequence &accel)
{
string icn;
QPixmap pm;
//int itmID = -1;
QAction *act = nullptr;
icn = Resources::global_res->getResourceStr(static_cast<const char*>(resourceIconPath.toLatin1()));
if(icn!="")
{
// pm = QPixmap::fromMimeSource( icn.c_str() );
if ( ! QPixmapCache::find( icn.c_str(), &pm) )
{
pm.load( (":/"+icn).c_str() );//fromMimeSource( icn.c_str() );
QPixmapCache::insert( icn.c_str(), pm);
}
act = menu->addAction( pm, itemName , res , member, accel ); //insertItem
} else
act = menu->addAction( itemName , res , member, accel); //insertItem
return act;
}
void fillLibraries(QComboBox *libs, libfwbuilder::FWObject *obj, bool rw)
{
bool standardObj = false;
bool templateObj = false;
bool deletedObj = false;
QString lib="";
if ( ! FWObjectDatabase::isA(obj))
{
FWObject *libobj = obj->getLibrary();
assert(libobj!=nullptr);
lib = libobj->getName().c_str();
standardObj = (libobj->getId()==FWObjectDatabase::STANDARD_LIB_ID);
templateObj = (libobj->getId()==FWObjectDatabase::TEMPLATE_LIB_ID);
deletedObj = (libobj->getId()==FWObjectDatabase::DELETED_OBJECTS_ID);
}
libs->clear();
list<FWObject*> ll = obj->getRoot()->getByType( Library::TYPENAME );
ll.sort(FWObjectNameCmpPredicate());
int n=0;
int cn=0;
string libicn;
for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
{
if (libicn.empty())
libicn=(":/Icons/"+(*i)->getTypeName()+"/icon-tree").c_str();
if ( (*i)->getId()==FWObjectDatabase::STANDARD_LIB_ID &&
!standardObj) continue;
if ( (*i)->getId()==FWObjectDatabase::TEMPLATE_LIB_ID &&
!templateObj) continue;
if ( (*i)->getId()==FWObjectDatabase::DELETED_OBJECTS_ID &&
!deletedObj ) continue;
if (rw && (*i)->isReadOnly()) continue;
if (lib==QString((*i)->getName().c_str())) cn=n;
QPixmap icon;
icon.load( (libicn).c_str() );
libs->addItem(icon,
QString::fromUtf8((*i)->getName().c_str()) );
n++;
}
libs->setCurrentIndex(cn);
}
void fillLibraries(QListWidget *libs, libfwbuilder::FWObject *obj, bool rw)
{
bool standardObj = false;
bool templateObj = false;
bool deletedObj = false;
QString lib="";
if ( ! FWObjectDatabase::isA(obj))
{
FWObject *libobj = obj->getLibrary();
assert(libobj!=nullptr);
lib = libobj->getName().c_str();
standardObj = (libobj->getId()==FWObjectDatabase::STANDARD_LIB_ID);
templateObj = (libobj->getId()==FWObjectDatabase::TEMPLATE_LIB_ID);
deletedObj = (libobj->getId()==FWObjectDatabase::DELETED_OBJECTS_ID);
}
libs->clear();
list<FWObject*> ll = obj->getRoot()->getByType( Library::TYPENAME );
ll.sort(FWObjectNameCmpPredicate());
int n=0;
int cn=0;
string libicn;
for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
{
if (libicn.empty())
libicn=Resources::global_res->getObjResourceStr(*i,"icon-tree").c_str();
if ( (*i)->getId()==FWObjectDatabase::STANDARD_LIB_ID && !standardObj) continue;
if ( (*i)->getId()==FWObjectDatabase::TEMPLATE_LIB_ID && !templateObj) continue;
if ( (*i)->getId()==FWObjectDatabase::DELETED_OBJECTS_ID && !deletedObj ) continue;
if (rw && (*i)->isReadOnly()) continue;
if (lib==QString((*i)->getName().c_str())) cn=n;
QPixmap icon;
icon.load( (":/"+libicn).c_str() );
QListWidgetItem *item = new QListWidgetItem(icon, (*i)->getName().c_str());
libs->addItem(item);
n++;
}
libs->setCurrentRow(cn);
}
bool isTreeReadWrite(QWidget *parent, FWObject *obj)
{
if (obj->isReadOnly())
{
QMessageBox::warning(
parent, "Firewall Builder",
QObject::tr("Impossible to apply changes because object is "
"located in read-only\npart of the tree or data "
"file was opened read-only"),
QObject::tr("&Continue"), 0, 0,
0, 2 );
return false;
}
return true;
}
/*
* compare names as QString objects to catch non-ascii names
*/
bool validateName(QWidget *parent, FWObject *obj, const QString &newname)
{
if (newname.isEmpty())
{
// show warning dialog only if app has focus
if (QApplication::focusWidget() != nullptr)
{
parent->blockSignals(true);
QMessageBox::warning(
parent, "Firewall Builder",
QObject::tr("Object name should not be blank"),
QObject::tr("&Continue"), nullptr, nullptr, 0, 2 );
parent->blockSignals(false);
}
return false;
}
FWObject *p = obj->getParent();
for (FWObject::iterator i=p->begin(); i!=p->end(); ++i)
{
FWObject *o1= *i;
// Another hack: we need to be able to create policy and nat
// ruleset objects with name "ftp-proxy/*" for PF. Allow
// objects of different type to have the same name.
if (o1 == obj || o1->getTypeName() != obj->getTypeName()) continue;
if (QString(o1->getName().c_str()) == newname)
{
/*
* when we open this warning dialog, the dialog class
* loses focus and obj_name lineEdit widget sends signal
* "editingfinished" again. To the user this looks like the
* warning dialog popped up twice (in fact two copies of the
* same warning dialog appear at the same time, one exactly on
* top of another). To avoid this, block signals for the
* duration while we show the dialog. Note that documentation
* does not mention that QObject::blockSignals() affects not
* only the widget but all its children, but it seems to work
* that way. Tested with Qt 4.6.1. See #1171
*/
// show warning dialog only if app has focus
if (QApplication::focusWidget() != nullptr)
{
parent->blockSignals(true);
QMessageBox::warning(
parent, "Firewall Builder",
QObject::tr("Object with name '%1' already exists, "
"please choose different name.").
arg(o1->getName().c_str()),
QObject::tr("&Continue"), nullptr, nullptr, 0, 2 );
parent->blockSignals(false);
}
return false;
}
}
return true;
}
QString quoteString(const QString &str)
{
QString res;
if (str.indexOf(" ")!=-1) res="\"";
res+=str;
if (str.indexOf(" ")!=-1) res+="\"";
return res;
}
QString getFileDir(const QString &file)
{
return QFileInfo(file).dir().path();
}
void setDisabledPalette(QWidget *w)
{
QPalette pal=w->palette();
pal.setCurrentColorGroup( QPalette::Active );
pal.setColor( QPalette::Text, Qt::black );
pal.setCurrentColorGroup( QPalette::Inactive );
pal.setColor( QPalette::Text, Qt::black );
pal.setCurrentColorGroup( QPalette::Disabled );
pal.setColor( QPalette::Text, Qt::black );
w->setPalette( pal );
}
QString getAddrByName(const QString &name, int af_type)
{
list<InetAddr> results;
try
{
results = DNS::getHostByName(name.toLatin1().constData(), af_type);
} catch (FWException &e)
{
if (fwbdebug) qDebug("utils::getAddrByName: DNS lookup error: %s",
e.toString().c_str());
return "";
}
try
{
if (results.size()>0)
return QString(results.front().toString().c_str());
} catch (FWException &e)
{
qDebug() << "utils::getAddrByName: Can not convert address to string";
qDebug() << e.toString().c_str();
}
return "";
#if 0
QHostInfo a = QHostInfo::fromName(name);
QList<QHostAddress> alist = a.addresses();
if (alist.empty()) return "";
return alist.front().toString();
#endif
}
QString getNameByAddr(const QString &addr)
{
/*QHostAddress ha;
ha.setAddress(addr);
Q3Dns qry( ha, Q3Dns::Ptr);
QStringList nlist = qry.hostNames();
while (qry.isWorking())
{
app->processEvents(200);
}
nlist = qry.hostNames();
if (nlist.empty()) return "";
return nlist.front();*/
QHostInfo a = QHostInfo::fromName(addr);
return a.hostName();
}
QString wordWrap(const QString& s, int maxchinline)
{
int chcount=0;
int lastwdpos=0;
int linestart=0;
bool fl_wd=true;
/*unsigned*/ int pos=0;
QString res="";
QChar ch;
for ( ; pos < s.length(); pos++,chcount++)
{
ch = s.at(pos);
if (!ch.isLetter() && !ch.isNumber())
{
fl_wd=false;
} else
{
if (!fl_wd)
{
fl_wd=true;
lastwdpos=pos;
}
}
if (chcount>maxchinline)
{
if (fl_wd)
{
if (linestart<lastwdpos)
{
res.append(s.mid(linestart,lastwdpos-linestart));
linestart=lastwdpos;
pos=lastwdpos;
}else
{
res.append(s.mid(linestart,pos-linestart));
linestart=pos;
lastwdpos=pos;
}
}
else
{
res.append(s.mid(linestart,pos-linestart));
while (++pos< s.length() && s.at(pos).isSpace()) ;
if (pos<s.length())
{
linestart=pos--;
}
else
{
break;
}
}
res.append('\n');
chcount=0;
}
}
res.append(s.mid(linestart,pos-linestart));
return res;
}
void loadIcon(QPixmap &pm, FWObject *obj)
{
QString icn_file = (":/Icons/" + obj->getTypeName()+"/icon-tree").c_str();
LoadPixmap(icn_file, pm);
// if ( ! QPixmapCache::find( icn_file, pm) )
// {
// pm.load( icn_file );
// QPixmapCache::insert( icn_file, pm);
// }
}
void LoadPixmap(const QString &path, QPixmap &pm)
{
if ( ! QPixmapCache::find( path, &pm ) )
{
pm.load( path );
if (pm.width() == 0)
qDebug("pixmap load failed: %s", path.toLatin1().constData());
QPixmapCache::insert( path, pm );
}
}
QPixmap LoadPixmap(const QString &path)
{
QPixmap p;
LoadPixmap(path, p);
return p;
}
QString calculateIconName(const QString &_icn, bool negation)
{
// if _icn has white space, use only the first word
QStringList icnl = _icn.split(" ");
QString icn = ":/Icons/" + icnl[0] + "/icon";
if (negation)
{
icn = icn + "-neg";
}
if (FWBSettings::SIZE16X16 == st->getIconsInRulesSize())
{
return icn+"-tree";
}
return icn;
}
void doSetObjectIcon(FWObject *obj, QPixmap *pm, int icon_size)
{
QString icn_alias;
QString icn_sfx;
switch (icon_size)
{
case 0: icn_sfx = "icon-tree"; break;
case 2: icn_sfx = "icon-big"; break;
default: icn_sfx = "icon"; break;
}
// note that we do not have "locked" version of large icons
if (obj->getRO() && icon_size != 2)
icn_alias = ":/Icons/lock";
else
{
if (FWBTree().isStandardFolder(obj))
icn_alias = ":/Icons/SystemGroup/" + icn_sfx;
else
icn_alias = QString(":/Icons/") + obj->getTypeName().c_str() + "/" + icn_sfx;
}
LoadPixmap(icn_alias, *pm);
}
QString _getNextToken(QStringList &args)
{
QString a;
while (args.size() > 0)
{
a = args.front();
args.pop_front();
if (!a.isEmpty()) break;
}
return a;
}
// reassemble quoted strings from the list of tokens, possibly
// recursively if there are quoted strings inside. The first token is
// assumed to be " or '. Pops all processed tokens from the list but
// leaves the rest in it.
QString _parseTokens(QStringList &args, const QChar closing_quote='\0')
{
QString a = _getNextToken(args);
if (args.size() == 0) return a;
if (closing_quote != QChar('\0') && a.endsWith(closing_quote))
return a;
if (a.startsWith("\"") || a.startsWith("'"))
{
QStringList res;
QChar closing_quote = a[0];
res.append(a);
while (!a.endsWith(closing_quote) && args.size() > 0)
{
a = _parseTokens(args, closing_quote);
res.append(a);
}
return res.join(" ");
}
return a;
}
/**
* parse command line for ssh or scp given by user in the global
* preferences dialog. The challenge is to be able to handle situation
* when the program is installed in directory with a whitespace in the
* name, so we can't just split the string by a " ".
*
* Recognize the following constructs:
*
* /path/to/program/program -arg1 val1 -arg2 val2 -arg3 "value 3"
*
* everything before the first "-" is considered executable name
* (possibly with full path)
*
* word that starts with "-" or "/" preceded by a space is an argument
* argument may have an optional parameter
* parameter may be quoted using double or single quotes
*/
void parseCommandLine(const QString &cmd, QStringList &argv)
{
int first_arg = cmd.indexOf(QRegExp(" *-"));
if (first_arg == -1)
{
// no arguments
argv.append(cmd.trimmed());
return;
}
QString program = cmd.mid(0, first_arg).trimmed();
if (!program.isEmpty()) argv.append(program);
QStringList args = cmd.mid(first_arg).split(QRegExp("\\s+"));
// QString::SkipEmptyParts);
// splits like this:
// ["", "-arg1", "val1", "-arg2", "\"value", "2", "\""]
while (args.size() > 0)
{
QString t = _parseTokens(args);
// remove quotes from quoted strings
if ((t.startsWith('\"') && t.endsWith('\"')) ||
(t.startsWith('\'') || t.endsWith('\'')))
{
t = t.mid(1, t.length()-2);
}
argv.append(t);
}
}
static bool stringsCompare(const QString &a, const QString &b)
{
QString aLower = a.toLower();
QString bLower = b.toLower();
int result = aLower.localeAwareCompare(bLower);
if (result == 0) {
return a.localeAwareCompare(b) < 0;
} else {
return result < 0;
}
}
QStringList sortStrings(const QStringList &list)
{
QStringList ret = list;
std::sort(ret.begin(), ret.end(), stringsCompare);
return ret;
}