Ver código fonte

Qml App-Launcher und Wrapper für Wifi-Monitoring implementiert.

Rind 1 ano atrás
pai
commit
69d965af5c
10 arquivos alterados com 1157 adições e 268 exclusões
  1. 6 1
      README.md
  2. 40 0
      builddbg.sh
  3. 9 2
      gfaqt.pro
  4. 182 0
      src/argv_split.h
  5. 3 0
      src/qappctrl.cpp
  6. 266 27
      src/qappctrl.h
  7. 371 0
      src/qapplaunch.cpp
  8. 80 233
      src/qnetworkinfo.cpp
  9. 6 5
      src/qsysinfo.cpp
  10. 194 0
      src/qwlaninfo.cpp

+ 6 - 1
README.md

@@ -5,7 +5,7 @@ Allgemeine Bibliothek für QML-Objekte und Objekte mit QT-Bindung, mit Ausnahme
 ---
 
 ***Version:***  
-libgfaqt.so.1.6.0  
+libgfaqt.so.1.7.0  
 
 ***SO-Name:***  
 libgfaqt.so.1
@@ -28,6 +28,7 @@ libgfaqt.so (-lgfaqt)
 * QML-Wrapper für Tiva/SPI-Info.
 * QML-Wrapper zur Netzwerk-Interface-Konfiguration.
 * QML-Wrapper für Netzwerk-Monitor.
+* QML-Wrapper für Wlan-Monitor.
 
 ---
 
@@ -58,3 +59,7 @@ libgfaqt.so (-lgfaqt)
 
 * **1.6.0**
 	* Funktion zum Update der Storage-Device-Infos im Sysinfo-Prozess hinzugefügt.
+
+* **1.7.0**
+	* QGfaAppLauncher zum Ausführen von Prozessen hinzugefügt.
+	* Funktion zum Update von Wlan-Infos und QML-Wrapper für Wlan-Monitor hinzugefügt.

+ 40 - 0
builddbg.sh

@@ -0,0 +1,40 @@
+#!/bin/bash
+set -e
+set -o pipefail
+
+#########################################################################################
+#########################################################################################
+#########################################################################################
+
+CWD=$(pwd)
+MAKE=/usr/bin/make
+PROJ=/home/wrk/share/gfaqt/gfaqt.pro
+CRTINST=/home/wrk/share/gfalibtools/create.sh
+INSTDIR=$CWD/install
+
+rm -f $INSTDIR/*.sh
+
+#########################################################################################
+#########################################################################################
+#########################################################################################
+# Sitara
+
+QMAKE=/opt/GfA/TC_L44104_C493_QT57_V02/usr/bin/qmake
+SPEC=devices/linux-buildroot-g++
+
+#########################################################################################
+# Debug
+
+BASENAMEDBG="libgfaqtd.so.1.7.0-install-debug"
+
+BUILDDIR=Debug/Sitara_1
+mkdir -p $BUILDDIR
+cd $BUILDDIR
+$QMAKE $PROJ -spec $SPEC CONFIG+=debug CONFIG+=qml_debug && $MAKE qmake_all
+$MAKE clean -j2
+$MAKE -j2
+$MAKE install_toolchain
+$CRTINST $(pwd) $CWD debug $SPEC
+cd $CWD
+cd $INSTDIR
+./$BASENAMEDBG"-toolchain.sh"

+ 9 - 2
gfaqt.pro

@@ -1,5 +1,5 @@
 TEMPLATE = lib
-VERSION = 1.6
+VERSION = 1.7
 QT += qml quick core
 CONFIG -= app_bundle
 CONFIG += c++11 shared thread
@@ -12,8 +12,10 @@ SOURCES += \
     src/qappinfo.cpp \
     src/qmysqlinfo.cpp \
     src/qnetworkinfo.cpp \
+    src/qwlaninfo.cpp \
     src/qsysinfo.cpp \
-    src/qgfalocale.cpp
+    src/qgfalocale.cpp \
+    src/qapplaunch.cpp
 
 HEADERS += \
     src/helpers.h \
@@ -28,6 +30,8 @@ QMAKE_RPATHLINKDIR += $$GFA_LIB_PATH
 QMAKE_RPATHDIR += $$GFA_LIB_PATH
 QMAKE_DEL_DIR = rmdir --ignore-fail-on-non-empty
 QMAKE_LN_SHLIB = :
+QMAKE_CXXFLAGS += -Wno-deprecated-copy
+QMAKE_CFLAGS += -Wno-deprecated-copy
 
 ####################################################################################
 
@@ -47,6 +51,9 @@ INSTALLS += target
 ####################################################################################
 
 linux-g++ {
+    QMAKE_CXXFLAGS += -Wno-deprecated-declarations -Wno-misleading-indentation -Wno-unused-result
+    QMAKE_CFLAGS += -Wno-deprecated-declarations -Wno-misleading-indentation -Wno-unused-result
+
 	includes.path = $$GFA_INC_PATH
 	includes.extra += -$(INSTALL_FILE) $$PWD/src/qappctrl.h $(INSTALL_ROOT)$$includes.path
 	includes.extra += $$escape_expand(\\n\\t)-$(INSTALL_FILE) $$PWD/src/qgfalocale.h $(INSTALL_ROOT)$$includes.path

+ 182 - 0
src/argv_split.h

@@ -0,0 +1,182 @@
+#include <array>
+#include <vector>
+#include <string>
+#include <sstream>
+
+#define ESCAPE_HEX_CODE 0x5c
+#define SGLQUOTE_HEX_CODE 0x27
+#define DBLQUOTE_HEX_CODE 0x22
+#define SPACE_HEX_CODE 0x20
+
+class argv_split {
+private:
+	char quotes[3];
+	char space[2];
+	bool prependProgname;
+	std::string progname;
+	std::vector<std::string> arguments;
+	std::vector<const char*> argv_arr;
+
+	bool isEscaped(const std::string& str, size_t idx) {
+		// is first character, can not be escaped
+		if ( idx == 0 ) return false;
+		// is out of bounds (-1)
+		if ( idx == std::string::npos ) return false;
+
+		// preceeding character is backslash?
+		if ( str.at(idx - 1) == ESCAPE_HEX_CODE )
+			return true;
+		else
+			return false;
+	}
+
+	size_t findFirstQuote(const std::string& str) {
+		size_t idx = 0;
+
+		do {
+			idx = str.find_first_of(quotes, idx == 0 ? 0 : idx + 1);
+		} while ( isEscaped( str, idx ) && idx != std::string::npos);
+
+		return idx;
+	}
+
+	size_t findMatching(const std::string& str, size_t match_idx) {
+		if (match_idx == std::string::npos) return std::string::npos;
+		
+		char match[1];
+		match[0] = str.at( match_idx );
+
+		size_t idx = match_idx;
+
+		do {
+			idx = str.find_first_of( match, idx + 1 );
+		} while ( isEscaped( str, idx ) && idx != std::string::npos);
+
+		return idx;
+	}
+
+	void splitStrToVectorBy(const std::string& str, char delim, std::vector<std::string>& vec)
+	{
+		std::stringstream strStream( str );
+		std::string element;
+
+		while ( std::getline( strStream, element, delim ) )
+		{
+			if ( !element.empty() )
+				vec.push_back( element );
+		}
+	}
+
+	// function is called recursive
+	// inefficient: (but ok for the intended use)
+	//	- using substrings (copying) for recursion; C++17 string_view could fix this
+	//	- no memory preallocation for arguments vector
+	void _parse(const std::string& cmdlinestr) {
+		if (cmdlinestr.length() == 0)
+			return;
+
+		std::string quoted_str, pre_quoted_str, post_quoted_str;
+
+		// w_front used as limit for string splitting on whitespace
+		size_t w_front = cmdlinestr.size(); // if no quotes are found this is used as the substring SIZE for splitting by space
+		size_t w_back = cmdlinestr.size() - 1; // if no quotes are found this is used as OFFSET for the next (and final) recursion
+
+		size_t q_front = findFirstQuote(cmdlinestr);
+		size_t q_back = findMatching(cmdlinestr, q_front);
+		// found an unescaped qoute, are same when npos an so no quote found. are different when two quotes or only a first one are found
+		if ( q_front != q_back )
+		{			
+			// get quoted string
+			// and get attached string after quoted string. open quotes will be treated as quotes til the end!
+
+			// found matching quote to first
+			if ( q_back != std::string::npos )
+			{
+				quoted_str = cmdlinestr.substr( q_front + 1, q_back - q_front - 1 );
+
+				// find first whitespace after quote
+				w_back = cmdlinestr.find_first_of( space, q_back + 1 );
+				// none found? handle as quoted til the end
+				if (w_back == std::string::npos)
+					w_back = cmdlinestr.size() - 1;
+
+				post_quoted_str = cmdlinestr.substr(q_back + 1, w_back - q_back - 1);
+			}
+			// did not find matching quote further in string, everything til the end is quoted now
+			else
+			{
+				quoted_str = cmdlinestr.substr(q_front + 1, std::string::npos);
+			}
+
+
+			// get string attached in front of quoted string
+			
+			// find last whitespace before quote
+			w_front = cmdlinestr.find_last_of(space, q_front);
+			// none found?
+			if ( w_front == std::string::npos )
+				w_front = - 1;
+
+			pre_quoted_str = cmdlinestr.substr( w_front + 1, q_front - w_front - 1 );
+
+		}
+
+		// split by whitespace in [0, w_front[
+		if(w_front != (size_t)-1 && w_front != std::string::npos)
+			splitStrToVectorBy(cmdlinestr.substr(0, w_front), SPACE_HEX_CODE, arguments);
+		
+		//add qouted string and surrounding
+		if (!quoted_str.empty())
+			arguments.push_back(pre_quoted_str + quoted_str + post_quoted_str);
+		
+		//recurse
+		_parse(cmdlinestr.substr(w_back + 1, std::string::npos));
+	}
+
+public:
+	argv_split() : quotes{ SGLQUOTE_HEX_CODE, DBLQUOTE_HEX_CODE, 0}, space{ SPACE_HEX_CODE, 0 }, prependProgname(false) {}
+
+	argv_split(std::string progname) : argv_split()
+	{
+		prependProgname = true;
+		this->progname = progname;
+	}
+
+	~argv_split() {}
+
+	std::vector<std::string> getArguments()
+	{
+		return arguments;
+	}
+
+	const char** argv() {
+		//return argv_arr;
+		return argv_arr.data();
+	}
+
+	const char** parse(const std::string& cmdline) {
+		// setup/cleanup argv pointer
+		argv_arr.clear();
+
+		// setup/cleanup arguments
+		arguments.clear();
+		if (prependProgname)
+			arguments.push_back(progname);
+
+
+		// parse the string and populate arguments vector
+		_parse(cmdline);
+
+		// zero arguments? exit now. argv_arr=NULL at this point; allow handling by argv()
+		if (arguments.size() == 0)
+			return argv();
+
+		// populate argv array
+		for (auto& it : arguments)
+			argv_arr.push_back(it.c_str());
+		// terminate with null as standard argv array
+		argv_arr.push_back(NULL);
+
+		return argv();
+	}
+};

+ 3 - 0
src/qappctrl.cpp

@@ -99,6 +99,7 @@ void QGfaAppCtrl::Release(void)
 void QGfaAppCtrl::RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor, int nVerMinor)
 {
 	qmlRegisterUncreatableType<QGfaStgDevList>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaStgDevList", QStringLiteral("class not creatable in QML"));
+	qmlRegisterUncreatableType<QGfaWlanMonSchemaModel>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaWlanMonSchemaModel", QStringLiteral("class not creatable in QML"));
 	qmlRegisterUncreatableType<QGfaSysInfo>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaSysInfo", QStringLiteral("class not creatable in QML"));
 	qmlRegisterUncreatableType<QGfaAppInfo>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaAppInfo", QStringLiteral("class not creatable in QML"));
 	qmlRegisterUncreatableType<QGfaAppCtrl>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaAppCtrl", QStringLiteral("class not creatable in QML"));
@@ -113,6 +114,8 @@ void QGfaAppCtrl::RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor, int nVerMino
 	qmlRegisterUncreatableType<QIPv4Address>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QIPv4Address", QStringLiteral("class not creatable in QML"));
 //	qmlRegisterUncreatableType<QQmlListProperty<QInterface>>("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QQmlListProperty<QInterface>", QStringLiteral("class not creatable in QML"));
 
+	QGfaAppLauncher::RegisterQmlTypes(rEng, nVerMajor, nVerMinor);
+		
 	rEng.rootContext()->setContextProperty(QStringLiteral("qGfaAppCtrl"), this);
 }
 

+ 266 - 27
src/qappctrl.h

@@ -10,6 +10,7 @@
 #include <QAbstractItemModel>
 #include <QModelIndex>
 #include <QVector>
+#include <QProcess>
 #include <vector>
 #include <gfa/gfaipc.h>
 #include <gfa/ipcpriv.h>
@@ -82,7 +83,7 @@ public:
 	int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
 	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
 	QHash<int, QByteArray> roleNames(void) const Q_DECL_OVERRIDE;
-	
+
 	void diskAdded(int nIndex, const GFA_SYSINFO_DISK &disk);
 	void diskRemoved(int nIndex, const GFA_SYSINFO_DISK &disk);
 	void partitionAdded(int nIndex, const GFA_SYSINFO_PARTITION &part);
@@ -101,7 +102,7 @@ private:
 private:
 	GFA_SYSINFO_STORAGE_DEVICE_MAP m_stgDevShadowCpy;
 	std::vector<STG_DEV_DISK_PART> m_partVec;
-	
+
 	static const STG_DEV_ROLES m_roles[];
 };
 
@@ -199,7 +200,7 @@ class QGfaMySqlInfo : public QObject
 public:
 	explicit QGfaMySqlInfo(QObject *pParent = NULL);
 	virtual ~QGfaMySqlInfo(void);
-	
+
 	void onMySqlInitEvent(bool bInit);
 	void onMySqlServerEvent(const GFA_MYSQL_SERVER &svr);
 	void onMySqlResourceEvent(const GFA_MYSQL_RESOURCE &res);
@@ -231,19 +232,19 @@ private:
 
 	bool svrInnoDbFilePerTableSpace(void) const;
 	void setSvrInnoDbFilePerTableSpace(bool val);
-	
+
 	qint32 svrPid(void) const;
 	void setSvrPid(pid_t val);
-	
+
 	quint64 svrUpTime(void) const;
 	void setSvrUpTime(time_t val);
-	
+
 	quint64 svrDiscUsage(void) const;
 	void setSvrDiscUsage(size_t val);
-	
+
 	QString svrVersion(void) const;
 	void setSvrVersion(const char *val);
-	
+
 	QString svrDataDir(void) const;
 	void setSvrDataDir(const char *val);
 
@@ -270,7 +271,7 @@ private:
 
 	quint32 svrNumDataBases(void) const;
 	void setSvrNumDataBases(unsigned int val);
-	
+
 	QGfaMySqlSchemaModel* schemaModel(void);
 
 private:
@@ -319,7 +320,7 @@ private:
     int b2(void) const;
     int b3(void) const;
     QVariant addr(void) const;
-    
+
     void setAddress(const QVariant &addr);
     void setB0(int b);
     void setB1(int b);
@@ -405,7 +406,7 @@ class QDhcp : public QObject
 public:
     explicit QDhcp(IFACE_INET_DHCP &itfd, NotificationSink &notifyer, QObject *pParent = 0);
     virtual ~QDhcp(void);
-    
+
     void setDynamicAddr(const struct in_addr &addr, const struct in_addr &mask, bool bDelete);
 
 private:
@@ -421,11 +422,39 @@ private:
 
 /////////////////////////////////////////////////////////////////////////////
 
+class QManual : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QIPv4Address* ipAddress READ ipAddress CONSTANT)
+    Q_PROPERTY(QIPv4Address* netMask READ netMask CONSTANT)
+
+public:
+    explicit QManual(IFACE_INET_MANUAL &itfm, NotificationSink &notifyer, QObject *pParent = 0);
+    virtual ~QManual(void);
+
+    void setAddr(const struct in_addr &addr, const struct in_addr &mask, bool bDelete);
+
+private:
+    QIPv4Address* ipAddress(void);
+    QIPv4Address* netMask(void);
+
+private:
+	IFACE_INET_MANUAL &m_itfm;
+	struct in_addr m_addr;
+	struct in_addr m_mask;
+	QIPv4Address m_ipAddr;	// dynamic address
+	QIPv4Address m_netMask;	// dynamic mask
+	NotificationSink &m_rNotifyer;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
 class QInet : public QObject
 {
     Q_OBJECT
     Q_PROPERTY(QStatic* stat READ stat CONSTANT)
     Q_PROPERTY(QDhcp* dhcp READ dhcp CONSTANT)
+    Q_PROPERTY(QManual* manu READ manu CONSTANT)
 
 public:
     explicit QInet(ITF_IFACE_BLOCK &ifb, NotificationSink &notifyer, QObject *pParent = 0);
@@ -434,10 +463,12 @@ public:
 public:
     QStatic* stat(void);
     QDhcp* dhcp(void);
+    QManual* manu(void);
 
 private:
     QStatic m_static;
     QDhcp m_dhcp;
+    QManual m_manual;
 	NotificationSink &m_rNotifyer;
 };
 
@@ -475,13 +506,13 @@ public:
 
     inline ITF_IFACE_BLOCK & getIface(void){
     	return m_ifb;}
-    
+
     inline unsigned long getID(void) const {
     	return m_ifb.id;}
-    
+
     inline int getSelCfg(void) const {
 	    return m_selCfg;}
-    
+
     inline const char * getName(void) const {
 	    return m_ifb.cfgName.c_str();}
 
@@ -623,7 +654,7 @@ public:
 
 private slots:
 	void onValueChanged(const QVariant &val);
-	
+
 private:
 	QVector<QGfaNetInterfacesSchemaTreeItem*> m_childItems;
 	QVector<QVariant> m_itemData;
@@ -698,7 +729,7 @@ class QNetworkInterfaces :	public QObject,
     Q_PROPERTY(int itfFilterMethod READ itfFilterMethod WRITE setItfFilterMethod NOTIFY itfFilterMethodChanged)
     Q_PROPERTY(bool ifUpDownInProgress READ ifUpDownInProgress CONSTANT)
     Q_PROPERTY(QGfaNetInterfacesSchemaModel *schemaModel READ schemaModel CONSTANT)
-    
+
 public:
     explicit QNetworkInterfaces(QObject *pParent = 0);
     virtual ~QNetworkInterfaces(void);
@@ -730,19 +761,19 @@ public:
 	virtual void filterPropertyChanged(void) const;
 	virtual void selConfigChanged(QInterface* pi, unsigned int cfgOld, unsigned int cfgNew);
 	virtual int getInterfaceSelConfig(QInterface &ri);
-	
+
 	inline pid_t GetIfUpDownPid(void) const {
 		return m_ifUpDownPid;}
-	
+
 	inline void SetIfUpDownPid(pid_t pid){
 		m_ifUpDownPid = pid;}
-	    
+
 	inline bool GetIfUpDownInProgress(void) const {
 		return m_bIfUpDownInProgress;}
-	    
+
 	inline void SetIfUpDownInProgress(bool bVal){
 		m_bIfUpDownInProgress = bVal;}
-	
+
 	bool SetInterlockedIfUpDownInProgress(void);
 
 signals:
@@ -773,7 +804,7 @@ private:
     static void onIfDownCompleted(int nExitCode, void *pCtx);
     static void onIfRestartCompleted(int nExitCode, void *pCtx);
 	static void onStaticNetmonEvent(unsigned int nEvtType, const void *pData, LPCRT_ATTRIBUTE pAtts, size_t nMaxAtts, void *pParam);
-	
+
 	QGfaNetInterfacesSchemaModel* schemaModel(void);
 
 private:
@@ -855,6 +886,92 @@ private:
 
 /////////////////////////////////////////////////////////////////////////////
 
+class QGfaWlanMonSchemaModel : public QAbstractTableModel
+{
+    Q_OBJECT
+	Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged)
+
+public:
+	typedef struct _WLAN_SCAN_RESULT
+	{
+		_WLAN_SCAN_RESULT(void) {
+			nwID = 0;
+			channel = 0;
+			freqHz = 0;
+			encrypted = false;
+			qualPerc = 0;
+			qualBars = 0;
+		}
+		int32_t nwID;
+		int32_t channel;
+		double freqHz;
+		bool encrypted;
+		bool connected;
+		QString essid;
+		QString macStr;
+		QString freqStr;
+		QString qualStr;
+		QString cipherStr;
+		uint32_t qualPerc;
+		int32_t qualBars;
+	}WLAN_SCAN_RESULT;
+
+	typedef struct WLAN_MON_ROLES
+	{
+		int nRole;
+		const char *pszRoleName;
+	}WLAN_MON_ROLES;
+
+	enum WlanModelRoles
+	{
+	    WLR_ESSID = Qt::UserRole,
+	    WLR_MAC_ADDR_STR,
+	    WLR_NWID,
+	    WLR_FREQ_HZ,
+	    WLR_FREQ_STR,
+	    WLR_CHANNEL,
+	    WLR_MODE_STR,
+	    WLR_ENCRYPTED,
+	    WLR_QUALITY_STR,
+	    WLR_QUALITY_PERC,
+	    WLR_QUALITY_BARS,
+	    WLR_IS_CONNECTED,
+	    WLR_CIPHER_STR,
+	    WLR_LAST
+	};
+	Q_ENUM(WlanModelRoles)
+
+public:
+	explicit QGfaWlanMonSchemaModel(QObject *pParent = NULL);
+	~QGfaWlanMonSchemaModel(void);
+
+	Q_INVOKABLE void startScan(void);
+	Q_INVOKABLE void clearAll(void);
+	Q_INVOKABLE bool setWpaSuppConfig(int cellIndex, QString passphrase);
+	void updateModel(void);
+
+	int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
+	int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
+	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+	QHash<int, QByteArray> roleNames(void) const Q_DECL_OVERRIDE;
+
+private:
+	bool scanning(void) const;
+
+signals:
+	void scanStarted(void);
+	void scanCompleted(void);
+	void scanningChanged(bool isScanning) const;
+
+private:
+	static const WLAN_MON_ROLES m_roles[];
+	std::vector<WLAN_SCAN_RESULT> m_scanRes;
+	CGfaWifiMon m_wlMon;
+	bool m_bScanning;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
 class QGfaSysInfo : public QObject
 {
     Q_OBJECT
@@ -865,6 +982,7 @@ class QGfaSysInfo : public QObject
 	Q_PROPERTY(quint64 memBuffers READ memBuffers NOTIFY memBuffersChanged)
 	Q_PROPERTY(quint64 memCached READ memCached NOTIFY memCachedChanged)
     Q_PROPERTY(QGfaStgDevList *stgDev READ stgDev CONSTANT)
+    Q_PROPERTY(QGfaWlanMonSchemaModel *wifiMon READ wifiMon CONSTANT)
     Q_PROPERTY(QTivaInfo *tivaInfo READ tivaInfo CONSTANT)
     Q_PROPERTY(QNetworkInterfaces *netInterfaceInfo READ netInterfaceInfo CONSTANT)
     Q_PROPERTY(bool bootFromEmmc READ bootFromEmmc NOTIFY bootFromEmmcChanged)
@@ -891,6 +1009,7 @@ private:
 	quint64 memBuffers(void) const;
 	quint64 memCached(void) const;
 	QGfaStgDevList* stgDev(void);
+	QGfaWlanMonSchemaModel* wifiMon(void);
 	QTivaInfo* tivaInfo(void);
 	QNetworkInterfaces* netInterfaceInfo(void);
 	bool bootFromEmmc(void) const;
@@ -912,7 +1031,7 @@ public:
 	inline void partitionAdded(int nIndex, const GFA_SYSINFO_PARTITION &part) {
 		return m_stgDevList.partitionAdded(nIndex, part);
 	}
-		
+
 	inline void partitionRemoved(int nIndex, const GFA_SYSINFO_PARTITION &part) {
 		return m_stgDevList.partitionRemoved(nIndex, part);
 	}
@@ -932,7 +1051,7 @@ public:
 	inline void UpdateSpiInfo(const GFA_SYSINFO_SPI &spi, bool bReset) {
 		return m_tivaInfo.UpdateSpiInfo(spi, bReset);
 	}
-	
+
 	inline void ResetSpiInfo(void) {
 		m_tivaInfo.ResetSpiInfo();
 	}
@@ -946,6 +1065,7 @@ private:
 	quint64 m_nMemBuffers;
 	quint64 m_nMemCached;
 	QGfaStgDevList m_stgDevList;
+	QGfaWlanMonSchemaModel m_wifiMon;
 	QTivaInfo m_tivaInfo;
 	QNetworkInterfaces m_netInterfaces;
 	bool m_bootFromEmmc;
@@ -1009,7 +1129,7 @@ signals:
 public:
 	explicit QGfaAppInfo(int nIndex, QObject *pParent = NULL);
 	virtual ~QGfaAppInfo(void);
-	
+
 	appid_t appId(void) const;
 
 	int state(void) const;
@@ -1020,7 +1140,7 @@ public:
 
 	QString name(void) const;
 	void setName(const QString &val);
-	
+
 	quint64 cycInt(void) const;
 	quint64 cycCur(void) const;
 	quint64 cycMin(void) const;
@@ -1096,7 +1216,7 @@ public:
 	};
 	Q_ENUM(AppStates)
 	static_assert((STATE_INVALID - STATE_NOT_RUNNING) == (GIAS_Invalid - GIAS_StateNotRunning), "enum AppStates does not match enum GfaIpcAppStates!");
-	
+
 	enum AppIndex
 	{
 		APP_INDEX_REMANENT		= GAI_Remanent,
@@ -1162,6 +1282,125 @@ private:
 	struct timespec m_tsLastHeavyLoadUpdate;
 };
 
+/////////////////////////////////////////////////////////////////////////////
+
+class QGfaAppLauncher : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(bool normalExit READ normalExit CONSTANT)
+    Q_PROPERTY(int exitCode READ exitCode CONSTANT)
+    Q_PROPERTY(ProcessError error READ error CONSTANT)
+    Q_PROPERTY(qint64 processId READ processId CONSTANT)
+    Q_PROPERTY(ProcessState state READ state NOTIFY stateChanged)
+    Q_PROPERTY(QString workingDirectory READ workingDirectory WRITE setWorkingDirectory NOTIFY workingDirectoryChanged)
+    Q_PROPERTY(QString program READ program WRITE setProgram NOTIFY programChanged)
+    Q_PROPERTY(QString arguments READ arguments WRITE setArguments NOTIFY argumentsChanged)
+    Q_PROPERTY(QString shell READ shell WRITE setShell NOTIFY shellChanged)
+
+public:
+	enum ProcessState
+	{
+		NotRunning,
+		Starting,
+		Running
+	};
+	Q_ENUM(ProcessState)
+
+	enum ProcessError
+	{
+		FailedToStart,
+		Crashed,
+		Timedout,
+		ReadError,
+		WriteError,
+		UnknownError
+	};
+	Q_ENUM(ProcessError)
+
+	enum ExecReturnFilter
+	{
+		StdOut	= 1,
+		StdErr	= 2,
+		AllOut	= 3
+	};
+	Q_ENUM(ExecReturnFilter)
+
+public:
+	explicit QGfaAppLauncher(QObject *pParent = nullptr);
+	virtual ~QGfaAppLauncher(void);
+
+	static void RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor = 1, int nVerMinor = 0);
+	static QStringList SplitCmdLine(const QString &cmd);
+	static QString EscapeQuotes(const QString &cmd);
+
+public:
+	Q_INVOKABLE void start(const QString &program, const QStringList &arguments);
+	Q_INVOKABLE void start(const QString &program, const QString &arguments = "");
+	Q_INVOKABLE void start(void);
+
+	Q_INVOKABLE QByteArray exec(const QString &program, const QStringList &arguments, ExecReturnFilter rf = AllOut);
+	Q_INVOKABLE QByteArray exec(const QString &program, const QString &arguments = "", ExecReturnFilter rf = AllOut);
+	Q_INVOKABLE QByteArray exec(ExecReturnFilter rf = AllOut);
+
+	Q_INVOKABLE static QByteArray execChain(const QStringList &programs, const QStringList &arguments);
+
+	Q_INVOKABLE QByteArray shellExec(const QStringList &arguments, ExecReturnFilter rf = AllOut);
+	Q_INVOKABLE QByteArray shellExec(const QString &arguments = "", ExecReturnFilter rf = AllOut);
+	Q_INVOKABLE QByteArray shellExecList(const QStringList &strArgList, ExecReturnFilter rf = AllOut);
+
+	Q_INVOKABLE void setStandardInputFile(const QString &fileName);
+	Q_INVOKABLE void setStandardOutputFile(const QString &fileName);
+	Q_INVOKABLE void setStandardErrorFile(const QString &fileName);
+
+	bool normalExit(void) const;
+	int exitCode(void) const;
+	ProcessError error(void) const;
+	qint64 processId(void) const;
+	ProcessState state() const;
+
+	QString workingDirectory() const;
+	void setWorkingDirectory(const QString &dir);
+
+	QString program() const;
+	void setProgram(const QString &program);
+
+	QString arguments() const;
+	void setArguments(const QString &arguments);
+	void setArguments(const QStringList &arguments);
+
+	QString shell() const;
+	void setShell(const QString &shl);
+
+signals:
+	void started(void);
+	void finished(int exitCode, bool normalExit);
+	void standardOutputAvailable(const QByteArray &txt);
+	void standardErrorAvailable(const QByteArray &txt);
+	void stateChanged(ProcessState newState);
+	void errorOccurred(ProcessError error);
+
+	void normalExitChanged(bool val);
+	void workingDirectoryChanged(const QString &dir);
+	void programChanged(const QString &prog);
+	void argumentsChanged(const QString &prog);
+	void shellChanged(const QString &shl);
+
+private slots:
+	void onProcStarted(void);
+	void onProcFinished(int exitCode, QProcess::ExitStatus exitStatus);
+	void onProcReadyReadStandardOutput(void);
+	void onProcReadyReadStandardError(void);
+	void onProcStateChanged(QProcess::ProcessState newState);
+	void onProcErrorOccurred(QProcess::ProcessError error);
+
+private:
+	QProcess m_qProc;
+	bool m_bIsSyncMode;
+	QByteArray m_execOutput;
+	QString m_strShell;
+	ExecReturnFilter m_rf;
+};
+
 /////////////////////////////////////////////////////////////////////////////
 #endif	//	__cplusplus
 #endif	//	!defined(AGD_QAPPCTRL_H__ADD46467_F628_4A07_8844_613598E359DE__INCLUDED_)

+ 371 - 0
src/qapplaunch.cpp

@@ -0,0 +1,371 @@
+#include "qappctrl.h"
+#include "argv_split.h"
+#include "defines.h"
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+QGfaAppLauncher::QGfaAppLauncher(QObject *pParent) :	QObject(pParent),
+														m_qProc(this),
+														m_bIsSyncMode(false),
+														m_strShell(QStringLiteral("bash")),
+														m_rf(AllOut)
+{
+	setObjectName(QStringLiteral("QGfaAppLauncher"));
+	connect(&m_qProc, SIGNAL(started(void)), SLOT(onProcStarted(void)));
+	connect(&m_qProc, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(onProcFinished(int, QProcess::ExitStatus)));
+	connect(&m_qProc, SIGNAL(readyReadStandardOutput(void)), SLOT(onProcReadyReadStandardOutput(void)));
+	connect(&m_qProc, SIGNAL(readyReadStandardError(void)), SLOT(onProcReadyReadStandardError(void)));
+	connect(&m_qProc, SIGNAL(stateChanged(QProcess::ProcessState)), SLOT(onProcStateChanged(QProcess::ProcessState)));
+	connect(&m_qProc, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(onProcErrorOccurred(QProcess::ProcessError)));
+}
+
+QGfaAppLauncher::~QGfaAppLauncher(void)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void QGfaAppLauncher::RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor, int nVerMinor)
+{
+	Q_UNUSED(rEng);
+	qmlRegisterType<QGfaAppLauncher>("com.gfa.ipc.applaunch", nVerMajor, nVerMinor, "GfaAppLauncher");
+}
+
+QStringList QGfaAppLauncher::SplitCmdLine(const QString &cmd)
+{
+	QStringList args;
+	argv_split parser;
+	const char **argv = parser.parse(cmd.toStdString());
+	if(argv)
+	{
+		while(*argv)
+		{
+			args << *argv;
+			++argv;
+		}
+	}
+	return args;
+}
+
+QString QGfaAppLauncher::EscapeQuotes(const QString &str)
+{
+	QChar c, p = L'\0';
+	QString s;
+	for(int i = 0; i < str.size(); ++i)
+	{
+		c = str[i];
+
+		if((c == L'\"') && (p != L'\\'))
+		{
+			s += L'\\';
+		}
+		s += c;
+		p = c;
+	}
+	return s;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void QGfaAppLauncher::onProcStarted(void)
+{
+	emit started();
+}
+
+void QGfaAppLauncher::onProcFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+	emit finished(exitCode, exitStatus == QProcess::NormalExit);
+}
+
+void QGfaAppLauncher::onProcReadyReadStandardOutput(void)
+{
+	QByteArray arr = m_qProc.readAllStandardOutput();
+	if(m_bIsSyncMode)
+	{
+		if(m_rf | StdOut)
+			m_execOutput.append(arr);
+	}
+	else
+		emit standardOutputAvailable(arr);
+}
+
+void QGfaAppLauncher::onProcReadyReadStandardError(void)
+{
+	QByteArray arr = m_qProc.readAllStandardError();
+	if(m_bIsSyncMode)
+	{
+		if(m_rf | StdErr)
+			m_execOutput.append(arr);
+	}
+	else
+		emit standardErrorAvailable(arr);
+}
+
+void QGfaAppLauncher::onProcStateChanged(QProcess::ProcessState newState)
+{
+	emit stateChanged((ProcessState)newState);
+}
+
+void QGfaAppLauncher::onProcErrorOccurred(QProcess::ProcessError error)
+{
+	emit errorOccurred((ProcessError)error);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+QString QGfaAppLauncher::arguments() const
+{
+	return m_qProc.arguments().join(QStringLiteral(" "));
+}
+
+void QGfaAppLauncher::setArguments(const QStringList &arguments)
+{
+	QStringList sl = m_qProc.arguments();
+	
+	if(sl != arguments)
+	{
+		m_qProc.setArguments(arguments);
+		emit argumentsChanged(arguments.join(QStringLiteral(" ")));
+	}
+}
+
+void QGfaAppLauncher::setArguments(const QString &arguments)
+{
+	QStringList sl = SplitCmdLine(arguments);
+	setArguments(sl);
+}
+
+QString QGfaAppLauncher::program() const
+{
+	return m_qProc.program();
+}
+
+void QGfaAppLauncher::setProgram(const QString &program)
+{
+	QString prog = m_qProc.program();
+	if(prog != program)
+	{
+		m_qProc.setProgram(program);
+		emit programChanged(program);
+	}
+}
+
+bool QGfaAppLauncher::normalExit(void) const
+{
+	return m_qProc.exitStatus() == QProcess::NormalExit;
+}
+
+int QGfaAppLauncher::exitCode(void) const
+{
+	return m_qProc.exitCode();
+}
+
+QGfaAppLauncher::ProcessError QGfaAppLauncher::error(void) const
+{
+	return (ProcessError)m_qProc.error();
+}
+
+qint64 QGfaAppLauncher::processId(void) const
+{
+	return m_qProc.processId();
+}
+
+QGfaAppLauncher::ProcessState QGfaAppLauncher::state() const
+{
+	return (ProcessState)m_qProc.state();
+}
+
+QString	QGfaAppLauncher::workingDirectory() const
+{
+	return m_qProc.workingDirectory();
+}
+
+void QGfaAppLauncher::setWorkingDirectory(const QString &dir)
+{
+	QString wd = m_qProc.workingDirectory();
+	if(wd != dir)
+	{
+		m_qProc.setWorkingDirectory(dir);
+		emit workingDirectoryChanged(dir);
+	}
+}
+
+void QGfaAppLauncher::setStandardInputFile(const QString &fileName)
+{
+	m_qProc.setStandardInputFile(fileName);
+}
+
+void QGfaAppLauncher::setStandardOutputFile(const QString &fileName)
+{
+	m_qProc.setStandardOutputFile(fileName);
+}
+
+void QGfaAppLauncher::setStandardErrorFile(const QString &fileName)
+{
+	m_qProc.setStandardErrorFile(fileName);
+}
+
+QString QGfaAppLauncher::shell() const
+{
+	return m_strShell;
+}
+
+void QGfaAppLauncher::setShell(const QString &shl)
+{
+	if(m_strShell != shl)
+	{
+		m_strShell = shl;
+		emit shellChanged(shl);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void QGfaAppLauncher::start(const QString &program, const QStringList &arguments)
+{
+	m_qProc.start(program, arguments);
+}
+
+void QGfaAppLauncher::start(const QString &program, const QString &arguments)
+{
+	QStringList sl = SplitCmdLine(arguments);
+	start(program, sl);
+}
+
+void QGfaAppLauncher::start(void)
+{
+	m_qProc.start();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+QByteArray QGfaAppLauncher::exec(const QString &program, const QStringList &arguments, ExecReturnFilter rf)
+{
+	m_bIsSyncMode = true;
+	m_execOutput.clear();
+	m_rf = rf;
+	m_qProc.start(program, arguments);
+	m_qProc.waitForFinished();
+	m_bIsSyncMode = false;
+	return m_execOutput;
+}
+
+QByteArray QGfaAppLauncher::exec(const QString &program, const QString &arguments, ExecReturnFilter rf)
+{
+	QStringList sl = SplitCmdLine(arguments);
+	return exec(program, sl, rf);
+}
+
+QByteArray QGfaAppLauncher::exec(ExecReturnFilter rf)
+{
+	m_bIsSyncMode = true;
+	m_execOutput.clear();
+	m_rf = rf;
+	m_qProc.start();
+	m_qProc.waitForFinished();
+	m_bIsSyncMode = false;
+	return m_execOutput;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+QByteArray QGfaAppLauncher::shellExec(const QStringList &arguments, ExecReturnFilter rf)
+{
+	QStringList sl;
+	sl << "-c";
+	sl << arguments.join(QStringLiteral(" "));
+	return exec(m_strShell, sl, rf);
+}
+
+QByteArray QGfaAppLauncher::shellExec(const QString &arguments, ExecReturnFilter rf)
+{
+	QStringList sl = SplitCmdLine(arguments);
+	return shellExec(sl, rf);
+}
+
+QByteArray QGfaAppLauncher::shellExecList(const QStringList &strArgList, ExecReturnFilter rf)
+{
+	m_bIsSyncMode = true;
+	m_execOutput.clear();
+	m_rf = rf;
+
+	for(int i = 0; i < strArgList.count(); ++i)
+	{
+		const QString &arg = strArgList.at(i);
+		QStringList sl;
+		sl << "-c";
+		sl << arg;
+		m_qProc.start(m_strShell, sl);
+		m_qProc.waitForFinished();
+		
+		if(!normalExit())
+			break;
+	}
+
+	m_bIsSyncMode = false;
+	return m_execOutput;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+QByteArray QGfaAppLauncher::execChain(const QStringList &programs, const QStringList &arguments)
+{
+	QProcess *pPrevProc = nullptr;
+	QList<QProcess*> procs;
+
+	for(int i = 0; i < programs.count(); ++i)
+	{
+		QProcess *pNewProc = new QProcess(nullptr);
+		pNewProc->setProgram(programs.at(i));
+
+		if(arguments.count() > i)
+		{
+			const QString &cmd = arguments.at(i);
+			if(cmd.length() > 0)
+			{
+				QStringList args = SplitCmdLine(cmd);
+				pNewProc->setArguments(args);
+			}
+		}
+
+		if(pPrevProc)
+			pPrevProc->setStandardOutputProcess(pNewProc);
+		procs.push_back(pNewProc);
+		pPrevProc = pNewProc;
+	}
+
+	QByteArray ret;
+	QProcess *proc = nullptr;
+
+	for(int i = 0; i < procs.count(); ++i)
+	{
+		proc = procs.at(i);
+		proc->start();
+	}
+
+	for(int i = 0; i < procs.count(); ++i)
+	{
+		proc = procs.at(i);
+		proc->waitForFinished();
+		if(proc->exitStatus() == QProcess::CrashExit)
+		{
+			ret.append(proc->readAllStandardError());
+			proc = nullptr;
+		}
+	}
+	
+	if(proc)
+		ret.append(proc->readAllStandardOutput());
+
+	for(int i = 0; i < procs.count(); ++i)
+	{
+		proc = procs.at(i);
+		delete proc;
+	}
+	
+	return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////

+ 80 - 233
src/qnetworkinfo.cpp

@@ -24,9 +24,9 @@ typedef const SCHEMA_MODEL_ROLES *LPCSCHEMA_MODEL_ROLES;
 
 static const SCHEMA_MODEL_ROLES g_roles[] =
 {
-	{QGfaMySqlSchemaModel::SMR_Name,			"name"},
-	{QGfaMySqlSchemaModel::SMR_Info,			"infoRaw"},
-	{QGfaMySqlSchemaModel::SMR_InfoFormatted,	"infoFormatted"}
+	{QGfaNetInterfacesSchemaModel::SMR_Name,			"name"},
+	{QGfaNetInterfacesSchemaModel::SMR_Info,			"infoRaw"},
+	{QGfaNetInterfacesSchemaModel::SMR_InfoFormatted,	"infoFormatted"}
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -368,227 +368,7 @@ QObject* QGfaNetInterfacesSchemaModel::getChildObject(QObject *parent, std::vect
 	return obj;
 }
 
-#if 0
-void QGfaNetInterfacesSchemaModel::setModelData(LPETC_NETWORK_INTERFACES pnif)
-{
-	int i;
-	beginResetModel();
-	m_pRootItem->clear();
-
-	for(auto itfb = pnif->ibl.begin(); itfb != pnif->ibl.end(); ++itfb)
-	{
-		const ITF_IFACE_BLOCK &ifb = *itfb;
-		QGfaNetInterfacesSchemaTreeItem *pNiTi = new QGfaNetInterfacesSchemaTreeItem(ifb.cfgName.c_str(), (quint32)ifb.method, ::GetIfaceMethodStr(ifb.method), m_pRootItem);
-		
-		if(ifb.proto != IFP_Unknown)
-		{
-			const char *pszProto;
-			switch(ifb.proto)
-			{
-			case IFP_Inet:
-				pszProto = "IPv4";
-				break;
-			case IFP_Inet6:
-				pszProto = "IPv6";
-				break;
-			default:
-				pszProto = ::GetIfaceProtoStr(ifb.proto);
-				break;
-			}
-
-			QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Protocol", pszProto, QVariant(), pNiTi);
-			pNiTi->appendChild(pTmpTi);
-		}
-
-		if(!ifb.inherits.empty())
-		{
-			QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Inherits", ifb.inherits.c_str(), QVariant(), pNiTi);
-			pNiTi->appendChild(pTmpTi);
-		}
-		
-		{
-			QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Up", ifb.up, ifb.up ? "yes" : "no", pNiTi);
-			pNiTi->appendChild(pTmpTi);
-		}
-		
-		{
-			QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Running", ifb.running, ifb.running ? "yes" : "no", pNiTi);
-			pNiTi->appendChild(pTmpTi);
-		}
-
-		if(ifb.method == IFM_Static)
-		{
-			const IFACE_INET_STATIC &inet4s = ifb.inet4s;
-
-			if(inet4s.addr.s_addr != INADDR_ANY)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Address", (quint32)inet4s.addr.s_addr, ::inet_ntoa(inet4s.addr), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4s.netmask.s_addr != INADDR_ANY)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Netmask", (quint32)inet4s.netmask.s_addr, ::inet_ntoa(inet4s.netmask), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4s.gate.s_addr != INADDR_ANY)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Gateway", (quint32)inet4s.gate.s_addr, ::inet_ntoa(inet4s.gate), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4s.bcast.s_addr != INADDR_ANY)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Broadcast", (quint32)inet4s.bcast.s_addr, ::inet_ntoa(inet4s.bcast), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4s.pointopoint.s_addr != INADDR_ANY)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("PointToPoint", (quint32)inet4s.pointopoint.s_addr, ::inet_ntoa(inet4s.pointopoint), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			for(i = 0; i < (int)_countof(inet4s.namesvr); ++i)
-			{
-				if(inet4s.namesvr[i].s_addr)
-				{
-					char szName[32];
-					sprintf(szName, "DNS %d", i + 1);
-					QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem(szName, (quint32)inet4s.namesvr[i].s_addr, ::inet_ntoa(inet4s.namesvr[i]), pNiTi);
-					pNiTi->appendChild(pTmpTi);
-				}
-			}
-
-			if(inet4s.metric != -1)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Metric", (quint32)inet4s.metric, QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4s.mtu != -1)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("MTU", (quint32)inet4s.mtu, QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4s.hwaddr.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("HW-Address", inet4s.hwaddr.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4s.scope.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("HW-Address", inet4s.scope.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			i = 0;
-			for(auto it = inet4s.dnss.begin(); it != inet4s.dnss.end(); ++it)
-			{
-				const std::string &s = *it;
-				if(!s.empty())
-				{
-					char szName[32];
-					sprintf(szName, "DNSS %d", i + 1);
-					QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem(szName, s.c_str(), QVariant(), pNiTi);
-					pNiTi->appendChild(pTmpTi);
-				}
-			}
-		}
-		else if(ifb.method == IFM_Dhcp)
-		{
-			const IFACE_INET_DHCP &inet4d = ifb.inet4d;
-
-			if(inet4d.leasetime != -1)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Lease time", (qint32)inet4d.leasetime, QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4d.leasehours != -1)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Lease hours", (qint32)inet4d.leasehours, QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(inet4d.metric != -1)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Metric", (quint32)inet4d.metric, QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4d.hostname.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Hostname", inet4d.hostname.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4d.vendor.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Vendor", inet4d.vendor.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4d.client.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("Client", inet4d.client.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4d.hwaddr.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("HW-Address", inet4d.hwaddr.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-		}
-		else if(ifb.method == IFM_Manual)
-		{
-			const IFACE_INET_MANUAL &inet4m = ifb.inet4m;
-
-			if(inet4m.mtu != -1)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("MTU", (quint32)inet4m.mtu, QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-
-			if(!inet4m.hwaddr.empty())
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem("HW-Address", inet4m.hwaddr.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-		}
-
-		for(auto it = ifb.cmds.begin(); it != ifb.cmds.end(); ++it)
-		{
-			const IFACE_COMMAND &cmd = *it;
-			if(cmd.cmd != IFC_Unknown)
-			{
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem(::GetIfaceCommandsStr(cmd.cmd), cmd.args.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-		}
-
-		for(auto it = ifb.unparsed.begin(); it != ifb.unparsed.end(); ++it)
-		{
-			const std::string &s = *it;
-			if(!s.empty())
-			{
-				char szName[32];
-				sprintf(szName, "CMD %d", i + 1);
-				QGfaNetInterfacesSchemaTreeItem *pTmpTi = new QGfaNetInterfacesSchemaTreeItem(szName, s.c_str(), QVariant(), pNiTi);
-				pNiTi->appendChild(pTmpTi);
-			}
-		}
-
-		m_pRootItem->appendChild(pNiTi);
-	}
-
-	endResetModel();
-}
-#endif
+/////////////////////////////////////////////////////////////////////////////
 
 void QGfaNetInterfacesSchemaModel::setModelData(QObject *pifs)
 {
@@ -801,6 +581,24 @@ void QGfaNetInterfacesSchemaModel::setModelData(QObject *pifs)
 			{
 				if(af == QInterface::AF_Inet)
 				{
+					QObject *pManu, *pAddr;
+					
+					if((pManu = getChildObject(pif, {"inet", "manu"})))
+					{
+						if((pAddr = getChildObject(pManu, {"ipAddress"})))
+						{
+							pTmpTi = new QGfaNetInterfacesSchemaTreeItem(*this, "Address", pAddr->property("addr"), &QGfaNetInterfacesSchemaModel::ipV4String, pNiTi);
+							QObject::connect(pAddr, SIGNAL(addrChanged(const QVariant&)), pTmpTi, SLOT(onValueChanged(const QVariant&)));
+							pNiTi->appendChild(pTmpTi);
+						}
+
+						if((pAddr = getChildObject(pManu, {"netMask"})))
+						{
+							pTmpTi = new QGfaNetInterfacesSchemaTreeItem(*this, "Netmask", pAddr->property("addr"), &QGfaNetInterfacesSchemaModel::ipV4String, pNiTi);
+							QObject::connect(pAddr, SIGNAL(addrChanged(const QVariant&)), pTmpTi, SLOT(onValueChanged(const QVariant&)));
+							pNiTi->appendChild(pTmpTi);
+						}
+					}
 				}
 			}
 
@@ -998,7 +796,6 @@ bool QNetworkInterfaces::initialize(void)
 			m_interfaces.append(new QInterface(ibl, static_cast<NotificationSink&>(*this), this));
 		}
 
-//		m_netInterfacesSchemaModel.setModelData(&m_eni);
 		m_netInterfacesSchemaModel.setModelData(this);
 
 		emit interfacesChanged();
@@ -1017,7 +814,6 @@ bool QNetworkInterfaces::save(void)
 	if(	::WriteEtcNetworkInterfaces(m_eni, NULL) &&
 		initialize())
 	{
-//		m_netInterfacesSchemaModel.setModelData(&m_eni);
 		m_netInterfacesSchemaModel.setModelData(this);
 		return true;
 	}
@@ -1033,7 +829,6 @@ bool QNetworkInterfaces::saveAs(const QString &path)
 	if(	::WriteEtcNetworkInterfaces(m_eni, pszPath) &&
 		initialize())
 	{
-//		m_netInterfacesSchemaModel.setModelData(&m_eni);
 		m_netInterfacesSchemaModel.setModelData(this);
 		return true;
 	}
@@ -1045,7 +840,6 @@ bool QNetworkInterfaces::reload(void)
     m_netInterfacesSchemaModel.clearAll();
 	if(initialize())
 	{
-//		m_netInterfacesSchemaModel.setModelData(&m_eni);
 		m_netInterfacesSchemaModel.setModelData(this);
 	    return true;
 	}
@@ -1525,8 +1319,11 @@ void QNetworkInterfaces::onNetmonEvent(unsigned int nEvtType, const void *pData,
 
 void QNetworkInterfaces::onStaticNetmonEvent(unsigned int nEvtType, const void *pData, LPCRT_ATTRIBUTE pAtts, size_t nMaxAtts, void *pParam)
 {
-	QNetworkInterfaces *pThis = (QNetworkInterfaces*)pParam;
-	pThis->onNetmonEvent(nEvtType, pData, pAtts, nMaxAtts);
+	if(pParam)
+	{
+		QNetworkInterfaces *pThis = static_cast<QNetworkInterfaces*>(pParam);
+		pThis->onNetmonEvent(nEvtType, pData, pAtts, nMaxAtts);
+	}
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -1928,6 +1725,7 @@ void QInterface::onNetmonEvent(unsigned int nEvtType, const void *pData, LPCRT_A
 	{
 	case RTM_DELLINK:
 		bDelLink = true;
+		// FALLTHRU
 	case RTM_NEWLINK:
 		if(af() == AF_Inet)
 		{
@@ -1966,6 +1764,7 @@ void QInterface::onNetmonEvent(unsigned int nEvtType, const void *pData, LPCRT_A
 		break;
 	case RTM_DELADDR:
 		bDelAddr = true;
+		// FALLTHRU
 	case RTM_NEWADDR:
 		if((af() == AF_Inet))
 		{
@@ -1973,12 +1772,23 @@ void QInterface::onNetmonEvent(unsigned int nEvtType, const void *pData, LPCRT_A
 
 			if((am.ifa_family == AF_INET) && (nMaxAtts > IFA_LOCAL))
 			{
-				if(method() == IM_Dhcp)
+				switch(method())
+				{
+				case IM_Dhcp:
 				{
 					const struct in_addr &addr = *(const struct in_addr*)pAtts[IFA_LOCAL].pData;
 					const struct in_addr mask = {_PREFIX_TO_MASK(am.ifa_prefixlen)};
 					m_inet.dhcp()->setDynamicAddr(addr, mask, bDelAddr);
 				}
+					break;
+				case IM_Manual:
+				{
+					const struct in_addr &addr = *(const struct in_addr*)pAtts[IFA_LOCAL].pData;
+					const struct in_addr mask = {_PREFIX_TO_MASK(am.ifa_prefixlen)};
+					m_inet.manu()->setAddr(addr, mask, bDelAddr);
+					break;
+				}
+				}
 			}
 		}
 		break;
@@ -1994,6 +1804,7 @@ void QInterface::onNetmonEvent(unsigned int nEvtType, const void *pData, LPCRT_A
 QInet::QInet(ITF_IFACE_BLOCK &ifb, NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
 																					m_static(ifb.inet4s, notifyer, this),
 																					m_dhcp(ifb.inet4d, notifyer, this),
+																					m_manual(ifb.inet4m, notifyer, this),
 																					m_rNotifyer(notifyer)
 {
 	setObjectName("QInet");
@@ -2013,6 +1824,11 @@ QDhcp* QInet::dhcp(void)
 	return &m_dhcp;
 }
 
+QManual* QInet::manu(void)
+{
+	return &m_manual;
+}
+
 /////////////////////////////////////////////////////////////////////////////
 
 QStatic::QStatic(IFACE_INET_STATIC &itfs, NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
@@ -2174,6 +1990,39 @@ QIPv4Address* QDhcp::netMask(void)
 
 /////////////////////////////////////////////////////////////////////////////
 
+QManual::QManual(IFACE_INET_MANUAL &itfm, NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
+																							m_itfm(itfm),
+																							m_addr{0},
+																							m_mask{0},
+																							m_ipAddr(m_addr, notifyer, this),
+																							m_netMask(m_mask, notifyer, this, _IsValidNetmask),
+																							m_rNotifyer(notifyer)
+{
+	setObjectName("QManual");
+}
+
+QManual::~QManual(void)
+{
+}
+
+void QManual::setAddr(const struct in_addr &addr, const struct in_addr &mask, bool bDelete)
+{
+	m_ipAddr.setAddr(bDelete ? 0.0 : addr.s_addr);
+	m_netMask.setAddr(bDelete ? 0.0 : mask.s_addr);
+}
+
+QIPv4Address* QManual::ipAddress(void)
+{
+	return &m_ipAddr;
+}
+
+QIPv4Address* QManual::netMask(void)
+{
+	return &m_netMask;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 QIPv4Address::QIPv4Address(struct in_addr &addr, NotificationSink &notifyer, QObject *pParent, PFN_ADDRESS_VALIDATOR pfnAddrValidator) :	QObject(pParent),
 																																			m_addr(addr),
 																																			m_pfnAddrValidator(pfnAddrValidator),
@@ -2217,7 +2066,6 @@ int QIPv4Address::b3(void) const
 
 QVariant QIPv4Address::addr(void) const
 {
-//	return ::ntohl(m_addr.s_addr);
 	return m_addr.s_addr;
 }
 
@@ -2324,7 +2172,6 @@ void QIPv4Address::setB3(int b)
 
 void QIPv4Address::setAddr(const QVariant &val)
 {
-//	unsigned int addr = ::htonl(val.toUInt());
 	unsigned int addr = val.toUInt();
 
 	if(m_addr.s_addr != addr)

+ 6 - 5
src/qsysinfo.cpp

@@ -52,7 +52,7 @@ QGfaStgDevList::QGfaStgDevList(QObject *pParent) : 	QAbstractTableModel(pParent)
 {
 	memset(&m_stgDevShadowCpy, 0, sizeof(m_stgDevShadowCpy));
     setObjectName("QGfaStgDevList");
-	static_assert(_countof(m_roles) == (SDR_PARTFSUSED_FMT - SDR_DISKNAME + 1), "enum StgDevRoles does not match array STG_DEV_ROLES!");
+	static_assert(_countof(m_roles) == (SDR_PARTFSUSED_FMT - SDR_DISKNAME + 1), "enum StgDevRoles does not match array QGfaStgDevList::m_roles!");
 }
 
 QGfaStgDevList::~QGfaStgDevList(void)
@@ -315,10 +315,6 @@ void QGfaStgDevList::updatePartitionInfo(const GFA_SYSINFO_STORAGE_DEVICE_MAP &s
 	endResetModel();
 }
 
-/*void QGfaStgDevList::updateModel(const GFA_SYSINFO_STORAGE_DEVICE_MAP &sdm)
-{
-}*/
-
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
@@ -667,6 +663,11 @@ QGfaStgDevList* QGfaSysInfo::stgDev(void)
 	return &m_stgDevList;
 }
 
+QGfaWlanMonSchemaModel* QGfaSysInfo::wifiMon(void)
+{
+	return &m_wifiMon;
+}
+
 QTivaInfo* QGfaSysInfo::tivaInfo(void)
 {
 	return &m_tivaInfo;

+ 194 - 0
src/qwlaninfo.cpp

@@ -0,0 +1,194 @@
+#include "qappctrl.h"
+#include "defines.h"
+#include "helpers.h"
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _countof
+#define _countof(a)					(sizeof(a) / sizeof(*a))
+#endif	//	_countof
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+const QGfaWlanMonSchemaModel::WLAN_MON_ROLES QGfaWlanMonSchemaModel::m_roles[] =
+{
+	{WLR_ESSID,			"EssID"},
+	{WLR_MAC_ADDR_STR,	"MacAddrStr"},
+	{WLR_NWID,			"NwID"},
+	{WLR_FREQ_HZ,		"FreqHz"},
+	{WLR_FREQ_STR,		"FreqStr"},
+	{WLR_CHANNEL,		"Channel"},
+	{WLR_MODE_STR,		"ModeStr"},
+	{WLR_ENCRYPTED,		"Encrypted"},
+	{WLR_QUALITY_STR,	"QualStr"},
+	{WLR_QUALITY_PERC,	"QualPerc"},
+	{WLR_QUALITY_BARS,	"QualBars"},
+	{WLR_IS_CONNECTED,	"Connected"},
+	{WLR_CIPHER_STR,	"CipherStr"}
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+QGfaWlanMonSchemaModel::QGfaWlanMonSchemaModel(QObject *pParent) : 	QAbstractTableModel(pParent), m_bScanning(false)
+{
+    setObjectName("QGfaWlanMonSchemaModel");
+	static_assert(_countof(m_roles) == (WLR_LAST - WLR_ESSID), "enum WlanModelRoles does not match array 'QGfaWlanMonSchemaModel::m_roles[]'!");
+}
+
+QGfaWlanMonSchemaModel::~QGfaWlanMonSchemaModel(void)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int QGfaWlanMonSchemaModel::rowCount(const QModelIndex &parent) const
+{
+	Q_UNUSED(parent);
+	return (int)m_scanRes.size();
+}
+
+int QGfaWlanMonSchemaModel::columnCount(const QModelIndex &parent) const
+{
+	Q_UNUSED(parent);
+	return (int)_countof(m_roles);
+}
+
+QVariant QGfaWlanMonSchemaModel::data(const QModelIndex &index, int role) const
+{
+	if(!index.isValid())
+		return QVariant();
+
+	QVariant val;
+	int nIndex = index.row();
+	const WLAN_SCAN_RESULT &wsr = m_scanRes[nIndex];
+
+	switch(role)
+	{
+	case WLR_ESSID:
+		val = wsr.essid;
+		break;
+	case WLR_MAC_ADDR_STR:
+		val = wsr.macStr;
+		break;
+	case WLR_NWID:
+		val = wsr.nwID;
+		break;
+	case WLR_FREQ_HZ:
+		val = wsr.freqHz;
+		break;
+	case WLR_FREQ_STR:
+		val = wsr.freqStr;
+		break;
+	case WLR_CHANNEL:
+		val = wsr.channel;
+		break;
+	case WLR_MODE_STR:
+		break;
+	case WLR_ENCRYPTED:
+		val = wsr.encrypted;
+		break;
+	case WLR_QUALITY_STR:
+		val = wsr.qualStr;
+		break;
+	case WLR_QUALITY_PERC:
+		val = wsr.qualPerc;
+		break;
+	case WLR_QUALITY_BARS:
+		val = wsr.qualBars;
+		break;
+	case WLR_IS_CONNECTED:
+		val = wsr.connected;
+		break;
+	case WLR_CIPHER_STR:
+		val = wsr.cipherStr;
+		break;
+	}
+
+	return val;
+}
+
+QHash<int, QByteArray> QGfaWlanMonSchemaModel::roleNames(void) const
+{
+	QHash<int, QByteArray> roles;
+	
+	for(size_t i = 0; i < _countof(m_roles); ++i)
+	{
+		roles[m_roles[i].nRole] = m_roles[i].pszRoleName;
+	}
+
+	return roles;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void QGfaWlanMonSchemaModel::startScan(void)
+{
+	if(m_wlMon.IwSocketOpen())
+	{
+		m_bScanning = true;
+		emit scanningChanged(m_bScanning);
+		emit scanStarted();
+		m_wlMon.IwEnum();
+		updateModel();
+		m_bScanning = false;
+		emit scanningChanged(m_bScanning);
+		emit scanCompleted();
+		m_wlMon.IwSocketClose();
+	}
+}
+
+bool QGfaWlanMonSchemaModel::scanning(void) const
+{
+	return m_bScanning;
+}
+
+void QGfaWlanMonSchemaModel::updateModel(void)
+{
+	beginResetModel();
+	m_scanRes.clear();
+	uint32_t nCells = m_wlMon.GetCountCells();
+	for(uint32_t i = 0; i < nCells; ++i)
+	{
+		WLAN_SCAN_RESULT wsr;
+
+		wsr.nwID	= m_wlMon.GetNWID(i);
+		wsr.channel	= m_wlMon.GetChannel(i);
+		wsr.freqHz	= m_wlMon.GetFreqHz(i);
+		wsr.encrypted = m_wlMon.GetEncodingEnabled(i);
+		wsr.freqStr	= QString::fromStdString(m_wlMon.GetFreqStr(i));
+		wsr.essid	= QString::fromStdString(m_wlMon.GetESSID(i));
+		wsr.macStr	= QString::fromStdString(m_wlMon.GetMACAddrStr(i));
+		wsr.qualStr = QString::fromStdString(m_wlMon.GetQualityStr(i));
+		wsr.qualPerc = m_wlMon.GetQualityPercent(i);
+		wsr.qualBars = m_wlMon.GetQualityBars(i);
+		wsr.connected = m_wlMon.GetConnected(i);
+		wsr.cipherStr	= QString::fromStdString(m_wlMon.GetWPAPairwiseCiphers(i));
+
+		m_scanRes.push_back(wsr);
+
+//		QModelIndex qi = createIndex(i, 0);
+//		emit dataChanged(qi, qi, {WLR_NWID, WLR_CHANNEL, WLR_FREQ_HZ, WLR_ENCRYPTED, WLR_FREQ_STR, WLR_ESSID, WLR_MAC_ADDR_STR, WLR_QUALITY_BARS});
+	}
+	endResetModel();
+}
+
+void QGfaWlanMonSchemaModel::clearAll(void)
+{
+	int nLast = m_scanRes.size() - 1;
+	if(nLast >= 0)
+	{
+		QModelIndex parent = QModelIndex();
+		emit beginRemoveRows(parent, 0, nLast);
+		m_scanRes.clear();
+		emit endRemoveRows();
+	}
+}
+
+bool QGfaWlanMonSchemaModel::setWpaSuppConfig(int cellIndex, QString passphrase)
+{
+	return m_wlMon.SetWpaSuppConfig(cellIndex, passphrase.toStdString().c_str());
+}