├── test.txt ├── installer ├── winConfig.xml ├── create-dmg │ ├── .gitignore │ ├── sample │ ├── builder │ │ └── create-dmg.builder │ ├── LICENSE │ ├── support │ │ ├── template.applescript │ │ └── dmg-license.py │ ├── README.md │ └── create-dmg.sh ├── debug-build.txt ├── debug-build.txtclear ├── depends │ ├── update.bat │ ├── libstdc++-6.dll │ ├── libgcc_s_dw2-1.dll │ └── libwinpthread-1.dll ├── config │ ├── .DS_Store │ ├── osxConfig.xml │ ├── winConfig.xml │ ├── winConfigTemplate.xml │ └── installScript.qs ├── packages │ ├── com.digilent.agent │ │ ├── data │ │ │ ├── update.bat │ │ │ └── translations │ │ │ │ ├── qt_ca.qm │ │ │ │ ├── qt_cs.qm │ │ │ │ ├── qt_de.qm │ │ │ │ ├── qt_en.qm │ │ │ │ ├── qt_fi.qm │ │ │ │ ├── qt_fr.qm │ │ │ │ ├── qt_he.qm │ │ │ │ ├── qt_hu.qm │ │ │ │ ├── qt_it.qm │ │ │ │ ├── qt_ja.qm │ │ │ │ ├── qt_ko.qm │ │ │ │ ├── qt_lv.qm │ │ │ │ ├── qt_pl.qm │ │ │ │ ├── qt_ru.qm │ │ │ │ ├── qt_sk.qm │ │ │ │ └── qt_uk.qm │ │ └── meta │ │ │ ├── packageTemplate.xml │ │ │ ├── license.txt │ │ │ └── installScript.qs │ └── com.digilent.waveformsliveofflinesupport │ │ ├── .DS_Store │ │ └── meta │ │ ├── installScript.qs │ │ ├── package.xml │ │ └── license.txt ├── digilent-agent.ini ├── build.sh ├── debian │ └── control ├── debBuildScript.sh ├── osxBuildScript.sh └── winBuildScript.sh ├── description-pak ├── qt.conf ├── digilent-agent.rc ├── digilent-agent ├── lib ├── .DS_Store └── digilent │ ├── .DS_Store │ └── qtHttp │ ├── httpClient.h │ └── httpClient.cpp ├── src ├── .DS_Store ├── httpServer │ ├── core │ │ ├── httpglobal.cpp │ │ ├── httpglobal.h │ │ ├── httprequesthandler.cpp │ │ ├── httpserver.pri │ │ ├── httprequesthandler.h │ │ ├── staticfilecontroller.h │ │ ├── httplistener.cpp │ │ ├── httplistener.h │ │ ├── httpconnectionhandlerpool.h │ │ ├── httpsessionstore.h │ │ ├── httpsession.h │ │ ├── httpconnectionhandler.h │ │ ├── httpcookie.h │ │ ├── httpsessionstore.cpp │ │ ├── httpsession.cpp │ │ ├── httpresponse.h │ │ ├── httpresponse.cpp │ │ ├── httpconnectionhandlerpool.cpp │ │ ├── httpcookie.cpp │ │ ├── staticfilecontroller.cpp │ │ └── httprequest.h │ ├── debugController.cpp │ ├── debugController.h │ ├── httpRouter.h │ ├── agentConfigCtrl.h │ └── httpRouter.cpp ├── wflDevice │ ├── wflDevice.cpp │ ├── wflDevice.h │ ├── wflSerialDevice.h │ └── wflSerialDevice.cpp ├── core │ ├── comboBoxEventFilter.cpp │ ├── comboBoxEventFilter.h │ ├── utils │ │ ├── runGuard.h │ │ └── runGuard.cpp │ └── agent.h ├── mainWindow.h ├── mainWindow.cpp └── main.cpp ├── images ├── .DS_Store ├── icon.icns ├── icon.ico ├── icon.png ├── refresh-arrow.png ├── icon.iconset │ ├── icon_16x16.png │ ├── icon_32x32.png │ ├── icon_128x128.png │ ├── icon_16x16@2x.png │ ├── icon_256x256.png │ ├── icon_32x32@2x.png │ ├── icon_512x512.png │ ├── icon_128x128@2x.png │ ├── icon_256x256@2x.png │ └── icon_512x512@2x.png └── digilent-agent-dmg-background.png ├── www ├── index.html └── files │ └── index.html ├── xcshareddata ├── .DS_Store └── xcschemes │ └── digilent-agent.xcscheme ├── digilent-agent.iconset ├── icon_16x16.png ├── icon_32x32.png ├── icon_128x128.png ├── icon_256x256.png ├── icon_512x512.png ├── icon_128x128@2x.png ├── icon_16x16@2x.png ├── icon_256x256@2x.png ├── icon_32x32@2x.png └── icon_512x512@2x.png ├── mainWindow.qrc ├── digilent-agent.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── digilent-agent.xcscmblueprint └── xcshareddata │ └── xcschemes │ └── digilent-agent.xcscheme ├── .gitmodules ├── digilent-agent.entitlements ├── project.xcworkspace └── xcshareddata │ └── WorkspaceSettings.xcsettings ├── waveforms-live-agent.ini_bak ├── readme.md ├── digilent-agent.xib ├── Info.plist ├── object_script.waveforms-live-agent.Debug ├── object_script.digilent-agent.Debug ├── .gitignore ├── object_script.waveforms-live-agent.Release ├── object_script.earlgrey.Debug ├── object_script.digilent-agent.Release ├── object_script.earlgrey.Release ├── digilent-agent.pro ├── .qmake.stash ├── mainWindow.ui └── LICENSE.txt /test.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /installer/winConfig.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /description-pak: -------------------------------------------------------------------------------- 1 | WaveForms Live Agent 2 | -------------------------------------------------------------------------------- /installer/create-dmg/.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | -------------------------------------------------------------------------------- /qt.conf: -------------------------------------------------------------------------------- 1 | [Paths] 2 | Plugins=PlugIns 3 | -------------------------------------------------------------------------------- /installer/debug-build.txt: -------------------------------------------------------------------------------- 1 | debug build 1.0.1 2 | -------------------------------------------------------------------------------- /installer/debug-build.txtclear: -------------------------------------------------------------------------------- 1 | debug build 2 | -------------------------------------------------------------------------------- /digilent-agent.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "images/icon.ico" -------------------------------------------------------------------------------- /digilent-agent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent -------------------------------------------------------------------------------- /installer/depends/update.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | start "" "%~dp0maintenancetool.exe" --updater -------------------------------------------------------------------------------- /lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/lib/.DS_Store -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/.DS_Store -------------------------------------------------------------------------------- /images/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.icns -------------------------------------------------------------------------------- /images/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.ico -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.png -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Static Home Page... 4 | 5 | -------------------------------------------------------------------------------- /lib/digilent/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/lib/digilent/.DS_Store -------------------------------------------------------------------------------- /www/files/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Static Files Page... 4 | 5 | -------------------------------------------------------------------------------- /xcshareddata/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/xcshareddata/.DS_Store -------------------------------------------------------------------------------- /images/refresh-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/refresh-arrow.png -------------------------------------------------------------------------------- /installer/config/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/config/.DS_Store -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/update.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | start "" "%~dp0maintenancetool.exe" --updater -------------------------------------------------------------------------------- /images/icon.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_16x16.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_32x32.png -------------------------------------------------------------------------------- /installer/depends/libstdc++-6.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/depends/libstdc++-6.dll -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_16x16.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_32x32.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_128x128.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_256x256.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_512x512.png -------------------------------------------------------------------------------- /installer/depends/libgcc_s_dw2-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/depends/libgcc_s_dw2-1.dll -------------------------------------------------------------------------------- /installer/depends/libwinpthread-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/depends/libwinpthread-1.dll -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_128x128.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_256x256.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_512x512.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /images/icon.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/icon.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /digilent-agent.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/digilent-agent.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /images/digilent-agent-dmg-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/images/digilent-agent-dmg-background.png -------------------------------------------------------------------------------- /src/httpServer/core/httpglobal.cpp: -------------------------------------------------------------------------------- 1 | #include "httpglobal.h" 2 | 3 | const char* getQtWebAppLibVersion() 4 | { 5 | return "1.6.5"; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /mainWindow.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/icon.png 4 | images/refresh-arrow.png 5 | 6 | 7 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_ca.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_ca.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_cs.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_cs.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_de.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_de.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_en.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_en.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_fi.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_fi.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_fr.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_fr.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_he.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_he.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_hu.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_hu.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_it.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_it.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_ja.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_ja.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_ko.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_ko.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_lv.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_lv.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_pl.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_pl.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_ru.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_ru.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_sk.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_sk.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/data/translations/qt_uk.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.agent/data/translations/qt_uk.qm -------------------------------------------------------------------------------- /installer/packages/com.digilent.waveformsliveofflinesupport/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Digilent/digilent-agent/HEAD/installer/packages/com.digilent.waveformsliveofflinesupport/.DS_Store -------------------------------------------------------------------------------- /digilent-agent.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/digilent/qtSerial"] 2 | path = lib/digilent/qtSerial 3 | url = https://github.com/Digilent/qtSerial.git 4 | [submodule "lib/digilent/pgm"] 5 | path = lib/digilent/pgm 6 | url = https://github.com/Digilent/pgm.git 7 | -------------------------------------------------------------------------------- /digilent-agent.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.waveformsliveofflinesupport/meta/installScript.qs: -------------------------------------------------------------------------------- 1 | function Component() { 2 | 3 | } 4 | 5 | Component.prototype.createOperationsForArchive = function(archive) 6 | { 7 | component.addOperation("Extract", archive, "@HomeDir@//AppData/Local/Digilent/Digilent Agent/www/"); 8 | } -------------------------------------------------------------------------------- /installer/digilent-agent.ini: -------------------------------------------------------------------------------- 1 | [listener] 2 | port=56089 3 | minThreads=4 4 | maxThreads=100 5 | cleanupInterval=60000 6 | readTimeout=60000 7 | maxRequestSize=16000 8 | maxMultiPartSize=10000000 9 | 10 | [files] 11 | path=.\\www 12 | encoding=UTF-8 13 | maxAge=90000 14 | cacheTime=60000 15 | cacheSize=1000000 16 | maxCachedFileSize=65536 17 | -------------------------------------------------------------------------------- /project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/httpServer/debugController.cpp: -------------------------------------------------------------------------------- 1 | #include "debugController.h" 2 | 3 | DebugController::DebugController(QObject* parent) : HttpRequestHandler(parent) { 4 | 5 | } 6 | 7 | void DebugController::service(HttpRequest &request, HttpResponse &response) { 8 | qDebug() << request.getBody(); 9 | response.write("Debug Controller Page...", true); 10 | } 11 | -------------------------------------------------------------------------------- /waveforms-live-agent.ini_bak: -------------------------------------------------------------------------------- 1 | [listener] 2 | ;host=0.0.0.0 3 | port=56089 4 | minThreads=4 5 | maxThreads=100 6 | cleanupInterval=60000 7 | readTimeout=60000 8 | maxRequestSize=16000 9 | maxMultiPartSize=10000000 10 | 11 | [files] 12 | path=./www 13 | encoding=UTF-8 14 | maxAge=90000 15 | cacheTime=60000 16 | cacheSize=1000000 17 | maxCachedFileSize=65536 18 | -------------------------------------------------------------------------------- /digilent-agent.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /installer/create-dmg/sample: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | test -f test2.dmg && rm test2.dmg 3 | ./create-dmg --window-size 500 300 --background ~/Projects/eclipse-osx-repackager/build/background.gif --icon-size 96 --volname "Hyper Foo" --app-drop-link 380 205 --icon "Eclipse OS X Repackager" 110 205 test2.dmg /Users/andreyvit/Projects/eclipse-osx-repackager/temp/Eclipse\ OS\ X\ Repackager\ r10/ 4 | -------------------------------------------------------------------------------- /src/httpServer/debugController.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGCONTROLLER_H 2 | #define DEBUGCONTROLLER_H 3 | 4 | #include "httprequesthandler.h" 5 | 6 | class DebugController : public HttpRequestHandler { 7 | Q_OBJECT 8 | public: 9 | DebugController(QObject* parent=0); 10 | void service(HttpRequest& request, HttpResponse& response); 11 | }; 12 | 13 | #endif // DEBUGCONTROLLER_H 14 | -------------------------------------------------------------------------------- /src/wflDevice/wflDevice.cpp: -------------------------------------------------------------------------------- 1 | #include "wflDevice.h" 2 | 3 | #include 4 | 5 | WflDevice::WflDevice(QObject *parent) : QObject(parent) 6 | { 7 | qDebug() << "WflDevice::WflDevice()" << "thread: " << QThread::currentThread(); 8 | deviceType = "Unknown"; 9 | name = "Unknown Device"; 10 | } 11 | 12 | WflDevice::~WflDevice() { 13 | qDebug() << "~WflDevice()"; 14 | } 15 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.waveformsliveofflinesupport/meta/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | WaveForms Live Offline Support 4 | WaveForms Live Offline Support 5 | 1.0.0 6 | 2017-09-05 7 | true 8 | 9 | -------------------------------------------------------------------------------- /src/core/comboBoxEventFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "comboBoxEventFilter.h" 2 | #include 3 | #include 4 | 5 | ComboBoxEventFilter::ComboBoxEventFilter(QObject *parent) : QObject(parent) 6 | { 7 | 8 | } 9 | 10 | bool ComboBoxEventFilter::eventFilter(QObject *obj, QEvent *event) 11 | { 12 | qDebug() << obj; 13 | if(event->type() == 2) { 14 | qDebug("Mouse Click"); 15 | emit mouseClick(); 16 | } 17 | return false; 18 | } 19 | -------------------------------------------------------------------------------- /src/core/comboBoxEventFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef COMBOBOXEVENTFILTER_H 2 | #define COMBOBOXEVENTFILTER_H 3 | 4 | #include 5 | 6 | class ComboBoxEventFilter : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit ComboBoxEventFilter(QObject *parent = 0); 11 | 12 | protected: 13 | bool eventFilter(QObject *obj, QEvent *event); 14 | 15 | signals: 16 | void mouseClick(); 17 | 18 | public slots: 19 | }; 20 | 21 | #endif // COMBOBOXEVENTFILTER_H 22 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/meta/packageTemplate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Digilent Agent 4 | Digilent Agent 5 | VERSION_DUMMY 6 | DATE_DUMMY 7 | 8 | 9 | 10 | true 11 | 12 | -------------------------------------------------------------------------------- /lib/digilent/qtHttp/httpClient.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPCLIENT_H 2 | #define HTTPCLIENT_H 3 | 4 | #include 5 | #include 6 | 7 | class HttpClient : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | HttpClient(QObject *parent = 0); 12 | QByteArray get(QUrl url); 13 | //static QByteArray getBody(QUrl url); 14 | 15 | signals: 16 | void requestComplete(); 17 | 18 | public slots: 19 | void onRequestFinished(QNetworkReply *reply); 20 | 21 | private: 22 | QByteArray replyBody; 23 | }; 24 | 25 | #endif // HTTPCLIENT_H 26 | -------------------------------------------------------------------------------- /installer/config/osxConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | WaveForms Live Agent 4 | 0.1.6 5 | WaveForms Live Agent 6 | Digilent 7 | Digilent 8 | /Library/Digilent/WaveFormsLiveAgent 9 | true 10 | true 11 | Modern 12 | /Library/Digilent/WaveFormsLiveAgent 13 | installScript.qs 14 | 15 | -------------------------------------------------------------------------------- /src/core/utils/runGuard.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNGUARD_H 2 | #define RUNGUARD_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | class RunGuard 10 | { 11 | 12 | public: 13 | RunGuard( const QString& key ); 14 | ~RunGuard(); 15 | 16 | bool isAnotherRunning(); 17 | bool tryToRun(); 18 | void release(); 19 | 20 | private: 21 | const QString key; 22 | const QString memLockKey; 23 | const QString sharedmemKey; 24 | 25 | QSharedMemory sharedMem; 26 | QSystemSemaphore memLock; 27 | 28 | Q_DISABLE_COPY( RunGuard ) 29 | }; 30 | 31 | 32 | #endif // RUNGUARD_H 33 | -------------------------------------------------------------------------------- /src/httpServer/core/httpglobal.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPGLOBAL_H 7 | #define HTTPGLOBAL_H 8 | 9 | #include 10 | 11 | // This is specific to Windows dll's 12 | #if defined(Q_OS_WIN) 13 | #if defined(QTWEBAPPLIB_EXPORT) 14 | #define DECLSPEC Q_DECL_EXPORT 15 | #elif defined(QTWEBAPPLIB_IMPORT) 16 | #define DECLSPEC Q_DECL_IMPORT 17 | #endif 18 | #endif 19 | #if !defined(DECLSPEC) 20 | #define DECLSPEC 21 | #endif 22 | 23 | /** Get the library version number */ 24 | DECLSPEC const char* getQtWebAppLibVersion(); 25 | 26 | #endif // HTTPGLOBAL_H 27 | 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Digilent Agent 2 | The Digilent Agent is a service that runs in the system tray on Windows, Mac and Linux and enables browser based applications to communicate with Digilent hardware. 3 | 4 | #### Download Pre-built Installers 5 | [Windows, Mac, and Linux downloads.](https://reference.digilentinc.com/reference/software/waveforms-live/waveforms-live-agent) 6 | 7 | #### Documentation 8 | - [Reference Manual](https://reference.digilentinc.com/reference/software/digilent-agent/reference-manual) 9 | - [Building The Digilent Agent From Source](https://reference.digilentinc.com/reference/software/digilent-agent/build-from-source) 10 | 11 | -------------------------------------------------------------------------------- /installer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | TARGET=$1 3 | VERSION=$2 4 | BUILDTYPE=$3 5 | 6 | if [ -z "$1" ]; then 7 | echo "Error: Please specifiy the traget platform" 8 | exit 1 9 | fi 10 | 11 | if [ $TARGET = "win" ]; then 12 | printf "Preparing to build for Windows...\n" 13 | ./winBuildScript.sh $VERSION $BUILDTYPE 14 | elif [ $TARGET = "osx" ]; then 15 | printf "Preparing to build for OSX...\n" 16 | ./osxBuildScript.sh $VERSION $BUILDTYPE 17 | elif [ $TARGET = "deb" ]; then 18 | printf "Preparing to build for Linux...\n" 19 | ./debBuildScript.sh $VERSION $BUILDTYPE 20 | else 21 | printf "Unknown target platform $TARGET" 22 | fi 23 | 24 | 25 | -------------------------------------------------------------------------------- /installer/create-dmg/builder/create-dmg.builder: -------------------------------------------------------------------------------- 1 | SET app_name create-dmg 2 | 3 | VERSION create-dmg.cur create-dmg heads/master 4 | 5 | NEWDIR build.dir temp %-build - 6 | 7 | NEWFILE create-dmg.zip featured %.zip % 8 | 9 | 10 | COPYTO [build.dir] 11 | INTO create-dmg [create-dmg.cur]/create-dmg 12 | INTO sample [create-dmg.cur]/sample 13 | INTO support [create-dmg.cur]/support 14 | 15 | SUBSTVARS [build.dir]/create-dmg [[]] 16 | 17 | 18 | ZIP [create-dmg.zip] 19 | INTO [build-files-prefix] [build.dir] 20 | 21 | 22 | PUT megabox-builds create-dmg.zip 23 | PUT megabox-builds build.log 24 | 25 | PUT s3-builds create-dmg.zip 26 | PUT s3-builds build.log 27 | -------------------------------------------------------------------------------- /installer/debian/control: -------------------------------------------------------------------------------- 1 | Source: digilent-agent 2 | Section: x11 3 | Priority: optional 4 | Maintainer: Sam Kristoff 5 | Build-Depends: debhelper (>=9) 6 | Standards-Version: 3.9.6 7 | Homepage: https://www.digilentinc.com 8 | #Vcs-Git: git://anonscm.debian.org/collab-maint/earlgrey.git 9 | #Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/earlgrey.git 10 | 11 | Package: digilent-agent 12 | Architecture: any 13 | Depends: ${shlibs:Depends}, ${misc:Depends} 14 | Description: Digilent Agent 15 | The Digilent Agent is a service that runs in the system tray on Windows, Mac and Linux and enables browser based applications to communicate with Digilent hardware. 16 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/meta/license.txt: -------------------------------------------------------------------------------- 1 | The Digilent Agent is free software: you can redistribute it and/or modify 2 | it under the terms of the GNU General Public License as published by 3 | the Free Software Foundation, either version 3 of the License, or 4 | (at your option) any later version. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see -------------------------------------------------------------------------------- /src/httpServer/core/httprequesthandler.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "httprequesthandler.h" 7 | 8 | HttpRequestHandler::HttpRequestHandler(QObject* parent) 9 | : QObject(parent) 10 | {} 11 | 12 | HttpRequestHandler::~HttpRequestHandler() 13 | {} 14 | 15 | void HttpRequestHandler::service(HttpRequest& request, HttpResponse& response) 16 | { 17 | qCritical("HttpRequestHandler: you need to override the service() function"); 18 | qDebug("HttpRequestHandler: request=%s %s %s",request.getMethod().data(),request.getPath().data(),request.getVersion().data()); 19 | response.setStatus(501,"not implemented"); 20 | response.write("501 not implemented",true); 21 | } 22 | -------------------------------------------------------------------------------- /digilent-agent.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | digilent-agent 7 | CFBundleGetInfoString 8 | Created by Qt/QMake 9 | CFBundleIconFile 10 | icon.icns 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundlePackageType 14 | APPL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | 3 19 | NOTE 20 | This file was generated by Qt/QMake. 21 | NSPrincipalClass 22 | NSApplication 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/wflDevice/wflDevice.h: -------------------------------------------------------------------------------- 1 | #ifndef WFLDEVICE_H 2 | #define WFLDEVICE_H 3 | 4 | #include 5 | #include 6 | 7 | class WflDevice : public QObject 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | explicit WflDevice(QObject *parent = 0); 13 | virtual ~WflDevice(); 14 | 15 | //Functions 16 | virtual QByteArray writeRead(QByteArray cmd) = 0; 17 | virtual void execCommand(QByteArray cmd) = 0; 18 | virtual bool isOpen() = 0; 19 | 20 | //Variables 21 | QString name; 22 | QString deviceType; 23 | 24 | signals: 25 | void execCommandComplete(QByteArray response); 26 | void writeReadComplete(); 27 | void fastWriteReadComplete(); 28 | void softResetComplete(); 29 | void releaseComplete(); 30 | 31 | public slots: 32 | virtual void release() = 0; 33 | virtual bool softReset() = 0; 34 | 35 | private: 36 | 37 | }; 38 | 39 | #endif // WFLDEVICE_H 40 | -------------------------------------------------------------------------------- /installer/config/winConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Digilent Agent 4 | 1.0.1 5 | Digilent Agent 6 | Digilent 7 | Digilent 8 | @ApplicationsDir@/Digilent/Agent 9 | true 10 | true 11 | Modern 12 | @ApplicationsDir@/Digilent/Agent/digilent-agent.exe 13 | installScript.qs 14 | 15 | 16 | http://digilent-qt-repo.s3-website-us-west-2.amazonaws.com/digilent-agent 17 | 1 18 | Digilent Agent Repository 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/httpServer/httpRouter.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPROUTER_H 2 | #define HTTPROUTER_H 3 | 4 | //QT core includes 5 | #include 6 | 7 | //HTTP Core Includes 8 | #include "../core/agent.h" 9 | #include "httprequesthandler.h" 10 | #include "staticfilecontroller.h" 11 | #include "agentConfigCtrl.h" 12 | 13 | //OpenScope device includes 14 | #include "../wflDevice/wflDevice.h" 15 | 16 | class HttpRouter : public HttpRequestHandler { 17 | Q_OBJECT 18 | public: 19 | HttpRouter(Agent* agent, QObject* parent=0); 20 | 21 | Agent *agent; 22 | static StaticFileController* staticFileController; 23 | 24 | void service(HttpRequest& request, HttpResponse& response); 25 | 26 | signals: 27 | void deviceComplete(); 28 | 29 | private slots: 30 | void onComplete(QByteArray reply); 31 | 32 | private: 33 | AgentConfigCtrl *agentConfigCtrl; 34 | QByteArray reply; 35 | bool waitingForResponse; 36 | }; 37 | 38 | #endif // HTTPROUTER_H 39 | 40 | -------------------------------------------------------------------------------- /installer/config/winConfigTemplate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Digilent Agent 4 | VERSION_DUMMY 5 | Digilent Agent 6 | Digilent 7 | Digilent 8 | @ApplicationsDir@/Digilent/Agent 9 | true 10 | true 11 | Modern 12 | @ApplicationsDir@/Digilent/Agent/digilent-agent.exe 13 | installScript.qs 14 | 15 | 16 | http://digilent-qt-repo.s3-website-us-west-2.amazonaws.com/digilent-agent 17 | 1 18 | Digilent Agent Repository 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/wflDevice/wflSerialDevice.h: -------------------------------------------------------------------------------- 1 | #ifndef WFLSERIALDEVICE_H 2 | #define WFLSERIALDEVICE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "wflDevice.h" 8 | #include "lib/digilent/qtSerial/serial.h" 9 | 10 | class WflSerialDevice : public WflDevice{ 11 | Q_OBJECT 12 | 13 | public: 14 | WflSerialDevice(QString address, QObject *parent = 0); 15 | virtual ~WflSerialDevice(); 16 | virtual bool isOpen(); 17 | virtual void execCommand(QByteArray cmd); 18 | virtual QByteArray writeRead(QByteArray cmd); 19 | 20 | signals: 21 | void startFastWriteRead(QByteArray cmd, int delay, int timeout); 22 | void startSoftReset(); 23 | 24 | private slots: 25 | void onFastWriteReadResponse(QByteArray response); 26 | void onSoftResetResponse(bool success); 27 | 28 | public slots: 29 | void release(); 30 | virtual bool softReset(); 31 | 32 | 33 | private: 34 | Serial* serial; 35 | QByteArray data; 36 | bool softResetSuccess; 37 | }; 38 | 39 | 40 | #endif // WFLSERIALDEVICE_H 41 | -------------------------------------------------------------------------------- /src/httpServer/agentConfigCtrl.h: -------------------------------------------------------------------------------- 1 | #ifndef AGENTCONFIGCTRL_H 2 | #define AGENTCONFIGCTRL_H 3 | 4 | #include 5 | 6 | #include "httprequesthandler.h" 7 | #include "../core/agent.h" 8 | 9 | 10 | class AgentConfigCtrl : public HttpRequestHandler { 11 | Q_OBJECT 12 | 13 | public: 14 | AgentConfigCtrl(Agent* agent, QObject* parent=0); 15 | void service(HttpRequest& request, HttpResponse& response); 16 | 17 | signals: 18 | void startUpdateActiveDeviceFirmware(QString hexPath, bool enterBootloader); 19 | 20 | private: 21 | enum CmdCode { 22 | e_enumerateDevices, 23 | e_getInfo, 24 | e_setActiveDevice, 25 | e_saveToTempFile, 26 | e_uploadFirmware, 27 | e_updateFirmwareGetStatus, 28 | e_updateWaveFormsLiveBrowser, 29 | e_enterJsonMode, 30 | e_releaseActiveDevice, 31 | e_unknownCommand, 32 | }; 33 | 34 | Agent *agent; 35 | 36 | QJsonObject processCommand(QJsonObject cmdObj, QByteArray data = QByteArray()); 37 | CmdCode parseCmd(QString cmdString); 38 | }; 39 | 40 | #endif // AGENTCONFIGCTRL_H 41 | -------------------------------------------------------------------------------- /lib/digilent/qtHttp/httpClient.cpp: -------------------------------------------------------------------------------- 1 | #include "httpClient.h" 2 | 3 | #include 4 | #include 5 | 6 | HttpClient::HttpClient(QObject *parent) : QObject(parent) { 7 | 8 | } 9 | 10 | //Perform an HTTP GET on the specified URL. This function blocks until the request is complete or the specified timeout. 11 | //If the reqeust completes the response is returned, null is returned otherwise. 12 | //TODO - Add timeout 13 | QByteArray HttpClient::get(QUrl url) { 14 | QNetworkAccessManager qnam; 15 | QEventLoop loop; 16 | 17 | //connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(onRequestFinished(QNetworkReply*))); 18 | QNetworkRequest request(url); 19 | QNetworkReply *reply = qnam.get(request); 20 | 21 | //Wait for signal that proxy call has returned 22 | connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); 23 | loop.exec(); 24 | 25 | //Return response body 26 | return reply->readAll(); 27 | } 28 | 29 | void HttpClient::onRequestFinished(QNetworkReply *reply) { 30 | QList headers = reply->rawHeaderList(); 31 | this->replyBody = reply->readAll(); 32 | emit requestComplete(); 33 | } 34 | -------------------------------------------------------------------------------- /installer/create-dmg/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2008-2014 Andrey Tarantsov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/httpServer/core/httpserver.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | QT += network 5 | 6 | # Enable very detailed debug messages when compiling the debug version 7 | CONFIG(debug, debug|release) { 8 | DEFINES += SUPERVERBOSE 9 | } 10 | 11 | HEADERS += $$PWD/httpglobal.h \ 12 | $$PWD/httplistener.h \ 13 | $$PWD/httpconnectionhandler.h \ 14 | $$PWD/httpconnectionhandlerpool.h \ 15 | $$PWD/httprequest.h \ 16 | $$PWD/httpresponse.h \ 17 | $$PWD/httpcookie.h \ 18 | $$PWD/httprequesthandler.h \ 19 | $$PWD/httpsession.h \ 20 | $$PWD/httpsessionstore.h \ 21 | $$PWD/staticfilecontroller.h 22 | 23 | SOURCES += $$PWD/httpglobal.cpp \ 24 | $$PWD/httplistener.cpp \ 25 | $$PWD/httpconnectionhandler.cpp \ 26 | $$PWD/httpconnectionhandlerpool.cpp \ 27 | $$PWD/httprequest.cpp \ 28 | $$PWD/httpresponse.cpp \ 29 | $$PWD/httpcookie.cpp \ 30 | $$PWD/httprequesthandler.cpp \ 31 | $$PWD/httpsession.cpp \ 32 | $$PWD/httpsessionstore.cpp \ 33 | $$PWD/staticfilecontroller.cpp 34 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.waveformsliveofflinesupport/meta/license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Digilent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /object_script.waveforms-live-agent.Debug: -------------------------------------------------------------------------------- 1 | INPUT( 2 | ./debug\httpglobal.o 3 | ./debug\httplistener.o 4 | ./debug\httpconnectionhandler.o 5 | ./debug\httpconnectionhandlerpool.o 6 | ./debug\httprequest.o 7 | ./debug\httpresponse.o 8 | ./debug\httpcookie.o 9 | ./debug\httprequesthandler.o 10 | ./debug\httpsession.o 11 | ./debug\httpsessionstore.o 12 | ./debug\staticfilecontroller.o 13 | ./debug\httpRouter.o 14 | ./debug\main.o 15 | ./debug\debugController.o 16 | ./debug\mainWindow.o 17 | ./debug\comboBoxEventFilter.o 18 | ./debug\agentConfigCtrl.o 19 | ./debug\agent.o 20 | ./debug\wflDevice.o 21 | ./debug\runGuard.o 22 | ./debug\serial.o 23 | ./debug\wflSerialDevice.o 24 | ./debug\digilentPgm.o 25 | ./debug\pgmBlock.o 26 | ./debug\httpClient.o 27 | ./debug\qrc_mainWindow.o 28 | ./debug\moc_httplistener.o 29 | ./debug\moc_httpconnectionhandler.o 30 | ./debug\moc_httpconnectionhandlerpool.o 31 | ./debug\moc_httprequesthandler.o 32 | ./debug\moc_httpsessionstore.o 33 | ./debug\moc_staticfilecontroller.o 34 | ./debug\moc_httpRouter.o 35 | ./debug\moc_mainWindow.o 36 | ./debug\moc_comboBoxEventFilter.o 37 | ./debug\moc_agentConfigCtrl.o 38 | ./debug\moc_debugController.o 39 | ./debug\moc_agent.o 40 | ./debug\moc_wflDevice.o 41 | ./debug\moc_wflSerialDevice.o 42 | ./debug\moc_httpClient.o 43 | ); 44 | -------------------------------------------------------------------------------- /object_script.digilent-agent.Debug: -------------------------------------------------------------------------------- 1 | INPUT( 2 | ./debug\httpglobal.o 3 | ./debug\httplistener.o 4 | ./debug\httpconnectionhandler.o 5 | ./debug\httpconnectionhandlerpool.o 6 | ./debug\httprequest.o 7 | ./debug\httpresponse.o 8 | ./debug\httpcookie.o 9 | ./debug\httprequesthandler.o 10 | ./debug\httpsession.o 11 | ./debug\httpsessionstore.o 12 | ./debug\staticfilecontroller.o 13 | ./debug\httpRouter.o 14 | ./debug\main.o 15 | ./debug\debugController.o 16 | ./debug\mainWindow.o 17 | ./debug\comboBoxEventFilter.o 18 | ./debug\agentConfigCtrl.o 19 | ./debug\agent.o 20 | ./debug\wflDevice.o 21 | ./debug\runGuard.o 22 | ./debug\serial.o 23 | ./debug\wflSerialDevice.o 24 | ./debug\digilentPgm.o 25 | ./debug\pgmBlock.o 26 | ./debug\httpClient.o 27 | ./debug\qrc_mainWindow.o 28 | ./debug\moc_httplistener.o 29 | ./debug\moc_httpconnectionhandler.o 30 | ./debug\moc_httpconnectionhandlerpool.o 31 | ./debug\moc_httprequesthandler.o 32 | ./debug\moc_httpsessionstore.o 33 | ./debug\moc_staticfilecontroller.o 34 | ./debug\moc_httpRouter.o 35 | ./debug\moc_mainWindow.o 36 | ./debug\moc_comboBoxEventFilter.o 37 | ./debug\moc_agentConfigCtrl.o 38 | ./debug\moc_debugController.o 39 | ./debug\moc_agent.o 40 | ./debug\moc_wflDevice.o 41 | ./debug\moc_serial.o 42 | ./debug\moc_wflSerialDevice.o 43 | ./debug\moc_httpClient.o 44 | ); 45 | -------------------------------------------------------------------------------- /installer/packages/com.digilent.agent/meta/installScript.qs: -------------------------------------------------------------------------------- 1 | function Component() { 2 | 3 | //Register processes that should be stopped before this component is added/updated/removed 4 | component.addStopProcessForUpdateRequest("waveforms-live-agent.exe"); 5 | component.addStopProcessForUpdateRequest("digilent-agent.exe"); 6 | 7 | var programFiles = installer.environmentVariable("ProgramFiles"); 8 | if (programFiles != "") { 9 | installer.setValue("TargetDir", programFiles + "/Digilent/Agent"); 10 | } 11 | } 12 | 13 | //Platform Specific Custom Actions 14 | Component.prototype.createOperations = function () { 15 | //Call default createOperations 16 | component.createOperations(); 17 | 18 | ////Windows Install Actions 19 | if (systemInfo.productType === "windows") { 20 | //Create Shortcut To Start At System Boot 21 | var exePath = installer.value("TargetDir") + "/digilent-agent.exe"; 22 | component.addOperation("CreateShortcut", exePath, "@UserStartMenuProgramsPath@/Startup/Digilent-Agent.lnk", "workingDirectory=@TargetDir@", "iconPath=%SystemRoot%/system32/SHELL32.dll", "iconId=2"); 23 | 24 | //Create start menu shortcut 25 | component.addOperation("CreateShortcut", "@TargetDir@/digilent-agent.exe", "@StartMenuDir@/Digilent Agent.lnk"); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | *.DS_Store 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | qrc_*.cpp 24 | ui_*.h 25 | Makefile* 26 | *build-* 27 | 28 | # QtCreator 29 | 30 | *.autosave 31 | 32 | # QtCtreator Qml 33 | *.qmlproject.user 34 | *.qmlproject.user.* 35 | 36 | # QtCtreator CMake 37 | CMakeLists.txt.user* 38 | 39 | #Earlgrey 40 | *.exe 41 | *.dmg 42 | installer/packages/com.digilent.waveformsliveagent/data/* 43 | installer/packages/com.digilent.waveformsliveofflinesupport/data/* 44 | installer/build/* 45 | installer/working/* 46 | installer/waveforms-live-offline 47 | installer/repo/* 48 | installer/packages/* 49 | debug/ 50 | release/ 51 | Makefile 52 | 53 | # Xcode 54 | # 55 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 56 | 57 | ## Build generated 58 | build/ 59 | DerivedData/ 60 | 61 | ## Various settings 62 | *.pbxuser 63 | !default.pbxuser 64 | *.mode1v3 65 | !default.mode1v3 66 | *.mode2v3 67 | !default.mode2v3 68 | *.perspectivev3 69 | !default.perspectivev3 70 | xcuserdata/ 71 | 72 | ## Other 73 | *.moved-aside 74 | *.xccheckout 75 | *.xcscmblueprinty 76 | *.build 77 | .DS_Store 78 | -------------------------------------------------------------------------------- /object_script.waveforms-live-agent.Release: -------------------------------------------------------------------------------- 1 | INPUT( 2 | ./release\httpglobal.o 3 | ./release\httplistener.o 4 | ./release\httpconnectionhandler.o 5 | ./release\httpconnectionhandlerpool.o 6 | ./release\httprequest.o 7 | ./release\httpresponse.o 8 | ./release\httpcookie.o 9 | ./release\httprequesthandler.o 10 | ./release\httpsession.o 11 | ./release\httpsessionstore.o 12 | ./release\staticfilecontroller.o 13 | ./release\httpRouter.o 14 | ./release\main.o 15 | ./release\debugController.o 16 | ./release\mainWindow.o 17 | ./release\comboBoxEventFilter.o 18 | ./release\agentConfigCtrl.o 19 | ./release\agent.o 20 | ./release\wflDevice.o 21 | ./release\runGuard.o 22 | ./release\serial.o 23 | ./release\wflSerialDevice.o 24 | ./release\digilentPgm.o 25 | ./release\pgmBlock.o 26 | ./release\httpClient.o 27 | ./release\qrc_mainWindow.o 28 | ./release\moc_httplistener.o 29 | ./release\moc_httpconnectionhandler.o 30 | ./release\moc_httpconnectionhandlerpool.o 31 | ./release\moc_httprequesthandler.o 32 | ./release\moc_httpsessionstore.o 33 | ./release\moc_staticfilecontroller.o 34 | ./release\moc_httpRouter.o 35 | ./release\moc_mainWindow.o 36 | ./release\moc_comboBoxEventFilter.o 37 | ./release\moc_agentConfigCtrl.o 38 | ./release\moc_debugController.o 39 | ./release\moc_agent.o 40 | ./release\moc_wflDevice.o 41 | ./release\moc_wflSerialDevice.o 42 | ./release\moc_httpClient.o 43 | ); 44 | -------------------------------------------------------------------------------- /object_script.earlgrey.Debug: -------------------------------------------------------------------------------- 1 | INPUT( 2 | ./debug\httpglobal.o 3 | ./debug\httplistener.o 4 | ./debug\httpconnectionhandler.o 5 | ./debug\httpconnectionhandlerpool.o 6 | ./debug\httprequest.o 7 | ./debug\httpresponse.o 8 | ./debug\httpcookie.o 9 | ./debug\httprequesthandler.o 10 | ./debug\httpsession.o 11 | ./debug\httpsessionstore.o 12 | ./debug\staticfilecontroller.o 13 | ./debug\httpRouter.o 14 | ./debug\main.o 15 | ./debug\debugController.o 16 | ./debug\mainWindow.o 17 | ./debug\httpClient.o 18 | ./debug\uartClient.o 19 | ./debug\uartInfo.o 20 | ./debug\comboBoxEventFilter.o 21 | ./debug\agentConfigCtrl.o 22 | ./debug\agent.o 23 | ./debug\wflDevice.o 24 | ./debug\wflHttpDevice.o 25 | ./debug\wflUartDevice.o 26 | ./debug\runGuard.o 27 | ./debug\qrc_mainWindow.o 28 | ./debug\moc_httplistener.o 29 | ./debug\moc_httpconnectionhandler.o 30 | ./debug\moc_httpconnectionhandlerpool.o 31 | ./debug\moc_httprequesthandler.o 32 | ./debug\moc_httpsessionstore.o 33 | ./debug\moc_staticfilecontroller.o 34 | ./debug\moc_httpRouter.o 35 | ./debug\moc_mainWindow.o 36 | ./debug\moc_httpClient.o 37 | ./debug\moc_uartClient.o 38 | ./debug\moc_comboBoxEventFilter.o 39 | ./debug\moc_agentConfigCtrl.o 40 | ./debug\moc_debugController.o 41 | ./debug\moc_agent.o 42 | ./debug\moc_wflDevice.o 43 | ./debug\moc_wflUartDevice.o 44 | ./debug\moc_wflHttpDevice.o 45 | ); 46 | -------------------------------------------------------------------------------- /object_script.digilent-agent.Release: -------------------------------------------------------------------------------- 1 | INPUT( 2 | ./release\httpglobal.o 3 | ./release\httplistener.o 4 | ./release\httpconnectionhandler.o 5 | ./release\httpconnectionhandlerpool.o 6 | ./release\httprequest.o 7 | ./release\httpresponse.o 8 | ./release\httpcookie.o 9 | ./release\httprequesthandler.o 10 | ./release\httpsession.o 11 | ./release\httpsessionstore.o 12 | ./release\staticfilecontroller.o 13 | ./release\httpRouter.o 14 | ./release\main.o 15 | ./release\debugController.o 16 | ./release\mainWindow.o 17 | ./release\comboBoxEventFilter.o 18 | ./release\agentConfigCtrl.o 19 | ./release\agent.o 20 | ./release\wflDevice.o 21 | ./release\runGuard.o 22 | ./release\serial.o 23 | ./release\wflSerialDevice.o 24 | ./release\digilentPgm.o 25 | ./release\pgmBlock.o 26 | ./release\httpClient.o 27 | ./release\qrc_mainWindow.o 28 | ./release\moc_httplistener.o 29 | ./release\moc_httpconnectionhandler.o 30 | ./release\moc_httpconnectionhandlerpool.o 31 | ./release\moc_httprequesthandler.o 32 | ./release\moc_httpsessionstore.o 33 | ./release\moc_staticfilecontroller.o 34 | ./release\moc_httpRouter.o 35 | ./release\moc_mainWindow.o 36 | ./release\moc_comboBoxEventFilter.o 37 | ./release\moc_agentConfigCtrl.o 38 | ./release\moc_debugController.o 39 | ./release\moc_agent.o 40 | ./release\moc_wflDevice.o 41 | ./release\moc_serial.o 42 | ./release\moc_wflSerialDevice.o 43 | ./release\moc_httpClient.o 44 | ); 45 | -------------------------------------------------------------------------------- /object_script.earlgrey.Release: -------------------------------------------------------------------------------- 1 | INPUT( 2 | ./release\httpglobal.o 3 | ./release\httplistener.o 4 | ./release\httpconnectionhandler.o 5 | ./release\httpconnectionhandlerpool.o 6 | ./release\httprequest.o 7 | ./release\httpresponse.o 8 | ./release\httpcookie.o 9 | ./release\httprequesthandler.o 10 | ./release\httpsession.o 11 | ./release\httpsessionstore.o 12 | ./release\staticfilecontroller.o 13 | ./release\httpRouter.o 14 | ./release\main.o 15 | ./release\debugController.o 16 | ./release\mainWindow.o 17 | ./release\httpClient.o 18 | ./release\uartClient.o 19 | ./release\uartInfo.o 20 | ./release\comboBoxEventFilter.o 21 | ./release\agentConfigCtrl.o 22 | ./release\agent.o 23 | ./release\wflDevice.o 24 | ./release\wflHttpDevice.o 25 | ./release\wflUartDevice.o 26 | ./release\runGuard.o 27 | ./release\qrc_mainWindow.o 28 | ./release\moc_httplistener.o 29 | ./release\moc_httpconnectionhandler.o 30 | ./release\moc_httpconnectionhandlerpool.o 31 | ./release\moc_httprequesthandler.o 32 | ./release\moc_httpsessionstore.o 33 | ./release\moc_staticfilecontroller.o 34 | ./release\moc_httpRouter.o 35 | ./release\moc_mainWindow.o 36 | ./release\moc_httpClient.o 37 | ./release\moc_uartClient.o 38 | ./release\moc_comboBoxEventFilter.o 39 | ./release\moc_agentConfigCtrl.o 40 | ./release\moc_debugController.o 41 | ./release\moc_agent.o 42 | ./release\moc_wflDevice.o 43 | ./release\moc_wflUartDevice.o 44 | ./release\moc_wflHttpDevice.o 45 | ); 46 | -------------------------------------------------------------------------------- /installer/debBuildScript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | VERSION=$1 3 | 4 | DEBEMAIL="software@digilent.com" 5 | DEBFULLNAME="Sam Kristoff" 6 | 7 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | BUILD_DIR=$DIR/working 9 | #TARGET_NAME="digilent-agent" 10 | TARGET_NAME="digilent-agent" 11 | TARGET_DIR="$BUILD_DIR/$TARGET_NAME-$VERSION" 12 | 13 | echo $BUILD_DIR 14 | 15 | #Warn user if no version number was passed 16 | if [ -z "$1" ]; then 17 | echo "Error: Please specifiy the build version" 18 | exit 1 19 | fi 20 | 21 | 22 | #Remove any old files 23 | printf "Cleaning build directory\n" 24 | rm -r -f "$BUILD_DIR/" 25 | 26 | #Create build directory if it does not exist 27 | if [ ! -d "$TARGET_DIR" ]; then 28 | printf "Creating build directory\n" 29 | mkdir -p $TARGET_DIR 30 | fi 31 | 32 | #Copy files into build directory 33 | printf "Copying source files\n" 34 | rsync ../ $TARGET_DIR --exclude="installer/" --exclude="debug/" --exclude="release/" -r 35 | 36 | cd $TARGET_DIR 37 | 38 | #Generate Makefile 39 | printf "Generating Makefile\n" 40 | qmake -o Makefile digilent-agent.pro 41 | 42 | #Preparing .deb package 43 | printf "Preparing .deb package\n" 44 | 45 | #cp -R ../../debian . 46 | #tar -czvf $BUILD_DIR"/"$TARGET_NAME"_"$VERSION.orig.tar.gz ../$TARGET_NAME-$VERSION 47 | dh_make -s --createorig -c gpl3 48 | cp ../../debian/* ./debian/ 49 | rm ./debian/*.ex 50 | rm ./debian/*.EX 51 | 52 | #Building .deb package 53 | printf "Building .deb package\n" 54 | dpkg-buildpackage -uc -us 55 | 56 | -------------------------------------------------------------------------------- /src/httpServer/core/httprequesthandler.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPREQUESTHANDLER_H 7 | #define HTTPREQUESTHANDLER_H 8 | 9 | #include "httpglobal.h" 10 | #include "httprequest.h" 11 | #include "httpresponse.h" 12 | 13 | /** 14 | The request handler generates a response for each HTTP request. Web Applications 15 | usually have one central request handler that maps incoming requests to several 16 | controllers (servlets) based on the requested path. 17 |

18 | You need to override the service() method or you will always get an HTTP error 501. 19 |

20 | @warning Be aware that the main request handler instance must be created on the heap and 21 | that it is used by multiple threads simultaneously. 22 | @see StaticFileController which delivers static local files. 23 | */ 24 | 25 | class DECLSPEC HttpRequestHandler : public QObject { 26 | Q_OBJECT 27 | Q_DISABLE_COPY(HttpRequestHandler) 28 | public: 29 | 30 | /** 31 | * Constructor. 32 | * @param parent Parent object. 33 | */ 34 | HttpRequestHandler(QObject* parent=NULL); 35 | 36 | /** Destructor */ 37 | virtual ~HttpRequestHandler(); 38 | 39 | /** 40 | Generate a response for an incoming HTTP request. 41 | @param request The received HTTP request 42 | @param response Must be used to return the response 43 | @warning This method must be thread safe 44 | */ 45 | virtual void service(HttpRequest& request, HttpResponse& response); 46 | 47 | }; 48 | 49 | #endif // HTTPREQUESTHANDLER_H 50 | -------------------------------------------------------------------------------- /installer/osxBuildScript.sh: -------------------------------------------------------------------------------- 1 | VERSION=$1 2 | BUILDTYPE=$2 3 | DATE=`date +%Y-%m-%d` 4 | 5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | BUILD_DIR=$DIR/working 7 | TARGET_APP=$BUILD_DIR"/Digilent Agent.app" 8 | 9 | #Remove any old files 10 | printf "Cleaning build directory\n" 11 | rm -r -f "$BUILD_DIR/" 12 | 13 | #Create build directory if it does not exist 14 | if [ ! -d "$BUILD_DIR" ]; then 15 | printf "Creating build directory\n" 16 | mkdir -p $BUILD_DIR 17 | fi 18 | 19 | printf "Copying files to build directory\n" 20 | cp -r ../Release/digilent-agent.app "$TARGET_APP" 21 | ln -s /Users/Shared working/Shared 22 | mkdir -p working/digilent/digilent-agent/www 23 | cp -r waveforms-live-offline/ working/digilent/digilent-agent/www 24 | 25 | 26 | printf "Packaging Dependencies...\n" 27 | macdeployqt "$TARGET_APP" -codesign="Mac Developer: software@" -always-overwrite 28 | 29 | printf "Signing...\n" 30 | codesign --force --verify --verbose --sign "Mac Developer: software" "$TARGET_APP" 31 | find "$TARGET_APP" -name *.dylib | xargs -I $ codesign --force --verify --verbose --sign "Mac Developer: software" $ 32 | find "$TARGET_APP" -name Qt* -type f | xargs -I $ codesign --force --verify --verbose --sign "Mac Developer: software" $ 33 | 34 | printf "Creating .dmg...\n" 35 | ./create-dmg/create-dmg.sh \ 36 | --volname "Digilent Agent $VERSION" \ 37 | --background ../images/digilent-agent-dmg-background.png \ 38 | --window-size 640 430 \ 39 | --icon-size 64 \ 40 | --icon "Digilent\ Agent.app" 240 160 \ 41 | --app-drop-link 400 160 \ 42 | --icon "digilent" 240 300 \ 43 | --icon "Shared" 400 300 \ 44 | digilent-agent-$VERSION.dmg \ 45 | working/ \ 46 | \ -------------------------------------------------------------------------------- /src/mainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | //HTTP core includes 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //WFL Agent Core 15 | #include "core/agent.h" 16 | #include "core/comboBoxEventFilter.h" 17 | 18 | #ifndef QT_NO_SYSTEMTRAYICON 19 | #include 20 | 21 | namespace Ui { 22 | class MainWindow; 23 | } 24 | 25 | class MainWindow : public QMainWindow 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit MainWindow(Agent* agent, QWidget *parent = 0); 31 | ~MainWindow(); 32 | 33 | Agent *agent; 34 | QComboBox *deviceDropDown; 35 | 36 | protected: 37 | //void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; 38 | 39 | signals: 40 | void releaseActiveDeviceSignal(); 41 | 42 | private slots: 43 | void onActiveDeviceNameChange(QString activeDeviceName); 44 | void releaseActiveDevice(); 45 | //void refreshDeviceList(); 46 | //void onConnectReleased(); 47 | 48 | private: 49 | //UI Elements 50 | Ui::MainWindow *ui; 51 | 52 | 53 | //System Tray 54 | QMenu *trayIconMenu; 55 | QMenu* activeDeviceSubMenu; 56 | 57 | QAction *launchWflAction; 58 | QAction *checkForUpdatesAction; 59 | 60 | QAction *activeDeviceNameAction; 61 | QAction *activeDeviceSubMenuRelease; 62 | 63 | QAction *versionAction; 64 | QAction *quitAction; 65 | 66 | 67 | QSystemTrayIcon *trayIcon; 68 | 69 | 70 | 71 | void createWindowActions(); 72 | void createTrayIcon(); 73 | void launchWfl(); 74 | bool checkForUpdates(); 75 | void runUpdater(); 76 | }; 77 | 78 | #endif // QT_NO_SYSTEMTRAYICON 79 | #endif // MAINWINDOW_H 80 | -------------------------------------------------------------------------------- /src/core/utils/runGuard.cpp: -------------------------------------------------------------------------------- 1 | #include "runGuard.h" 2 | 3 | #include 4 | 5 | 6 | namespace 7 | { 8 | 9 | QString generateKeyHash( const QString& key, const QString& salt ) 10 | { 11 | QByteArray data; 12 | 13 | data.append( key.toUtf8() ); 14 | data.append( salt.toUtf8() ); 15 | data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); 16 | 17 | return data; 18 | } 19 | 20 | } 21 | 22 | 23 | RunGuard::RunGuard( const QString& key ) 24 | : key( key ) 25 | , memLockKey( generateKeyHash( key, "_memLockKey" ) ) 26 | , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) 27 | , sharedMem( sharedmemKey ) 28 | , memLock( memLockKey, 1 ) 29 | { 30 | memLock.acquire(); 31 | { 32 | QSharedMemory fix( sharedmemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/ 33 | fix.attach(); 34 | } 35 | memLock.release(); 36 | } 37 | 38 | RunGuard::~RunGuard() 39 | { 40 | release(); 41 | } 42 | 43 | bool RunGuard::isAnotherRunning() 44 | { 45 | if ( sharedMem.isAttached() ) 46 | return false; 47 | 48 | memLock.acquire(); 49 | const bool isRunning = sharedMem.attach(); 50 | if ( isRunning ) 51 | sharedMem.detach(); 52 | memLock.release(); 53 | 54 | return isRunning; 55 | } 56 | 57 | bool RunGuard::tryToRun() 58 | { 59 | if ( isAnotherRunning() ) // Extra check 60 | return false; 61 | 62 | memLock.acquire(); 63 | const bool result = sharedMem.create( sizeof( quint64 ) ); 64 | memLock.release(); 65 | if ( !result ) 66 | { 67 | release(); 68 | return false; 69 | } 70 | 71 | return true; 72 | } 73 | 74 | void RunGuard::release() 75 | { 76 | memLock.acquire(); 77 | if ( sharedMem.isAttached() ) 78 | sharedMem.detach(); 79 | memLock.release(); 80 | } 81 | -------------------------------------------------------------------------------- /installer/config/installScript.qs: -------------------------------------------------------------------------------- 1 | function Controller() { 2 | installer.uninstallationStarted.connect(onUninstallationStarted); 3 | } 4 | 5 | onUninstallationStarted = function () { 6 | 7 | } 8 | 9 | function skipFinishPageCallback() { 10 | gui.clickButton(buttons.Finish); 11 | } 12 | 13 | Controller.prototype.TargetDirectoryPageCallback = function () { 14 | var widget = gui.currentPageWidget(); 15 | widget.TargetDirectoryLineEdit.textChanged.connect(this, Controller.prototype.targetChanged); 16 | Controller.prototype.targetChanged(widget.TargetDirectoryLineEdit.text); 17 | } 18 | 19 | Controller.prototype.targetChanged = function (text) { 20 | if (text != "" && installer.fileExists(text + "/maintenancetool.exe")) { 21 | 22 | //Prompt user to launch updater 23 | if (QMessageBox.question("OverwriteTargetDirectory", "Launch Updater?", "A previous version exists in the specified directory. Do you want to launch the updater?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes) { 24 | //Launch Updater 25 | QDesktopServices.openUrl("file:///" + installer.value("TargetDir") + "/update.bat"); 26 | 27 | //Skip remaining wizard pages and quit the installer 28 | installer.setDefaultPageVisible(QInstaller.TargetDirectory, false); 29 | installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); 30 | installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); 31 | installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); 32 | installer.setDefaultPageVisible(QInstaller.PerformInstallation, false); 33 | installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); 34 | gui.clickButton(buttons.CancelButton); 35 | } 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /installer/winBuildScript.sh: -------------------------------------------------------------------------------- 1 | VERSION=$1 2 | BUILDTYPE=$2 3 | DATE=`date +%Y-%m-%d` 4 | 5 | #Generate config files from templates 6 | printf "Generating Config Files" 7 | sed "s/VERSION_DUMMY/$VERSION/g" config/winConfigTemplate.xml > config/winConfig.xml 8 | 9 | cp packages/com.digilent.agent/meta/packageTemplate.xml packages/com.digilent.agent/meta/package.xml 10 | sed -i "s/VERSION_DUMMY/$VERSION/g" packages/com.digilent.agent/meta/package.xml 11 | sed -i "s/DATE_DUMMY/$DATE/g" packages/com.digilent.agent/meta/package.xml 12 | 13 | #Copy build files into installer directory 14 | printf "Copying build to data directory...\n" 15 | rm -r ./packages/com.digilent.agent/data/* 16 | 17 | if [ $BUILDTYPE = "debug" ]; then 18 | cp ../debug/* packages/com.digilent.agent/data/ 19 | echo "debug build $VERSION" > debug-build.txt 20 | else 21 | cp ../release/* packages/com.digilent.agent/data/ 22 | fi 23 | 24 | #Automatically Pull Windows Dependencies 25 | printf "Pulling Component Dependencies...\n" 26 | cd packages/com.digilent.agent/data 27 | windeployqt digilent-agent.exe 28 | #Copy additional dependencies 29 | #missing depends for win32 30 | #"C:\Qt\5.7\mingw53_32\bin\libstdc++-6.dll" 31 | #"C:\Qt\5.7\mingw53_32\bin\libgcc_s_dw2-1.dll" 32 | #"C:\Qt\5.7\mingw53_32\bin\libwinpthread-1.dll" 33 | cd ../../.. 34 | cp depends/* packages/com.digilent.agent/data/ 35 | 36 | 37 | printf "Building Installer...\n" 38 | if [ $BUILDTYPE = "debug" ]; then 39 | binarycreator --offline-only -c config/winConfig.xml -p packages "digilent-agent-$VERSION-debug.exe" 40 | else 41 | binarycreator --offline-only -c config/winConfig.xml -p packages "digilent-agent-$VERSION.exe" 42 | fi 43 | 44 | 45 | if [ $BUILDTYPE = "debug" ]; then 46 | printf "Skipping repos for debug build" 47 | else 48 | printf "Building repositories" 49 | rm -r repo/ 50 | repogen.exe -p packages repo 51 | fi 52 | 53 | -------------------------------------------------------------------------------- /src/core/agent.h: -------------------------------------------------------------------------------- 1 | #ifndef AGENT_H 2 | #define AGENT_H 3 | 4 | //QT Core Includes 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //WFL Agent includes 11 | #include "lib/digilent/qtSerial/serial.h" 12 | #include "lib/digilent/pgm/digilentPgm.h" 13 | #include "../wflDevice/wflDevice.h" 14 | #include "../wflDevice/wflSerialDevice.h" 15 | 16 | //class Agent 17 | class Agent : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit Agent(QObject *parent = 0); 23 | virtual ~Agent(); 24 | 25 | WflDevice* activeDevice; 26 | 27 | QVector enumerateDevices(); 28 | //void flushDevices(); 29 | QByteArray getVersion(); 30 | int getMajorVersion(); 31 | int getMinorVersion(); 32 | int getPatchVersion(); 33 | QString getBuildNote(); 34 | QString getFirmwareUploadStatus(); 35 | int getFirmwareUploadProgress(); 36 | bool launchWfl(); 37 | bool internetAvailable(); 38 | QString waveFormsLiveBrowserPath; 39 | QThread* getThread(); 40 | 41 | 42 | signals: 43 | void activeDeviceChanged(QString activeDeviceName); 44 | void startReleaseDevice(); 45 | void softResetActiveDeviceSignal(); 46 | void releaseComplete(); 47 | void startUpdateActiveDeviceFirmware(QString hexFilePath, bool enterBootloader); 48 | void updateActiveDeviceFirmwareComplete(bool success); 49 | 50 | public slots: 51 | //WflDevice *createNewWflSerialDevice(QString address); 52 | void releaseActiveDevice(); 53 | bool setActiveDeviceByName(QString deviceName); 54 | bool updateActiveDeviceFirmware(QString hexFilePath, bool enterBootloader); 55 | 56 | 57 | private: 58 | //Variables 59 | int deviceCount; 60 | bool httpCapable; 61 | int majorVersion; 62 | int minorVersion; 63 | int patchVersion; 64 | QString buildNote; 65 | 66 | QString firmwareUploadStatus; 67 | DigilentPgm *pgm; 68 | 69 | }; 70 | 71 | #endif // AGENT_H 72 | -------------------------------------------------------------------------------- /installer/create-dmg/support/template.applescript: -------------------------------------------------------------------------------- 1 | on run (volumeName) 2 | tell application "Finder" 3 | tell disk (volumeName as string) 4 | open 5 | 6 | set theXOrigin to WINX 7 | set theYOrigin to WINY 8 | set theWidth to WINW 9 | set theHeight to WINH 10 | 11 | set theBottomRightX to (theXOrigin + theWidth) 12 | set theBottomRightY to (theYOrigin + theHeight) 13 | set dsStore to "\"" & "/Volumes/" & volumeName & "/" & ".DS_STORE\"" 14 | 15 | tell container window 16 | set current view to icon view 17 | set toolbar visible to false 18 | set statusbar visible to false 19 | set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY} 20 | set statusbar visible to false 21 | REPOSITION_HIDDEN_FILES_CLAUSE 22 | end tell 23 | 24 | set opts to the icon view options of container window 25 | tell opts 26 | set icon size to ICON_SIZE 27 | set text size to TEXT_SIZE 28 | set arrangement to not arranged 29 | end tell 30 | BACKGROUND_CLAUSE 31 | 32 | -- Positioning 33 | POSITION_CLAUSE 34 | 35 | -- Hiding 36 | HIDING_CLAUSE 37 | 38 | -- Application Link Clause 39 | APPLICATION_CLAUSE 40 | close 41 | open 42 | 43 | update without registering applications 44 | -- Force saving of the size 45 | delay 1 46 | 47 | tell container window 48 | set statusbar visible to false 49 | set the bounds to {theXOrigin, theYOrigin, theBottomRightX - 10, theBottomRightY - 10} 50 | end tell 51 | 52 | update without registering applications 53 | end tell 54 | 55 | delay 1 56 | 57 | tell disk (volumeName as string) 58 | tell container window 59 | set statusbar visible to false 60 | set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY} 61 | end tell 62 | 63 | update without registering applications 64 | end tell 65 | 66 | --give the finder some time to write the .DS_Store file 67 | delay 3 68 | 69 | set waitTime to 0 70 | set ejectMe to false 71 | repeat while ejectMe is false 72 | delay 1 73 | set waitTime to waitTime + 1 74 | 75 | if (do shell script "[ -f " & dsStore & " ]; echo $?") = "0" then set ejectMe to true 76 | end repeat 77 | log "waited " & waitTime & " seconds for .DS_STORE to be created." 78 | end tell 79 | end run 80 | -------------------------------------------------------------------------------- /digilent-agent.xcodeproj/project.xcworkspace/xcshareddata/digilent-agent.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "B5219A5B7F51D8FB3FDED3DA6AEF4D59AEB1318E", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "3C033380C2E9EEEAEA67503A530AD01E1352A642" : 9223372036854775807, 8 | "B5219A5B7F51D8FB3FDED3DA6AEF4D59AEB1318E" : 9223372036854775807, 9 | "4A46555535FE29AD2F0B011E56112C7396C3B5D7" : 9223372036854775807 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "3A5BD6A5-3E24-4778-8388-F48E75979337", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "3C033380C2E9EEEAEA67503A530AD01E1352A642" : "digilent-agent\/lib\/digilent\/qtSerial\/", 14 | "B5219A5B7F51D8FB3FDED3DA6AEF4D59AEB1318E" : "digilent-agent\/", 15 | "4A46555535FE29AD2F0B011E56112C7396C3B5D7" : "digilent-agent\/lib\/digilent\/pgm\/" 16 | }, 17 | "DVTSourceControlWorkspaceBlueprintNameKey" : "digilent-agent", 18 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 19 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "digilent-agent.xcodeproj", 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 21 | { 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Digilent\/qtSerial.git", 23 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 24 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3C033380C2E9EEEAEA67503A530AD01E1352A642" 25 | }, 26 | { 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Digilent\/pgm.git", 28 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 29 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4A46555535FE29AD2F0B011E56112C7396C3B5D7" 30 | }, 31 | { 32 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Digilent\/digilent-agent.git", 33 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 34 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "B5219A5B7F51D8FB3FDED3DA6AEF4D59AEB1318E" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /digilent-agent.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2016-11-02T11:00:21 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | QT += serialport 10 | QT += concurrent 11 | 12 | include(src/httpServer/core/httpserver.pri) 13 | 14 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 15 | 16 | TARGET = digilent-agent 17 | target.path = /usr/bin 18 | 19 | wwwRoot.path = /usr/share/digilent-agent/www 20 | wwwRoot.files = www/* 21 | 22 | INSTALLS += target 23 | INSTALLS += wwwRoot 24 | 25 | TEMPLATE = app 26 | CONFIG += qt 27 | 28 | CONFIG(debug, debug|release) { 29 | DEFINES += AGENT_BUILD_NOTE=\\\"DEBUG\\\" 30 | CONFIG+=console 31 | } 32 | 33 | 34 | SOURCES += \ 35 | src/httpServer/httpRouter.cpp \ 36 | src/main.cpp \ 37 | src/httpServer/debugController.cpp \ 38 | src/mainWindow.cpp \ 39 | src/core/comboBoxEventFilter.cpp \ 40 | src/httpServer/agentConfigCtrl.cpp \ 41 | src/core/agent.cpp \ 42 | src/wflDevice/wflDevice.cpp \ 43 | src/core/utils/runGuard.cpp \ 44 | lib/digilent/qtSerial/serial.cpp \ 45 | src/wflDevice/wflSerialDevice.cpp \ 46 | lib/digilent/pgm/digilentPgm.cpp \ 47 | lib/digilent/pgm/pgmBlock.cpp \ 48 | lib/digilent/qtHttp/httpClient.cpp \ 49 | 50 | 51 | 52 | HEADERS += \ 53 | src/httpServer/httpRouter.h \ 54 | src/mainWindow.h \ 55 | src/core/comboBoxEventFilter.h \ 56 | src/httpServer/agentConfigCtrl.h \ 57 | src/httpServer/debugController.h \ 58 | src/core/agent.h \ 59 | src/wflDevice/wflDevice.h \ 60 | src/core/utils/runGuard.h \ 61 | lib/digilent/qtSerial/serial.h \ 62 | src/wflDevice/wflSerialDevice.h \ 63 | lib/digilent/pgm/digilentPgm.h \ 64 | lib/digilent/pgm/pgmBlock.h \ 65 | lib/digilent/qtHttp/httpClient.h \ 66 | 67 | FORMS += \ 68 | mainWindow.ui 69 | 70 | RESOURCES += \ 71 | mainWindow.qrc 72 | 73 | RC_FILE = digilent-agent.rc 74 | ICON = images/icon.icns 75 | 76 | DISTFILES += \ 77 | # digilent-agent.ini 78 | lib/digilent/qtSerial/.gitignore \ 79 | lib/digilent/qtSerial/LICENSE \ 80 | lib/digilent/qtSerial/README.md \ 81 | lib/digilent/pgm/.gitignore \ 82 | lib/digilent/pgm/LICENSE 83 | 84 | OTHER_FILES += 85 | 86 | #QMAKE_CXXFLAGS += -static-libgcc -static-libstdc++ 87 | #QMAKE_LFLAGS += -static -lpthread -static-libgcc -static-libstdc++ 88 | 89 | -------------------------------------------------------------------------------- /src/httpServer/core/staticfilecontroller.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef STATICFILECONTROLLER_H 7 | #define STATICFILECONTROLLER_H 8 | 9 | #include 10 | #include 11 | #include "httpglobal.h" 12 | #include "httprequest.h" 13 | #include "httpresponse.h" 14 | #include "httprequesthandler.h" 15 | 16 | /** 17 | Delivers static files. It is usually called by the applications main request handler when 18 | the caller requests a path that is mapped to static files. 19 |

20 | The following settings are required in the config file: 21 |

22 |   path=../docroot
23 |   encoding=UTF-8
24 |   maxAge=60000
25 |   cacheTime=60000
26 |   cacheSize=1000000
27 |   maxCachedFileSize=65536
28 |   
29 | The path is relative to the directory of the config file. In case of windows, if the 30 | settings are in the registry, the path is relative to the current working directory. 31 |

32 | The encoding is sent to the web browser in case of text and html files. 33 |

34 | The cache improves performance of small files when loaded from a network 35 | drive. Large files are not cached. Files are cached as long as possible, 36 | when cacheTime=0. The maxAge value (in msec!) controls the remote browsers cache. 37 |

38 | Do not instantiate this class in each request, because this would make the file cache 39 | useless. Better create one instance during start-up and call it when the application 40 | received a related HTTP request. 41 | */ 42 | 43 | class DECLSPEC StaticFileController : public HttpRequestHandler { 44 | Q_OBJECT 45 | Q_DISABLE_COPY(StaticFileController) 46 | public: 47 | 48 | /** Constructor */ 49 | StaticFileController(QSettings* settings, QObject* parent = NULL); 50 | 51 | /** Generates the response */ 52 | void service(HttpRequest& request, HttpResponse& response); 53 | 54 | private: 55 | 56 | /** Encoding of text files */ 57 | QString encoding; 58 | 59 | /** Root directory of documents */ 60 | QString docroot; 61 | 62 | /** Maximum age of files in the browser cache */ 63 | int maxAge; 64 | 65 | struct CacheEntry { 66 | QByteArray document; 67 | qint64 created; 68 | QByteArray filename; 69 | }; 70 | 71 | /** Timeout for each cached file */ 72 | int cacheTimeout; 73 | 74 | /** Maximum size of files in cache, larger files are not cached */ 75 | int maxCachedFileSize; 76 | 77 | /** Cache storage */ 78 | QCache cache; 79 | 80 | /** Used to synchronize cache access for threads */ 81 | QMutex mutex; 82 | 83 | /** Set a content-type header in the response depending on the ending of the filename */ 84 | void setContentType(QString file, HttpResponse& response) const; 85 | }; 86 | 87 | #endif // STATICFILECONTROLLER_H 88 | -------------------------------------------------------------------------------- /installer/create-dmg/README.md: -------------------------------------------------------------------------------- 1 | create-dmg 2 | ========== 3 | 4 | A shell script to build fancy DMGs. 5 | 6 | 7 | Status and contribution policy 8 | ------------------------------ 9 | 10 | This project is maintained thanks to the contributors who send pull requests. The original author has no use for the project, so his only role is reviewing and merging pull requests. 11 | 12 | I will merge any pull request that adds something useful and does not break existing things. 13 | 14 | Starting in January 2015, everyone who gets a pull request merged gets commit access to the repository. 15 | 16 | 17 | Installation 18 | ------------ 19 | 20 | By being a shell script, yoursway-create-dmg installation is very simple. Simply download and run. 21 | 22 | > git clone https://github.com/andreyvit/yoursway-create-dmg.git 23 | > cd yoursway-create-dmg 24 | > ./create-dmg [options] 25 | 26 | 27 | Usage 28 | ----- 29 | 30 | > create-dmg [options...] [output\_name.dmg] [source\_folder] 31 | 32 | All contents of source\_folder will be copied into the disk image. 33 | 34 | **Options:** 35 | 36 | * **--volname [name]:** set volume name (displayed in the Finder sidebar and window title) 37 | * **--volicon [icon.icns]:** set volume icon 38 | * **--background [pic.png]:** set folder background image (provide png, gif, jpg) 39 | * **--window-pos [x y]:** set position the folder window 40 | * **--window-size [width height]:** set size of the folder window 41 | * **--text-size [text size]:** set window text size (10-16) 42 | * **--icon-size [icon size]:** set window icons size (up to 128) 43 | * **--icon [file name] [x y]:** set position of the file's icon 44 | * **--hide-extension [file name]:** hide the extension of file 45 | * **--custom-icon [file name]/[custom icon]/[sample file] [x y]:** set position and custom icon 46 | * **--app-drop-link [x y]:** make a drop link to Applications, at location x, y 47 | * **--eula [eula file]:** attach a license file to the dmg 48 | * **--no-internet-enable:** disable automatic mount© 49 | * **--version:** show tool version number 50 | * **-h, --help:** display the help 51 | 52 | 53 | Example 54 | ------- 55 | 56 | > \#!/bin/sh 57 | > test -f Application-Installer.dmg && rm Application-Installer.dmg 58 | > create-dmg \ 59 | > --volname "Application Installer" \ 60 | > --volicon "application\_icon.icns" \ 61 | > --background "installer\_background.png" \ 62 | > --window-pos 200 120 \ 63 | > --window-size 800 400 \ 64 | > --icon-size 100 \ 65 | > --icon Application.app 200 190 \ 66 | > --hide-extension Application.app \ 67 | > --app-drop-link 600 185 \ 68 | > Application-Installer.dmg \ 69 | > source\_folder/ 70 | 71 | 72 | Alternatives 73 | ------------ 74 | 75 | * [node-appdmg](https://github.com/LinusU/node-appdmg) 76 | * [dmgbuild](https://pypi.python.org/pypi/dmgbuild) 77 | * see the [StackOverflow question](http://stackoverflow.com/questions/96882/how-do-i-create-a-nice-looking-dmg-for-mac-os-x-using-command-line-tools) 78 | -------------------------------------------------------------------------------- /src/httpServer/core/httplistener.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "httplistener.h" 7 | #include "httpconnectionhandler.h" 8 | #include "httpconnectionhandlerpool.h" 9 | #include 10 | 11 | HttpListener::HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject *parent) 12 | : QTcpServer(parent) 13 | { 14 | qDebug() << "HttpListener::HttpListener()" << "thread: " << QThread::currentThread(); 15 | 16 | Q_ASSERT(settings!=0); 17 | Q_ASSERT(requestHandler!=0); 18 | pool=NULL; 19 | this->settings=settings; 20 | this->requestHandler=requestHandler; 21 | // Reqister type of socketDescriptor for signal/slot handling 22 | qRegisterMetaType("tSocketDescriptor"); 23 | // Start listening 24 | listen(); 25 | } 26 | 27 | 28 | HttpListener::~HttpListener() 29 | { 30 | close(); 31 | qDebug("HttpListener: destroyed"); 32 | } 33 | 34 | 35 | void HttpListener::listen() 36 | { 37 | if (!pool) 38 | { 39 | pool=new HttpConnectionHandlerPool(settings,requestHandler); 40 | } 41 | QString host = settings->value("host").toString(); 42 | int port=settings->value("port").toInt(); 43 | QTcpServer::listen(host.isEmpty() ? QHostAddress::Any : QHostAddress(host), port); 44 | if (!isListening()) 45 | { 46 | qCritical("HttpListener: Cannot bind on port %i: %s",port,qPrintable(errorString())); 47 | } 48 | else { 49 | qDebug("HttpListener: Listening on port %i",port); 50 | } 51 | } 52 | 53 | 54 | void HttpListener::close() { 55 | QTcpServer::close(); 56 | qDebug("HttpListener: closed"); 57 | if (pool) { 58 | delete pool; 59 | pool=NULL; 60 | } 61 | } 62 | 63 | void HttpListener::incomingConnection(tSocketDescriptor socketDescriptor) { 64 | #ifdef SUPERVERBOSE 65 | qDebug("HttpListener: New connection"); 66 | #endif 67 | 68 | HttpConnectionHandler* freeHandler=NULL; 69 | if (pool) 70 | { 71 | freeHandler=pool->getConnectionHandler(); 72 | } 73 | 74 | // Let the handler process the new connection. 75 | if (freeHandler) 76 | { 77 | // The descriptor is passed via signal/slot because the handler lives in another 78 | // thread and cannot open the socket when directly called by another thread. 79 | connect(this,SIGNAL(handleConnection(tSocketDescriptor)),freeHandler,SLOT(handleConnection(tSocketDescriptor))); 80 | emit handleConnection(socketDescriptor); 81 | disconnect(this,SIGNAL(handleConnection(tSocketDescriptor)),freeHandler,SLOT(handleConnection(tSocketDescriptor))); 82 | } 83 | else 84 | { 85 | // Reject the connection 86 | qDebug("HttpListener: Too many incoming connections"); 87 | QTcpSocket* socket=new QTcpSocket(this); 88 | socket->setSocketDescriptor(socketDescriptor); 89 | connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); 90 | socket->write("HTTP/1.1 503 too many connections\r\nConnection: close\r\n\r\nToo many connections\r\n"); 91 | socket->disconnectFromHost(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/httpServer/core/httplistener.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPLISTENER_H 7 | #define HTTPLISTENER_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include "httpglobal.h" 13 | #include "httpconnectionhandler.h" 14 | #include "httpconnectionhandlerpool.h" 15 | #include "httprequesthandler.h" 16 | 17 | /** 18 | Listens for incoming TCP connections and and passes all incoming HTTP requests to your implementation of HttpRequestHandler, 19 | which processes the request and generates the response (usually a HTML document). 20 |

21 | Example for the required settings in the config file: 22 |

23 |   ;host=192.168.0.100
24 |   port=8080
25 |   minThreads=1
26 |   maxThreads=10
27 |   cleanupInterval=1000
28 |   readTimeout=60000
29 |   ;sslKeyFile=ssl/my.key
30 |   ;sslCertFile=ssl/my.cert
31 |   maxRequestSize=16000
32 |   maxMultiPartSize=1000000
33 |   
34 | The optional host parameter binds the listener to one network interface. 35 | The listener handles all network interfaces if no host is configured. 36 | The port number specifies the incoming TCP port that this listener listens to. 37 | @see HttpConnectionHandlerPool for description of config settings minThreads, maxThreads, cleanupInterval and ssl settings 38 | @see HttpConnectionHandler for description of the readTimeout 39 | @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize 40 | */ 41 | 42 | class DECLSPEC HttpListener : public QTcpServer { 43 | Q_OBJECT 44 | Q_DISABLE_COPY(HttpListener) 45 | public: 46 | 47 | /** 48 | Constructor. 49 | Creates a connection pool and starts listening on the configured host and port. 50 | @param settings Configuration settings for the HTTP server. Must not be 0. 51 | @param requestHandler Processes each received HTTP request, usually by dispatching to controller classes. 52 | @param parent Parent object. 53 | @warning Ensure to close or delete the listener before deleting the request handler. 54 | */ 55 | HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent = NULL); 56 | 57 | /** Destructor */ 58 | virtual ~HttpListener(); 59 | 60 | /** 61 | Restart listeing after close(). 62 | */ 63 | void listen(); 64 | 65 | /** 66 | Closes the listener, waits until all pending requests are processed, 67 | then closes the connection pool. 68 | */ 69 | void close(); 70 | 71 | protected: 72 | 73 | /** Serves new incoming connection requests */ 74 | void incomingConnection(tSocketDescriptor socketDescriptor); 75 | 76 | private: 77 | 78 | /** Configuration settings for the HTTP server */ 79 | QSettings* settings; 80 | 81 | /** Point to the reuqest handler which processes all HTTP requests */ 82 | HttpRequestHandler* requestHandler; 83 | 84 | /** Pool of connection handlers */ 85 | HttpConnectionHandlerPool* pool; 86 | 87 | signals: 88 | 89 | /** 90 | Sent to the connection handler to process a new incoming connection. 91 | @param socketDescriptor references the accepted connection. 92 | */ 93 | 94 | void handleConnection(tSocketDescriptor socketDescriptor); 95 | 96 | }; 97 | 98 | #endif // HTTPLISTENER_H 99 | -------------------------------------------------------------------------------- /src/httpServer/core/httpconnectionhandlerpool.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPCONNECTIONHANDLERPOOL_H 2 | #define HTTPCONNECTIONHANDLERPOOL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "httpglobal.h" 9 | #include "httpconnectionhandler.h" 10 | 11 | /** 12 | Pool of http connection handlers. The size of the pool grows and 13 | shrinks on demand. 14 |

15 | Example for the required configuration settings: 16 |

17 |   minThreads=4
18 |   maxThreads=100
19 |   cleanupInterval=60000
20 |   readTimeout=60000
21 |   ;sslKeyFile=ssl/my.key
22 |   ;sslCertFile=ssl/my.cert
23 |   maxRequestSize=16000
24 |   maxMultiPartSize=1000000
25 |   
26 | After server start, the size of the thread pool is always 0. Threads 27 | are started on demand when requests come in. The cleanup timer reduces 28 | the number of idle threads slowly by closing one thread in each interval. 29 | But the configured minimum number of threads are kept running. 30 |

31 | For SSL support, you need an OpenSSL certificate file and a key file. 32 | Both can be created with the command 33 |

34 |       openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout my.key -out my.cert
35 |   
36 |

37 | Visit http://slproweb.com/products/Win32OpenSSL.html to download the Light version of OpenSSL for Windows. 38 |

39 | Please note that a listener with SSL settings can only handle HTTPS protocol. To 40 | support both HTTP and HTTPS simultaneously, you need to start two listeners on different ports - 41 | one with SLL and one without SSL. 42 | @see HttpConnectionHandler for description of the readTimeout 43 | @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize 44 | */ 45 | 46 | class DECLSPEC HttpConnectionHandlerPool : public QObject { 47 | Q_OBJECT 48 | Q_DISABLE_COPY(HttpConnectionHandlerPool) 49 | public: 50 | 51 | /** 52 | Constructor. 53 | @param settings Configuration settings for the HTTP server. Must not be 0. 54 | @param requestHandler The handler that will process each received HTTP request. 55 | @warning The requestMapper gets deleted by the destructor of this pool 56 | */ 57 | HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler); 58 | 59 | /** Destructor */ 60 | virtual ~HttpConnectionHandlerPool(); 61 | 62 | /** Get a free connection handler, or 0 if not available. */ 63 | HttpConnectionHandler* getConnectionHandler(); 64 | 65 | private: 66 | 67 | /** Settings for this pool */ 68 | QSettings* settings; 69 | 70 | /** Will be assigned to each Connectionhandler during their creation */ 71 | HttpRequestHandler* requestHandler; 72 | 73 | /** Pool of connection handlers */ 74 | QList pool; 75 | 76 | /** Timer to clean-up unused connection handler */ 77 | QTimer cleanupTimer; 78 | 79 | /** Used to synchronize threads */ 80 | QMutex mutex; 81 | 82 | /** The SSL configuration (certificate, key and other settings) */ 83 | QSslConfiguration* sslConfiguration; 84 | 85 | /** Load SSL configuration */ 86 | void loadSslConfig(); 87 | 88 | private slots: 89 | 90 | /** Received from the clean-up timer. */ 91 | void cleanup(); 92 | 93 | }; 94 | 95 | #endif // HTTPCONNECTIONHANDLERPOOL_H 96 | -------------------------------------------------------------------------------- /src/httpServer/core/httpsessionstore.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPSESSIONSTORE_H 7 | #define HTTPSESSIONSTORE_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "httpglobal.h" 14 | #include "httpsession.h" 15 | #include "httpresponse.h" 16 | #include "httprequest.h" 17 | 18 | /** 19 | Stores HTTP sessions and deletes them when they have expired. 20 | The following configuration settings are required in the config file: 21 |

 22 |   expirationTime=3600000
 23 |   cookieName=sessionid
 24 |   
25 | The following additional configurations settings are optionally: 26 |
 27 |   cookiePath=/
 28 |   cookieComment=Session ID
 29 |   ;cookieDomain=stefanfrings.de
 30 |   
31 | */ 32 | 33 | class DECLSPEC HttpSessionStore : public QObject { 34 | Q_OBJECT 35 | Q_DISABLE_COPY(HttpSessionStore) 36 | public: 37 | 38 | /** Constructor. */ 39 | HttpSessionStore(QSettings* settings, QObject* parent=NULL); 40 | 41 | /** Destructor */ 42 | virtual ~HttpSessionStore(); 43 | 44 | /** 45 | Get the ID of the current HTTP session, if it is valid. 46 | This method is thread safe. 47 | @warning Sessions may expire at any time, so subsequent calls of 48 | getSession() might return a new session with a different ID. 49 | @param request Used to get the session cookie 50 | @param response Used to get and set the new session cookie 51 | @return Empty string, if there is no valid session. 52 | */ 53 | QByteArray getSessionId(HttpRequest& request, HttpResponse& response); 54 | 55 | /** 56 | Get the session of a HTTP request, eventually create a new one. 57 | This method is thread safe. New sessions can only be created before 58 | the first byte has been written to the HTTP response. 59 | @param request Used to get the session cookie 60 | @param response Used to get and set the new session cookie 61 | @param allowCreate can be set to false, to disable the automatic creation of a new session. 62 | @return If autoCreate is disabled, the function returns a null session if there is no session. 63 | @see HttpSession::isNull() 64 | */ 65 | HttpSession getSession(HttpRequest& request, HttpResponse& response, bool allowCreate=true); 66 | 67 | /** 68 | Get a HTTP session by it's ID number. 69 | This method is thread safe. 70 | @return If there is no such session, the function returns a null session. 71 | @param id ID number of the session 72 | @see HttpSession::isNull() 73 | */ 74 | HttpSession getSession(const QByteArray id); 75 | 76 | /** Delete a session */ 77 | void removeSession(HttpSession session); 78 | 79 | protected: 80 | /** Storage for the sessions */ 81 | QMap sessions; 82 | 83 | private: 84 | 85 | /** Configuration settings */ 86 | QSettings* settings; 87 | 88 | /** Timer to remove expired sessions */ 89 | QTimer cleanupTimer; 90 | 91 | /** Name of the session cookie */ 92 | QByteArray cookieName; 93 | 94 | /** Time when sessions expire (in ms)*/ 95 | int expirationTime; 96 | 97 | /** Used to synchronize threads */ 98 | QMutex mutex; 99 | 100 | private slots: 101 | 102 | /** Called every minute to cleanup expired sessions. */ 103 | void sessionTimerEvent(); 104 | }; 105 | 106 | #endif // HTTPSESSIONSTORE_H 107 | -------------------------------------------------------------------------------- /src/httpServer/core/httpsession.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPSESSION_H 7 | #define HTTPSESSION_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include "httpglobal.h" 13 | 14 | /** 15 | This class stores data for a single HTTP session. 16 | A session can store any number of key/value pairs. This class uses implicit 17 | sharing for read and write access. This class is thread safe. 18 | @see HttpSessionStore should be used to create and get instances of this class. 19 | */ 20 | 21 | class DECLSPEC HttpSession { 22 | 23 | public: 24 | 25 | /** 26 | Constructor. 27 | @param canStore The session can store data, if this parameter is true. 28 | Otherwise all calls to set() and remove() do not have any effect. 29 | */ 30 | HttpSession(bool canStore=false); 31 | 32 | /** 33 | Copy constructor. Creates another HttpSession object that shares the 34 | data of the other object. 35 | */ 36 | HttpSession(const HttpSession& other); 37 | 38 | /** 39 | Copy operator. Detaches from the current shared data and attaches to 40 | the data of the other object. 41 | */ 42 | HttpSession& operator= (const HttpSession& other); 43 | 44 | 45 | /** 46 | Destructor. Detaches from the shared data. 47 | */ 48 | virtual ~HttpSession(); 49 | 50 | /** Get the unique ID of this session. This method is thread safe. */ 51 | QByteArray getId() const; 52 | 53 | /** 54 | Null sessions cannot store data. All calls to set() and remove() 55 | do not have any effect.This method is thread safe. 56 | */ 57 | bool isNull() const; 58 | 59 | /** Set a value. This method is thread safe. */ 60 | void set(const QByteArray& key, const QVariant& value); 61 | 62 | /** Remove a value. This method is thread safe. */ 63 | void remove(const QByteArray& key); 64 | 65 | /** Get a value. This method is thread safe. */ 66 | QVariant get(const QByteArray& key) const; 67 | 68 | /** Check if a key exists. This method is thread safe. */ 69 | bool contains(const QByteArray& key) const; 70 | 71 | /** 72 | Get a copy of all data stored in this session. 73 | Changes to the session do not affect the copy and vice versa. 74 | This method is thread safe. 75 | */ 76 | QMap getAll() const; 77 | 78 | /** 79 | Get the timestamp of last access. That is the time when the last 80 | HttpSessionStore::getSession() has been called. 81 | This method is thread safe. 82 | */ 83 | qint64 getLastAccess() const; 84 | 85 | /** 86 | Set the timestamp of last access, to renew the timeout period. 87 | Called by HttpSessionStore::getSession(). 88 | This method is thread safe. 89 | */ 90 | void setLastAccess(); 91 | 92 | private: 93 | 94 | struct HttpSessionData { 95 | 96 | /** Unique ID */ 97 | QByteArray id; 98 | 99 | /** Timestamp of last access, set by the HttpSessionStore */ 100 | qint64 lastAccess; 101 | 102 | /** Reference counter */ 103 | int refCount; 104 | 105 | /** Used to synchronize threads */ 106 | QReadWriteLock lock; 107 | 108 | /** Storage for the key/value pairs; */ 109 | QMap values; 110 | 111 | }; 112 | 113 | /** Pointer to the shared data. */ 114 | HttpSessionData* dataPtr; 115 | 116 | }; 117 | 118 | #endif // HTTPSESSION_H 119 | -------------------------------------------------------------------------------- /src/httpServer/core/httpconnectionhandler.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPCONNECTIONHANDLER_H 7 | #define HTTPCONNECTIONHANDLER_H 8 | 9 | #ifndef QT_NO_OPENSSL 10 | #include 11 | #endif 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "httpglobal.h" 17 | #include "httprequest.h" 18 | #include "httprequesthandler.h" 19 | 20 | /** Alias type definition, for compatibility to different Qt versions */ 21 | #if QT_VERSION >= 0x050000 22 | typedef qintptr tSocketDescriptor; 23 | #else 24 | typedef int tSocketDescriptor; 25 | #endif 26 | 27 | /** Alias for QSslConfiguration if OpenSSL is not supported */ 28 | #ifdef QT_NO_OPENSSL 29 | #define QSslConfiguration QObject 30 | #endif 31 | 32 | /** 33 | The connection handler accepts incoming connections and dispatches incoming requests to to a 34 | request mapper. Since HTTP clients can send multiple requests before waiting for the response, 35 | the incoming requests are queued and processed one after the other. 36 |

37 | Example for the required configuration settings: 38 |

 39 |   readTimeout=60000
 40 |   maxRequestSize=16000
 41 |   maxMultiPartSize=1000000
 42 |   
43 |

44 | The readTimeout value defines the maximum time to wait for a complete HTTP request. 45 | @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize. 46 | */ 47 | class DECLSPEC HttpConnectionHandler : public QThread { 48 | Q_OBJECT 49 | Q_DISABLE_COPY(HttpConnectionHandler) 50 | 51 | public: 52 | 53 | /** 54 | Constructor. 55 | @param settings Configuration settings of the HTTP webserver 56 | @param requestHandler Handler that will process each incoming HTTP request 57 | @param sslConfiguration SSL (HTTPS) will be used if not NULL 58 | */ 59 | HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler, QSslConfiguration* sslConfiguration=NULL); 60 | 61 | /** Destructor */ 62 | virtual ~HttpConnectionHandler(); 63 | 64 | /** Returns true, if this handler is in use. */ 65 | bool isBusy(); 66 | 67 | /** Mark this handler as busy */ 68 | void setBusy(); 69 | 70 | private: 71 | 72 | /** Configuration settings */ 73 | QSettings* settings; 74 | 75 | /** TCP socket of the current connection */ 76 | QTcpSocket* socket; 77 | 78 | /** Time for read timeout detection */ 79 | QTimer readTimer; 80 | 81 | /** Storage for the current incoming HTTP request */ 82 | HttpRequest* currentRequest; 83 | 84 | /** Dispatches received requests to services */ 85 | HttpRequestHandler* requestHandler; 86 | 87 | /** This shows the busy-state from a very early time */ 88 | bool busy; 89 | 90 | /** Configuration for SSL */ 91 | QSslConfiguration* sslConfiguration; 92 | 93 | /** Executes the threads own event loop */ 94 | void run(); 95 | 96 | /** Create SSL or TCP socket */ 97 | void createSocket(); 98 | 99 | public slots: 100 | 101 | /** 102 | Received from from the listener, when the handler shall start processing a new connection. 103 | @param socketDescriptor references the accepted connection. 104 | */ 105 | void handleConnection(tSocketDescriptor socketDescriptor); 106 | 107 | private slots: 108 | 109 | /** Received from the socket when a read-timeout occured */ 110 | void readTimeout(); 111 | 112 | /** Received from the socket when incoming data can be read */ 113 | void read(); 114 | 115 | /** Received from the socket when a connection has been closed */ 116 | void disconnected(); 117 | 118 | }; 119 | 120 | #endif // HTTPCONNECTIONHANDLER_H 121 | -------------------------------------------------------------------------------- /.qmake.stash: -------------------------------------------------------------------------------- 1 | QMAKE_DEFAULT_INCDIRS = \ 2 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0/include \ 3 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0/include-fixed \ 4 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include \ 5 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++ \ 6 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++/i686-w64-mingw32 \ 7 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++/backward 8 | QMAKE_DEFAULT_LIBDIRS = \ 9 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0 \ 10 | C:/Qt/Tools/mingw530_32/lib/gcc \ 11 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/lib \ 12 | C:/Qt/Tools/mingw530_32/lib 13 | QMAKE_XCODE_DEVELOPER_PATH = /Applications/Xcode.app/Contents/Developer 14 | QMAKE_XCODE_VERSION = 8.1 15 | QMAKE_MAC_SDK.macosx.Path = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk 16 | QMAKE_MAC_SDK.macosx.PlatformPath = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform 17 | QMAKE_MAC_SDK.macosx.SDKVersion = 10.12 18 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_CC = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang 19 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_CXX = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ 20 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_FIX_RPATH = \ 21 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool \ 22 | -id 23 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_AR = \ 24 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar \ 25 | cq 26 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_RANLIB = \ 27 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib \ 28 | -s 29 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_LINK = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ 30 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_LINK_SHLIB = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ 31 | QMAKE_MAC_SDK.macx-clang.macosx.QMAKE_ACTOOL = /Applications/Xcode.app/Contents/Developer/usr/bin/actool 32 | QMAKE_CXX.INCDIRS = \ 33 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0/include \ 34 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0/include-fixed \ 35 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include \ 36 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++ \ 37 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++/i686-w64-mingw32 \ 38 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++/backward \ 39 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 \ 40 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/include \ 41 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include \ 42 | /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include 43 | QMAKE_CXX.LIBDIRS = \ 44 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0 \ 45 | C:/Qt/Tools/mingw530_32/lib/gcc \ 46 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/lib \ 47 | C:/Qt/Tools/mingw530_32/lib 48 | QMAKE_CXX.QT_COMPILER_STDCXX = 199711L 49 | QMAKE_CXX.QMAKE_APPLE_CC = 6000 50 | QMAKE_CXX.QT_APPLE_CLANG_MAJOR_VERSION = 8 51 | QMAKE_CXX.QT_APPLE_CLANG_MINOR_VERSION = 1 52 | QMAKE_CXX.QT_APPLE_CLANG_PATCH_VERSION = 0 53 | QMAKE_CXX.QT_GCC_MAJOR_VERSION = 4 54 | QMAKE_CXX.QT_GCC_MINOR_VERSION = 2 55 | QMAKE_CXX.QT_GCC_PATCH_VERSION = 1 56 | QMAKE_CXX.COMPILER_MACROS = \ 57 | QT_COMPILER_STDCXX \ 58 | QMAKE_APPLE_CC \ 59 | QT_APPLE_CLANG_MAJOR_VERSION \ 60 | QT_APPLE_CLANG_MINOR_VERSION \ 61 | QT_APPLE_CLANG_PATCH_VERSION \ 62 | QT_GCC_MAJOR_VERSION \ 63 | QT_GCC_MINOR_VERSION \ 64 | QT_GCC_PATCH_VERSION 65 | -------------------------------------------------------------------------------- /src/httpServer/core/httpcookie.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPCOOKIE_H 7 | #define HTTPCOOKIE_H 8 | 9 | #include 10 | #include 11 | #include "httpglobal.h" 12 | 13 | /** 14 | HTTP cookie as defined in RFC 2109. This class can also parse 15 | RFC 2965 cookies, but skips fields that are not defined in RFC 16 | 2109. 17 | */ 18 | 19 | class DECLSPEC HttpCookie 20 | { 21 | public: 22 | 23 | /** Creates an empty cookie */ 24 | HttpCookie(); 25 | 26 | /** 27 | Create a cookie and set name/value pair. 28 | @param name name of the cookie 29 | @param value value of the cookie 30 | @param maxAge maximum age of the cookie in seconds. 0=discard immediately 31 | @param path Path for that the cookie will be sent, default="/" which means the whole domain 32 | @param comment Optional comment, may be displayed by the web browser somewhere 33 | @param domain Optional domain for that the cookie will be sent. Defaults to the current domain 34 | @param secure If true, the cookie will be sent by the browser to the server only on secure connections 35 | @param httpOnly If true, the browser does not allow client-side scripts to access the cookie 36 | */ 37 | HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path="/", const QByteArray comment=QByteArray(), const QByteArray domain=QByteArray(), const bool secure=false, const bool httpOnly=false); 38 | 39 | /** 40 | Create a cookie from a string. 41 | @param source String as received in a HTTP Cookie2 header. 42 | */ 43 | HttpCookie(const QByteArray source); 44 | 45 | /** Convert this cookie to a string that may be used in a Set-Cookie header. */ 46 | QByteArray toByteArray() const ; 47 | 48 | /** 49 | Split a string list into parts, where each part is delimited by semicolon. 50 | Semicolons within double quotes are skipped. Double quotes are removed. 51 | */ 52 | static QList splitCSV(const QByteArray source); 53 | 54 | /** Set the name of this cookie */ 55 | void setName(const QByteArray name); 56 | 57 | /** Set the value of this cookie */ 58 | void setValue(const QByteArray value); 59 | 60 | /** Set the comment of this cookie */ 61 | void setComment(const QByteArray comment); 62 | 63 | /** Set the domain of this cookie */ 64 | void setDomain(const QByteArray domain); 65 | 66 | /** Set the maximum age of this cookie in seconds. 0=discard immediately */ 67 | void setMaxAge(const int maxAge); 68 | 69 | /** Set the path for that the cookie will be sent, default="/" which means the whole domain */ 70 | void setPath(const QByteArray path); 71 | 72 | /** Set secure mode, so that the cookie will be sent by the browser to the server only on secure connections */ 73 | void setSecure(const bool secure); 74 | 75 | /** Set HTTP-only mode, so that he browser does not allow client-side scripts to access the cookie */ 76 | void setHttpOnly(const bool httpOnly); 77 | 78 | /** Get the name of this cookie */ 79 | QByteArray getName() const; 80 | 81 | /** Get the value of this cookie */ 82 | QByteArray getValue() const; 83 | 84 | /** Get the comment of this cookie */ 85 | QByteArray getComment() const; 86 | 87 | /** Get the domain of this cookie */ 88 | QByteArray getDomain() const; 89 | 90 | /** Get the maximum age of this cookie in seconds. */ 91 | int getMaxAge() const; 92 | 93 | /** Set the path of this cookie */ 94 | QByteArray getPath() const; 95 | 96 | /** Get the secure flag of this cookie */ 97 | bool getSecure() const; 98 | 99 | /** Get the HTTP-only flag of this cookie */ 100 | bool getHttpOnly() const; 101 | 102 | /** Returns always 1 */ 103 | int getVersion() const; 104 | 105 | private: 106 | 107 | QByteArray name; 108 | QByteArray value; 109 | QByteArray comment; 110 | QByteArray domain; 111 | int maxAge; 112 | QByteArray path; 113 | bool secure; 114 | bool httpOnly; 115 | int version; 116 | 117 | }; 118 | 119 | #endif // HTTPCOOKIE_H 120 | -------------------------------------------------------------------------------- /src/httpServer/httpRouter.cpp: -------------------------------------------------------------------------------- 1 | //HTTP Controllers 2 | #include "httpRouter.h" 3 | #include "debugController.h" 4 | 5 | StaticFileController* HttpRouter::staticFileController = 0; 6 | 7 | HttpRouter::HttpRouter(Agent* agent, QObject* parent) : HttpRequestHandler(parent) { 8 | qDebug() << "HttpRouter::HttpRouter()" << "Thread" << QThread::currentThread(); 9 | 10 | this->agent = agent; 11 | agentConfigCtrl = new AgentConfigCtrl(this->agent); 12 | } 13 | 14 | void HttpRouter::service(HttpRequest& request, HttpResponse& response) { 15 | 16 | QByteArray path = request.getPath(); 17 | QByteArray method = request.getMethod(); 18 | 19 | qDebug() << "HttpRouter: method = " << method << "path = ", path.data(); 20 | 21 | if(method == "OPTIONS"){ 22 | response.setHeader("Access-Control-Allow-Headers", "Content-Type"); 23 | response.setHeader("Access-Control-Allow-Origin", "*"); 24 | response.setHeader("Access-Control-Max-Age", "86400"); 25 | response.write("Options Response....", true); 26 | } 27 | else if (path=="/config" || path=="/config/") { 28 | agentConfigCtrl->service(request, response); 29 | } 30 | else if (path=="/debug" || path=="/debug/") { 31 | qDebug("Routing To Debug Controller"); 32 | DebugController(this).service(request, response); 33 | } 34 | else if (path=="/" && method == "POST") { 35 | 36 | //Add headers and return device call response to original requester 37 | response.setHeader("Access-Control-Allow-Origin", "*"); 38 | response.setHeader("Cache-Control", "no-cache"); 39 | response.setHeader("Connection", "close"); 40 | response.setHeader("Content-Type", "application/json"); 41 | response.setStatus(200, "OK"); 42 | 43 | if(agent->activeDevice == 0) 44 | { 45 | qDebug("No Active Device Selected!!!"); 46 | QJsonObject res = QJsonObject(); 47 | QJsonArray agentArray = QJsonArray(); 48 | QJsonObject statusObj = QJsonObject(); 49 | statusObj.insert("statusCode", qint64(0x80000666)); 50 | statusObj.insert("statusText", "No active device"); 51 | agentArray.append(statusObj); 52 | res.insert("agent", agentArray); 53 | 54 | response.write(QJsonDocument(res).toJson(), true); 55 | //TODO Send Back Command Response 56 | } 57 | else 58 | { 59 | QEventLoop loop; 60 | //Connect slots and signals 61 | connect(this, SIGNAL(deviceComplete()), &loop, SLOT(quit())); 62 | connect(agent->activeDevice, SIGNAL(execCommandComplete(QByteArray)), this, SLOT(onComplete(QByteArray))); 63 | 64 | waitingForResponse = true; 65 | qDebug("::::Request:::: \n %s", request.getBody().data()); 66 | agent->activeDevice->execCommand(request.getBody()); 67 | 68 | //Wait for signal that device call has returned 69 | if(waitingForResponse){ 70 | qDebug("HttpRouter Loop Begin"); 71 | loop.exec(); 72 | qDebug("HttpRouter Loop Done"); 73 | } 74 | qDebug("::::Response:::: \n %s", reply.data()); 75 | response.write(reply, true); 76 | 77 | //Disconnect signals to prevent multiple responses on subsequent calls 78 | if(disconnect(agent->activeDevice, SIGNAL(execCommandComplete(QByteArray)), this, SLOT(onComplete(QByteArray)))) 79 | { 80 | qDebug("Succesfully disconnected execCommandComplete signal"); 81 | } 82 | else 83 | { 84 | qDebug("Failed to disconnected execCommandComplete signal"); 85 | } 86 | 87 | } 88 | } 89 | else { 90 | qDebug("Routing To Static Controller"); 91 | staticFileController->service(request, response); 92 | } 93 | qDebug("HttpRouter: Request Complete"); 94 | } 95 | 96 | void HttpRouter::onComplete(QByteArray reply){ 97 | qDebug("HttpRouter::onComplete(): %s", reply.data()); 98 | waitingForResponse = false; 99 | this->reply = reply; 100 | //qDebug() << this->reply; 101 | emit deviceComplete(); 102 | } 103 | 104 | -------------------------------------------------------------------------------- /xcshareddata/xcschemes/digilent-agent.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 58 | 67 | 68 | 74 | 75 | 76 | 77 | 81 | 82 | 83 | 84 | 85 | 86 | 92 | 93 | 99 | 100 | 101 | 102 | 104 | 105 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/httpServer/core/httpsessionstore.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "httpsessionstore.h" 7 | #include 8 | #include 9 | 10 | HttpSessionStore::HttpSessionStore(QSettings* settings, QObject* parent) 11 | :QObject(parent) 12 | { 13 | this->settings=settings; 14 | connect(&cleanupTimer,SIGNAL(timeout()),this,SLOT(sessionTimerEvent())); 15 | cleanupTimer.start(60000); 16 | cookieName=settings->value("cookieName","sessionid").toByteArray(); 17 | expirationTime=settings->value("expirationTime",3600000).toInt(); 18 | qDebug("HttpSessionStore: Sessions expire after %i milliseconds",expirationTime); 19 | } 20 | 21 | HttpSessionStore::~HttpSessionStore() 22 | { 23 | cleanupTimer.stop(); 24 | } 25 | 26 | QByteArray HttpSessionStore::getSessionId(HttpRequest& request, HttpResponse& response) 27 | { 28 | // The session ID in the response has priority because this one will be used in the next request. 29 | mutex.lock(); 30 | // Get the session ID from the response cookie 31 | QByteArray sessionId=response.getCookies().value(cookieName).getValue(); 32 | if (sessionId.isEmpty()) 33 | { 34 | // Get the session ID from the request cookie 35 | sessionId=request.getCookie(cookieName); 36 | } 37 | // Clear the session ID if there is no such session in the storage. 38 | if (!sessionId.isEmpty()) 39 | { 40 | if (!sessions.contains(sessionId)) 41 | { 42 | qDebug("HttpSessionStore: received invalid session cookie with ID %s",sessionId.data()); 43 | sessionId.clear(); 44 | } 45 | } 46 | mutex.unlock(); 47 | return sessionId; 48 | } 49 | 50 | HttpSession HttpSessionStore::getSession(HttpRequest& request, HttpResponse& response, bool allowCreate) 51 | { 52 | QByteArray sessionId=getSessionId(request,response); 53 | mutex.lock(); 54 | if (!sessionId.isEmpty()) 55 | { 56 | HttpSession session=sessions.value(sessionId); 57 | if (!session.isNull()) 58 | { 59 | mutex.unlock(); 60 | // Refresh the session cookie 61 | QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray(); 62 | QByteArray cookiePath=settings->value("cookiePath").toByteArray(); 63 | QByteArray cookieComment=settings->value("cookieComment").toByteArray(); 64 | QByteArray cookieDomain=settings->value("cookieDomain").toByteArray(); 65 | response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain)); 66 | session.setLastAccess(); 67 | return session; 68 | } 69 | } 70 | // Need to create a new session 71 | if (allowCreate) 72 | { 73 | QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray(); 74 | QByteArray cookiePath=settings->value("cookiePath").toByteArray(); 75 | QByteArray cookieComment=settings->value("cookieComment").toByteArray(); 76 | QByteArray cookieDomain=settings->value("cookieDomain").toByteArray(); 77 | HttpSession session(true); 78 | qDebug("HttpSessionStore: create new session with ID %s",session.getId().data()); 79 | sessions.insert(session.getId(),session); 80 | response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain)); 81 | mutex.unlock(); 82 | return session; 83 | } 84 | // Return a null session 85 | mutex.unlock(); 86 | return HttpSession(); 87 | } 88 | 89 | HttpSession HttpSessionStore::getSession(const QByteArray id) 90 | { 91 | mutex.lock(); 92 | HttpSession session=sessions.value(id); 93 | mutex.unlock(); 94 | session.setLastAccess(); 95 | return session; 96 | } 97 | 98 | void HttpSessionStore::sessionTimerEvent() 99 | { 100 | mutex.lock(); 101 | qint64 now=QDateTime::currentMSecsSinceEpoch(); 102 | QMap::iterator i = sessions.begin(); 103 | while (i != sessions.end()) 104 | { 105 | QMap::iterator prev = i; 106 | ++i; 107 | HttpSession session=prev.value(); 108 | qint64 lastAccess=session.getLastAccess(); 109 | if (now-lastAccess>expirationTime) 110 | { 111 | qDebug("HttpSessionStore: session %s expired",session.getId().data()); 112 | sessions.erase(prev); 113 | } 114 | } 115 | mutex.unlock(); 116 | } 117 | 118 | 119 | /** Delete a session */ 120 | void HttpSessionStore::removeSession(HttpSession session) 121 | { 122 | mutex.lock(); 123 | sessions.remove(session.getId()); 124 | mutex.unlock(); 125 | } 126 | -------------------------------------------------------------------------------- /digilent-agent.xcodeproj/xcshareddata/xcschemes/digilent-agent.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 70 | 72 | 78 | 79 | 80 | 81 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 98 | 104 | 105 | 106 | 107 | 109 | 110 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/httpServer/core/httpsession.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "httpsession.h" 7 | #include 8 | #include 9 | 10 | 11 | HttpSession::HttpSession(bool canStore) 12 | { 13 | if (canStore) 14 | { 15 | dataPtr=new HttpSessionData(); 16 | dataPtr->refCount=1; 17 | dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch(); 18 | dataPtr->id=QUuid::createUuid().toString().toLocal8Bit(); 19 | #ifdef SUPERVERBOSE 20 | qDebug("HttpSession: created new session data with id %s",dataPtr->id.data()); 21 | #endif 22 | } 23 | else 24 | { 25 | dataPtr=0; 26 | } 27 | } 28 | 29 | HttpSession::HttpSession(const HttpSession& other) 30 | { 31 | dataPtr=other.dataPtr; 32 | if (dataPtr) 33 | { 34 | dataPtr->lock.lockForWrite(); 35 | dataPtr->refCount++; 36 | #ifdef SUPERVERBOSE 37 | qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount); 38 | #endif 39 | dataPtr->lock.unlock(); 40 | } 41 | } 42 | 43 | HttpSession& HttpSession::operator= (const HttpSession& other) 44 | { 45 | HttpSessionData* oldPtr=dataPtr; 46 | dataPtr=other.dataPtr; 47 | if (dataPtr) 48 | { 49 | dataPtr->lock.lockForWrite(); 50 | dataPtr->refCount++; 51 | #ifdef SUPERVERBOSE 52 | qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount); 53 | #endif 54 | dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch(); 55 | dataPtr->lock.unlock(); 56 | } 57 | if (oldPtr) 58 | { 59 | int refCount; 60 | oldPtr->lock.lockForRead(); 61 | refCount=oldPtr->refCount--; 62 | #ifdef SUPERVERBOSE 63 | qDebug("HttpSession: refCount of %s is %i",oldPtr->id.data(),oldPtr->refCount); 64 | #endif 65 | oldPtr->lock.unlock(); 66 | if (refCount==0) 67 | { 68 | delete oldPtr; 69 | } 70 | } 71 | return *this; 72 | } 73 | 74 | HttpSession::~HttpSession() 75 | { 76 | if (dataPtr) { 77 | int refCount; 78 | dataPtr->lock.lockForRead(); 79 | refCount=--dataPtr->refCount; 80 | #ifdef SUPERVERBOSE 81 | qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount); 82 | #endif 83 | dataPtr->lock.unlock(); 84 | if (refCount==0) 85 | { 86 | qDebug("HttpSession: deleting data"); 87 | delete dataPtr; 88 | } 89 | } 90 | } 91 | 92 | 93 | QByteArray HttpSession::getId() const 94 | { 95 | if (dataPtr) 96 | { 97 | return dataPtr->id; 98 | } 99 | else 100 | { 101 | return QByteArray(); 102 | } 103 | } 104 | 105 | bool HttpSession::isNull() const { 106 | return dataPtr==0; 107 | } 108 | 109 | void HttpSession::set(const QByteArray& key, const QVariant& value) 110 | { 111 | if (dataPtr) 112 | { 113 | dataPtr->lock.lockForWrite(); 114 | dataPtr->values.insert(key,value); 115 | dataPtr->lock.unlock(); 116 | } 117 | } 118 | 119 | void HttpSession::remove(const QByteArray& key) 120 | { 121 | if (dataPtr) 122 | { 123 | dataPtr->lock.lockForWrite(); 124 | dataPtr->values.remove(key); 125 | dataPtr->lock.unlock(); 126 | } 127 | } 128 | 129 | QVariant HttpSession::get(const QByteArray& key) const 130 | { 131 | QVariant value; 132 | if (dataPtr) 133 | { 134 | dataPtr->lock.lockForRead(); 135 | value=dataPtr->values.value(key); 136 | dataPtr->lock.unlock(); 137 | } 138 | return value; 139 | } 140 | 141 | bool HttpSession::contains(const QByteArray& key) const 142 | { 143 | bool found=false; 144 | if (dataPtr) 145 | { 146 | dataPtr->lock.lockForRead(); 147 | found=dataPtr->values.contains(key); 148 | dataPtr->lock.unlock(); 149 | } 150 | return found; 151 | } 152 | 153 | QMap HttpSession::getAll() const 154 | { 155 | QMap values; 156 | if (dataPtr) 157 | { 158 | dataPtr->lock.lockForRead(); 159 | values=dataPtr->values; 160 | dataPtr->lock.unlock(); 161 | } 162 | return values; 163 | } 164 | 165 | qint64 HttpSession::getLastAccess() const 166 | { 167 | qint64 value=0; 168 | if (dataPtr) 169 | { 170 | dataPtr->lock.lockForRead(); 171 | value=dataPtr->lastAccess; 172 | dataPtr->lock.unlock(); 173 | } 174 | return value; 175 | } 176 | 177 | 178 | void HttpSession::setLastAccess() 179 | { 180 | if (dataPtr) 181 | { 182 | dataPtr->lock.lockForRead(); 183 | dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch(); 184 | dataPtr->lock.unlock(); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /mainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 496 10 | 437 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 53 21 | 21 22 | 104 23 | 51 24 | 25 | 26 | 27 | 28 | QLayout::SetMinimumSize 29 | 30 | 31 | 32 | 33 | 34 | 10 35 | 75 36 | true 37 | 38 | 39 | 40 | Devices 41 | 42 | 43 | Qt::AlignCenter 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 163 56 | 25 57 | 135 58 | 46 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 10 67 | 75 68 | true 69 | 70 | 71 | 72 | Hostname or IP 73 | 74 | 75 | Qt::AlignCenter 76 | 77 | 78 | 79 | 80 | 81 | 82 | http://192.168.1.15 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 83 92 | 80 93 | 75 94 | 23 95 | 96 | 97 | 98 | Connect 99 | 100 | 101 | 102 | 103 | 104 | 20 105 | 50 106 | 30 107 | 23 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | images/refresh-arrow.pngimages/refresh-arrow.png 116 | 117 | 118 | 119 | 120 | 121 | 20 122 | 140 123 | 111 124 | 16 125 | 126 | 127 | 128 | 129 | 10 130 | 75 131 | true 132 | 133 | 134 | 135 | Active Device 136 | 137 | 138 | 139 | 140 | 141 | 20 142 | 160 143 | 161 144 | 16 145 | 146 | 147 | 148 | No Active Device 149 | 150 | 151 | 152 | 153 | 154 | 155 | 0 156 | 0 157 | 496 158 | 21 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/httpServer/core/httpresponse.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPRESPONSE_H 7 | #define HTTPRESPONSE_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include "httpglobal.h" 13 | #include "httpcookie.h" 14 | 15 | /** 16 | This object represents a HTTP response, used to return something to the web client. 17 |

18 |

 19 |     response.setStatus(200,"OK"); // optional, because this is the default
 20 |     response.writeBody("Hello");
 21 |     response.writeBody("World!",true);
 22 |   
23 |

24 | Example how to return an error: 25 |

 26 |     response.setStatus(500,"server error");
 27 |     response.write("The request cannot be processed because the servers is broken",true);
 28 |   
29 |

30 | In case of large responses (e.g. file downloads), a Content-Length header should be set 31 | before calling write(). Web Browsers use that information to display a progress bar. 32 | */ 33 | 34 | class DECLSPEC HttpResponse { 35 | Q_DISABLE_COPY(HttpResponse) 36 | public: 37 | 38 | /** 39 | Constructor. 40 | @param socket used to write the response 41 | */ 42 | HttpResponse(QTcpSocket* socket); 43 | 44 | /** 45 | Set a HTTP response header. 46 | You must call this method before the first write(). 47 | @param name name of the header 48 | @param value value of the header 49 | */ 50 | void setHeader(QByteArray name, QByteArray value); 51 | 52 | /** 53 | Set a HTTP response header. 54 | You must call this method before the first write(). 55 | @param name name of the header 56 | @param value value of the header 57 | */ 58 | void setHeader(QByteArray name, int value); 59 | 60 | /** Get the map of HTTP response headers */ 61 | QMap& getHeaders(); 62 | 63 | /** Get the map of cookies */ 64 | QMap& getCookies(); 65 | 66 | /** 67 | Set status code and description. The default is 200,OK. 68 | You must call this method before the first write(). 69 | */ 70 | void setStatus(int statusCode, QByteArray description=QByteArray()); 71 | 72 | /** Return the status code. */ 73 | int getStatusCode() const; 74 | 75 | /** 76 | Write body data to the socket. 77 |

78 | The HTTP status line, headers and cookies are sent automatically before the body. 79 |

80 | If the response contains only a single chunk (indicated by lastPart=true), 81 | then a Content-Length header is automatically set. 82 |

83 | Chunked mode is automatically selected if there is no Content-Length header 84 | and also no Connection:close header. 85 | @param data Data bytes of the body 86 | @param lastPart Indicates that this is the last chunk of data and flushes the output buffer. 87 | */ 88 | void write(QByteArray data, bool lastPart=false); 89 | 90 | /** 91 | Indicates whether the body has been sent completely (write() has been called with lastPart=true). 92 | */ 93 | bool hasSentLastPart() const; 94 | 95 | /** 96 | Set a cookie. 97 | You must call this method before the first write(). 98 | */ 99 | void setCookie(const HttpCookie& cookie); 100 | 101 | /** 102 | Send a redirect response to the browser. 103 | Cannot be combined with write(). 104 | @param url Destination URL 105 | */ 106 | void redirect(const QByteArray& url); 107 | 108 | /** 109 | * Flush the output buffer (of the underlying socket). 110 | * You normally don't need to call this method because flush is 111 | * automatically called after HttpRequestHandler::service() returns. 112 | */ 113 | void flush(); 114 | 115 | /** 116 | * May be used to check whether the connection to the web client has been lost. 117 | * This might be useful to cancel the generation of large or slow responses. 118 | */ 119 | bool isConnected() const; 120 | 121 | private: 122 | 123 | /** Request headers */ 124 | QMap headers; 125 | 126 | /** Socket for writing output */ 127 | QTcpSocket* socket; 128 | 129 | /** HTTP status code*/ 130 | int statusCode; 131 | 132 | /** HTTP status code description */ 133 | QByteArray statusText; 134 | 135 | /** Indicator whether headers have been sent */ 136 | bool sentHeaders; 137 | 138 | /** Indicator whether the body has been sent completely */ 139 | bool sentLastPart; 140 | 141 | /** Whether the response is sent in chunked mode */ 142 | bool chunkedMode; 143 | 144 | /** Cookies */ 145 | QMap cookies; 146 | 147 | /** Write raw data to the socket. This method blocks until all bytes have been passed to the TCP buffer */ 148 | bool writeToSocket(QByteArray data); 149 | 150 | /** 151 | Write the response HTTP status and headers to the socket. 152 | Calling this method is optional, because writeBody() calls 153 | it automatically when required. 154 | */ 155 | void writeHeaders(); 156 | 157 | }; 158 | 159 | #endif // HTTPRESPONSE_H 160 | -------------------------------------------------------------------------------- /src/httpServer/core/httpresponse.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "httpresponse.h" 7 | 8 | HttpResponse::HttpResponse(QTcpSocket* socket) 9 | { 10 | this->socket=socket; 11 | statusCode=200; 12 | statusText="OK"; 13 | sentHeaders=false; 14 | sentLastPart=false; 15 | chunkedMode=false; 16 | } 17 | 18 | void HttpResponse::setHeader(QByteArray name, QByteArray value) 19 | { 20 | Q_ASSERT(sentHeaders==false); 21 | headers.insert(name,value); 22 | } 23 | 24 | void HttpResponse::setHeader(QByteArray name, int value) 25 | { 26 | Q_ASSERT(sentHeaders==false); 27 | headers.insert(name,QByteArray::number(value)); 28 | } 29 | 30 | QMap& HttpResponse::getHeaders() 31 | { 32 | return headers; 33 | } 34 | 35 | void HttpResponse::setStatus(int statusCode, QByteArray description) 36 | { 37 | this->statusCode=statusCode; 38 | statusText=description; 39 | } 40 | 41 | int HttpResponse::getStatusCode() const 42 | { 43 | return this->statusCode; 44 | } 45 | 46 | void HttpResponse::writeHeaders() 47 | { 48 | Q_ASSERT(sentHeaders==false); 49 | QByteArray buffer; 50 | buffer.append("HTTP/1.1 "); 51 | buffer.append(QByteArray::number(statusCode)); 52 | buffer.append(' '); 53 | buffer.append(statusText); 54 | buffer.append("\r\n"); 55 | foreach(QByteArray name, headers.keys()) 56 | { 57 | buffer.append(name); 58 | buffer.append(": "); 59 | buffer.append(headers.value(name)); 60 | buffer.append("\r\n"); 61 | } 62 | foreach(HttpCookie cookie,cookies.values()) 63 | { 64 | buffer.append("Set-Cookie: "); 65 | buffer.append(cookie.toByteArray()); 66 | buffer.append("\r\n"); 67 | } 68 | buffer.append("\r\n"); 69 | writeToSocket(buffer); 70 | sentHeaders=true; 71 | } 72 | 73 | bool HttpResponse::writeToSocket(QByteArray data) 74 | { 75 | int remaining=data.size(); 76 | char* ptr=data.data(); 77 | while (socket->isOpen() && remaining>0) 78 | { 79 | // If the output buffer has become large, then wait until it has been sent. 80 | if (socket->bytesToWrite()>16384) 81 | { 82 | socket->waitForBytesWritten(-1); 83 | } 84 | 85 | int written=socket->write(ptr,remaining); 86 | if (written==-1) 87 | { 88 | return false; 89 | } 90 | ptr+=written; 91 | remaining-=written; 92 | } 93 | return true; 94 | } 95 | 96 | void HttpResponse::write(QByteArray data, bool lastPart) 97 | { 98 | Q_ASSERT(sentLastPart==false); 99 | 100 | // Send HTTP headers, if not already done (that happens only on the first call to write()) 101 | if (sentHeaders==false) 102 | { 103 | // If the whole response is generated with a single call to write(), then we know the total 104 | // size of the response and therefore can set the Content-Length header automatically. 105 | if (lastPart) 106 | { 107 | // Automatically set the Content-Length header 108 | headers.insert("Content-Length",QByteArray::number(data.size())); 109 | } 110 | 111 | // else if we will not close the connection at the end, them we must use the chunked mode. 112 | else 113 | { 114 | QByteArray connectionValue=headers.value("Connection",headers.value("connection")); 115 | bool connectionClose=QString::compare(connectionValue,"close",Qt::CaseInsensitive)==0; 116 | if (!connectionClose) 117 | { 118 | headers.insert("Transfer-Encoding","chunked"); 119 | chunkedMode=true; 120 | } 121 | } 122 | 123 | writeHeaders(); 124 | } 125 | 126 | // Send data 127 | if (data.size()>0) 128 | { 129 | if (chunkedMode) 130 | { 131 | if (data.size()>0) 132 | { 133 | QByteArray size=QByteArray::number(data.size(),16); 134 | writeToSocket(size); 135 | writeToSocket("\r\n"); 136 | writeToSocket(data); 137 | writeToSocket("\r\n"); 138 | } 139 | } 140 | else 141 | { 142 | writeToSocket(data); 143 | } 144 | } 145 | 146 | // Only for the last chunk, send the terminating marker and flush the buffer. 147 | if (lastPart) 148 | { 149 | if (chunkedMode) 150 | { 151 | writeToSocket("0\r\n\r\n"); 152 | } 153 | socket->flush(); 154 | sentLastPart=true; 155 | } 156 | } 157 | 158 | 159 | bool HttpResponse::hasSentLastPart() const 160 | { 161 | return sentLastPart; 162 | } 163 | 164 | 165 | void HttpResponse::setCookie(const HttpCookie& cookie) 166 | { 167 | Q_ASSERT(sentHeaders==false); 168 | if (!cookie.getName().isEmpty()) 169 | { 170 | cookies.insert(cookie.getName(),cookie); 171 | } 172 | } 173 | 174 | 175 | QMap& HttpResponse::getCookies() 176 | { 177 | return cookies; 178 | } 179 | 180 | 181 | void HttpResponse::redirect(const QByteArray& url) 182 | { 183 | setStatus(303,"See Other"); 184 | setHeader("Location",url); 185 | write("Redirect",true); 186 | } 187 | 188 | 189 | void HttpResponse::flush() 190 | { 191 | socket->flush(); 192 | } 193 | 194 | 195 | bool HttpResponse::isConnected() const 196 | { 197 | return socket->isOpen(); 198 | } 199 | -------------------------------------------------------------------------------- /src/httpServer/core/httpconnectionhandlerpool.cpp: -------------------------------------------------------------------------------- 1 | #ifndef QT_NO_OPENSSL 2 | #include 3 | #include 4 | #include 5 | #include 6 | #endif 7 | #include 8 | #include "httpconnectionhandlerpool.h" 9 | 10 | HttpConnectionHandlerPool::HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler) 11 | : QObject() 12 | { 13 | Q_ASSERT(settings!=0); 14 | this->settings=settings; 15 | this->requestHandler=requestHandler; 16 | this->sslConfiguration=NULL; 17 | loadSslConfig(); 18 | cleanupTimer.start(settings->value("cleanupInterval",1000).toInt()); 19 | connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup())); 20 | } 21 | 22 | 23 | HttpConnectionHandlerPool::~HttpConnectionHandlerPool() 24 | { 25 | // delete all connection handlers and wait until their threads are closed 26 | foreach(HttpConnectionHandler* handler, pool) 27 | { 28 | delete handler; 29 | } 30 | delete sslConfiguration; 31 | qDebug("HttpConnectionHandlerPool (%p): destroyed", this); 32 | } 33 | 34 | 35 | HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler() 36 | { 37 | HttpConnectionHandler* freeHandler=0; 38 | mutex.lock(); 39 | // find a free handler in pool 40 | foreach(HttpConnectionHandler* handler, pool) 41 | { 42 | if (!handler->isBusy()) 43 | { 44 | freeHandler=handler; 45 | freeHandler->setBusy(); 46 | break; 47 | } 48 | } 49 | // create a new handler, if necessary 50 | if (!freeHandler) 51 | { 52 | int maxConnectionHandlers=settings->value("maxThreads",100).toInt(); 53 | if (pool.count()setBusy(); 57 | pool.append(freeHandler); 58 | } 59 | } 60 | mutex.unlock(); 61 | return freeHandler; 62 | } 63 | 64 | 65 | void HttpConnectionHandlerPool::cleanup() 66 | { 67 | int maxIdleHandlers=settings->value("minThreads",1).toInt(); 68 | int idleCounter=0; 69 | mutex.lock(); 70 | foreach(HttpConnectionHandler* handler, pool) 71 | { 72 | if (!handler->isBusy()) 73 | { 74 | if (++idleCounter > maxIdleHandlers) 75 | { 76 | delete handler; 77 | pool.removeOne(handler); 78 | qDebug("HttpConnectionHandlerPool: Removed connection handler (%p), pool size is now %i",handler,pool.size()); 79 | break; // remove only one handler in each interval 80 | } 81 | } 82 | } 83 | mutex.unlock(); 84 | } 85 | 86 | 87 | void HttpConnectionHandlerPool::loadSslConfig() 88 | { 89 | // If certificate and key files are configured, then load them 90 | QString sslKeyFileName=settings->value("sslKeyFile","").toString(); 91 | QString sslCertFileName=settings->value("sslCertFile","").toString(); 92 | if (!sslKeyFileName.isEmpty() && !sslCertFileName.isEmpty()) 93 | { 94 | #ifdef QT_NO_OPENSSL 95 | qWarning("HttpConnectionHandlerPool: SSL is not supported"); 96 | #else 97 | // Convert relative fileNames to absolute, based on the directory of the config file. 98 | QFileInfo configFile(settings->fileName()); 99 | #ifdef Q_OS_WIN32 100 | if (QDir::isRelativePath(sslKeyFileName) && settings->format()!=QSettings::NativeFormat) 101 | #else 102 | if (QDir::isRelativePath(sslKeyFileName)) 103 | #endif 104 | { 105 | sslKeyFileName=QFileInfo(configFile.absolutePath(),sslKeyFileName).absoluteFilePath(); 106 | } 107 | #ifdef Q_OS_WIN32 108 | if (QDir::isRelativePath(sslCertFileName) && settings->format()!=QSettings::NativeFormat) 109 | #else 110 | if (QDir::isRelativePath(sslCertFileName)) 111 | #endif 112 | { 113 | sslCertFileName=QFileInfo(configFile.absolutePath(),sslCertFileName).absoluteFilePath(); 114 | } 115 | 116 | // Load the SSL certificate 117 | QFile certFile(sslCertFileName); 118 | if (!certFile.open(QIODevice::ReadOnly)) 119 | { 120 | qCritical("HttpConnectionHandlerPool: cannot open sslCertFile %s", qPrintable(sslCertFileName)); 121 | return; 122 | } 123 | QSslCertificate certificate(&certFile, QSsl::Pem); 124 | certFile.close(); 125 | 126 | // Load the key file 127 | QFile keyFile(sslKeyFileName); 128 | if (!keyFile.open(QIODevice::ReadOnly)) 129 | { 130 | qCritical("HttpConnectionHandlerPool: cannot open sslKeyFile %s", qPrintable(sslKeyFileName)); 131 | return; 132 | } 133 | QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem); 134 | keyFile.close(); 135 | 136 | // Create the SSL configuration 137 | sslConfiguration=new QSslConfiguration(); 138 | sslConfiguration->setLocalCertificate(certificate); 139 | sslConfiguration->setPrivateKey(sslKey); 140 | sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyNone); 141 | sslConfiguration->setProtocol(QSsl::TlsV1SslV3); 142 | 143 | qDebug("HttpConnectionHandlerPool: SSL settings loaded"); 144 | #endif 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/mainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainWindow.h" 2 | #include "ui_mainWindow.h" 3 | 4 | #ifndef QT_NO_SYSTEMTRAYICON 5 | 6 | //QT core includes 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "wflDevice/wflDevice.h" 14 | 15 | MainWindow::MainWindow(Agent* agent, QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) 16 | { 17 | qDebug() << "MainWindow::MainWindow()" << "thread: " << QThread::currentThread(); 18 | 19 | setWindowTitle(tr("Digilent Agent")); 20 | 21 | this->agent = agent; 22 | 23 | //Get UI element refs 24 | ui->setupUi(this); 25 | //hostnameIp = ui->hostnameIp; 26 | 27 | createWindowActions(); 28 | createTrayIcon(); 29 | 30 | //Set Tray Icon 31 | QIcon icon = QIcon(":/images/icon.png"); 32 | trayIcon->setIcon(icon); 33 | setWindowIcon(icon); 34 | 35 | //Set dock icon if on mac 36 | #if defined(TARGET_OS_MAC) 37 | QApplication::setWindowIcon(QIcon(":/images/icon.png")); 38 | #endif 39 | 40 | 41 | //Show system tray icon 42 | trayIcon->show(); 43 | 44 | 45 | } 46 | 47 | MainWindow::~MainWindow() 48 | { 49 | delete ui; 50 | } 51 | 52 | void MainWindow::createWindowActions() 53 | { 54 | #ifdef AGENT_BUILD_NOTE 55 | versionAction = new QAction(QString("Agent Version: ") + QString(this->agent->getVersion()) + " - " + this->agent->getBuildNote(), this); 56 | #else 57 | versionAction = new QAction(QString("Agent Version: ") + QString(this->agent->getVersion()), this); 58 | #endif 59 | versionAction->setEnabled(false); 60 | 61 | #ifdef _WIN32 62 | checkForUpdatesAction = new QAction(QString("Check For Updates"), this); 63 | checkForUpdatesAction->setEnabled(true); 64 | connect(checkForUpdatesAction, &QAction::triggered, this, &MainWindow::runUpdater); 65 | #endif 66 | 67 | //Active Device 68 | //activeDeviceNameAction = new QAction(QString("Active Device: -"), this); 69 | //activeDeviceNameAction->setEnabled(false); 70 | connect(this->agent, SIGNAL(activeDeviceChanged(QString)), this, SLOT(onActiveDeviceNameChange(QString))); 71 | 72 | quitAction = new QAction(tr("&Exit"), this); 73 | connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit); 74 | 75 | launchWflAction = new QAction(tr("Launch WaveForms Live"), this); 76 | connect(launchWflAction, &QAction::triggered, this, &MainWindow::launchWfl); 77 | 78 | } 79 | 80 | void MainWindow::createTrayIcon() 81 | { 82 | trayIconMenu = new QMenu(this); 83 | trayIconMenu->addAction(launchWflAction); 84 | 85 | //Active Device 86 | this->activeDeviceSubMenu = trayIconMenu->addMenu("Active Device: -"); 87 | this->activeDeviceSubMenuRelease = activeDeviceSubMenu->addAction("Release"); 88 | connect(activeDeviceSubMenuRelease, SIGNAL(triggered()), this, SLOT(releaseActiveDevice())); 89 | activeDeviceSubMenu->setEnabled(false); 90 | trayIconMenu->addSeparator(); 91 | 92 | trayIconMenu->addAction(versionAction); 93 | 94 | #ifdef _WIN32 95 | //Add check for updates button on Windows only since it depends on the maintainence tool 96 | trayIconMenu->addAction(checkForUpdatesAction); 97 | #endif 98 | 99 | trayIconMenu->addAction(quitAction); 100 | trayIcon = new QSystemTrayIcon(this); 101 | trayIcon->setContextMenu(trayIconMenu); 102 | 103 | } 104 | 105 | void MainWindow::launchWfl(){ 106 | agent->launchWfl(); 107 | } 108 | 109 | void MainWindow::onActiveDeviceNameChange(QString activeDeviceName) { 110 | qDebug("onActiveDeviceNameChange()"); 111 | if(activeDeviceName == "") 112 | { 113 | activeDeviceSubMenu->setTitle("Active Device: -"); 114 | activeDeviceSubMenu->setEnabled(false); 115 | } 116 | else 117 | { 118 | activeDeviceSubMenu->setTitle("Active Device: " + activeDeviceName); 119 | activeDeviceSubMenu->setEnabled(true); 120 | } 121 | } 122 | 123 | void MainWindow::releaseActiveDevice() { 124 | if(this->agent->activeDevice != 0) 125 | { 126 | emit releaseActiveDeviceSignal(); 127 | } 128 | //this->agent->releaseActiveDevice(); 129 | //Signal to relase agent 130 | } 131 | 132 | bool MainWindow::checkForUpdates(){ 133 | //QString maintenanceToolPath = qApp->applicationDirPath() + "/maintenancetool"; 134 | QString maintenanceToolPath = "C:/Program Files (x86)/Digilent/Agent/maintenancetool.exe"; 135 | 136 | this->runUpdater(); 137 | 138 | QProcess checkForUpdates; 139 | //checkForUpdates.start("maintenancetool --checkupdates"); 140 | //checkForUpdates.start("C:/Users/samkr/Documents/My Received Files/test.bat"); 141 | 142 | 143 | 144 | //Wait for update check to complete 145 | checkForUpdates.waitForFinished(); 146 | 147 | if(checkForUpdates.error() != QProcess::UnknownError) 148 | { 149 | qDebug() << "Update check failed" << checkForUpdates.error(); 150 | return false; 151 | } 152 | 153 | QByteArray updateData = checkForUpdates.readAllStandardOutput(); 154 | 155 | if(updateData.isEmpty()) 156 | { 157 | qDebug() << "No updates"; 158 | return false; 159 | } 160 | 161 | //Update is available 162 | return true; 163 | } 164 | 165 | void MainWindow::runUpdater() { 166 | 167 | QStringList args("--updater"); 168 | QProcess::startDetached(QCoreApplication::applicationDirPath() + "/maintenancetool.exe", args); 169 | 170 | // Close the agent so update can run 171 | qApp->closeAllWindows(); 172 | } 173 | 174 | #endif //QT_NO_SYSTEMTRAYICON 175 | 176 | -------------------------------------------------------------------------------- /src/wflDevice/wflSerialDevice.cpp: -------------------------------------------------------------------------------- 1 | #include "wflSerialDevice.h" 2 | #include 3 | 4 | WflSerialDevice::WflSerialDevice(QString address, QObject* parent) : WflDevice(parent) 5 | { 6 | qDebug() << "WflSerialDevice::WflSerialDevice()" << "thread: " << QThread::currentThread(); 7 | this->name = ""; 8 | this->deviceType = "UART"; 9 | 10 | //Initialize serial object, open the port and upgrade to the target baud rate (Work around Mac Issue) 11 | this->serial = new Serial(this); 12 | if(this->serial->open(address, 9600)) { 13 | this->name = address; 14 | if(!this->serial->setBaudRate(1250000)) { 15 | qDebug() << "Failed to updgrade serial baud rate when creating wflDevice for " << address; 16 | } 17 | } 18 | } 19 | 20 | WflSerialDevice::~WflSerialDevice(){ 21 | qDebug() << "WflSerialDevice::~WflSerialDevice()" << "thread: " << QThread::currentThread(); 22 | this->serial->close(); 23 | delete this->serial; 24 | this->name = ""; 25 | } 26 | 27 | //Send a command to the device and return the response. Upon completion this function emits the execCommandComplete signal with the response from the device. 28 | void WflSerialDevice::execCommand(QByteArray cmd) { 29 | qDebug() << "WflSerialDevice::execCommand()" << "thread: " << QThread::currentThread(); 30 | QByteArray resp = this->writeRead(cmd); 31 | emit execCommandComplete(resp); 32 | } 33 | 34 | //Send a signal to the serial object to start the transfer. This function blocks until the serial object response (via signal) and then this funciton returns the response from the serial device. 35 | QByteArray WflSerialDevice::writeRead(QByteArray cmd) { 36 | qDebug() << "WflSerialDevice::writeRead2()" << "thread: " << QThread::currentThread(); 37 | 38 | QEventLoop loop; 39 | 40 | connect(this, SIGNAL(writeReadComplete()), &loop, SLOT(quit())); //Connect signal to exit the blocking loop once this object gets a response 41 | connect(this, SIGNAL(startFastWriteRead(QByteArray,int,int)), this->serial, SLOT(fastWriteRead(QByteArray,int,int))); //Connect signal that this object emits to start the fastWriteRead 42 | connect(this->serial, SIGNAL(fastWriteReadResponse(QByteArray)), this, SLOT(onFastWriteReadResponse(QByteArray))); //Connect the signal that the fastWriteRead emits with the reponse 43 | 44 | //Start the fastWriteRead in thread that owns the serial object 45 | emit startFastWriteRead(cmd, 2000, 100); 46 | 47 | //Loop until writeRead is complete and writeReadComplete() signal is emited 48 | loop.exec(); 49 | 50 | //Disconnect signals before returning 51 | disconnect(this, SIGNAL(writeReadComplete()), &loop, SLOT(quit())); 52 | disconnect(this, SIGNAL(startFastWriteRead(QByteArray,int,int)), this->serial, SLOT(fastWriteRead(QByteArray,int,int))); 53 | disconnect(this->serial, SIGNAL(fastWriteReadResponse(QByteArray)), this, SLOT(onFastWriteReadResponse(QByteArray))); 54 | 55 | return this->data; 56 | } 57 | 58 | //Close and re-open the serial port; 59 | bool WflSerialDevice::softReset() { 60 | qDebug() << "WflSerialDevice::softReset()" << "thread: " << QThread::currentThread(); 61 | 62 | QEventLoop loop; 63 | 64 | //Connect slots and signals for cross thread call 65 | connect(this, SIGNAL(softResetComplete()), &loop, SLOT(quit())); 66 | connect(this, SIGNAL(startSoftReset()), this->serial, SLOT(softReset())); 67 | connect(this->serial, SIGNAL(softResetResponse(bool)), this, SLOT(onSoftResetResponse(bool))); 68 | 69 | //Start the fastWriteRead in thread that owns the serial object 70 | emit startSoftReset(); 71 | 72 | //Loop until writeRead is complete and writeReadComplete() signal is emited 73 | loop.exec(); 74 | 75 | //Disconnect signals before returning 76 | disconnect(this, SIGNAL(softResetComplete()), &loop, SLOT(quit())); 77 | disconnect(this, SIGNAL(startSoftReset()), this->serial, SLOT(softReset())); 78 | disconnect(this->serial, SIGNAL(softResetResponse(bool)), this, SLOT(onSoftResetResponse(bool))); 79 | 80 | return this->softResetSuccess; 81 | } 82 | 83 | //Return true if the device serial port is open, false otherwise. 84 | bool WflSerialDevice::isOpen() { 85 | return this->serial->isOpen(); 86 | } 87 | 88 | //Release this device and free the COM port by destroying this object. 89 | void WflSerialDevice::release(){ 90 | qDebug() << "WflSerialDevice::release()" << "thread: " << QThread::currentThread(); 91 | 92 | //Close the serial port so it is immediatly available to other processes, then schedule this object and it's children for deletion 93 | this->serial->close(); 94 | //this->deleteLater(); 95 | emit releaseComplete(); 96 | 97 | qDebug() << "WflSerialDevice::release() - Done" << "thread: " << QThread::currentThread(); 98 | } 99 | 100 | //Slot triggered when the Serial::fastWriteReadResponse signal is emitted 101 | void WflSerialDevice::onFastWriteReadResponse(QByteArray response) { 102 | qDebug() << "WflSerialDevice::onFastWriteReadResponse() Complete - " << response; 103 | 104 | //Save response data and emit signal to exit blocking loop 105 | this->data = response; 106 | emit writeReadComplete(); 107 | } 108 | 109 | 110 | //Slot triggered when the Serial::softResetResponse signal is emitted 111 | void WflSerialDevice::onSoftResetResponse(bool success) { 112 | qDebug() << "WflSerialDevice::onSoftResetResponse() - Success:" << success; 113 | 114 | //Save response and emit signal to exit blocking loop 115 | this->softResetSuccess = success; 116 | emit softResetComplete(); 117 | } 118 | -------------------------------------------------------------------------------- /src/httpServer/core/httpcookie.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "httpcookie.h" 7 | 8 | HttpCookie::HttpCookie() 9 | { 10 | version=1; 11 | maxAge=0; 12 | secure=false; 13 | } 14 | 15 | HttpCookie::HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path, const QByteArray comment, const QByteArray domain, const bool secure, const bool httpOnly) 16 | { 17 | this->name=name; 18 | this->value=value; 19 | this->maxAge=maxAge; 20 | this->path=path; 21 | this->comment=comment; 22 | this->domain=domain; 23 | this->secure=secure; 24 | this->httpOnly=httpOnly; 25 | this->version=1; 26 | } 27 | 28 | HttpCookie::HttpCookie(const QByteArray source) 29 | { 30 | version=1; 31 | maxAge=0; 32 | secure=false; 33 | QList list=splitCSV(source); 34 | foreach(QByteArray part, list) 35 | { 36 | 37 | // Split the part into name and value 38 | QByteArray name; 39 | QByteArray value; 40 | int posi=part.indexOf('='); 41 | if (posi) 42 | { 43 | name=part.left(posi).trimmed(); 44 | value=part.mid(posi+1).trimmed(); 45 | } 46 | else 47 | { 48 | name=part.trimmed(); 49 | value=""; 50 | } 51 | 52 | // Set fields 53 | if (name=="Comment") 54 | { 55 | comment=value; 56 | } 57 | else if (name=="Domain") 58 | { 59 | domain=value; 60 | } 61 | else if (name=="Max-Age") 62 | { 63 | maxAge=value.toInt(); 64 | } 65 | else if (name=="Path") 66 | { 67 | path=value; 68 | } 69 | else if (name=="Secure") 70 | { 71 | secure=true; 72 | } 73 | else if (name=="HttpOnly") 74 | { 75 | httpOnly=true; 76 | } 77 | else if (name=="Version") 78 | { 79 | version=value.toInt(); 80 | } 81 | else { 82 | if (this->name.isEmpty()) 83 | { 84 | this->name=name; 85 | this->value=value; 86 | } 87 | else 88 | { 89 | qWarning("HttpCookie: Ignoring unknown %s=%s",name.data(),value.data()); 90 | } 91 | } 92 | } 93 | } 94 | 95 | QByteArray HttpCookie::toByteArray() const 96 | { 97 | QByteArray buffer(name); 98 | buffer.append('='); 99 | buffer.append(value); 100 | if (!comment.isEmpty()) 101 | { 102 | buffer.append("; Comment="); 103 | buffer.append(comment); 104 | } 105 | if (!domain.isEmpty()) 106 | { 107 | buffer.append("; Domain="); 108 | buffer.append(domain); 109 | } 110 | if (maxAge!=0) 111 | { 112 | buffer.append("; Max-Age="); 113 | buffer.append(QByteArray::number(maxAge)); 114 | } 115 | if (!path.isEmpty()) 116 | { 117 | buffer.append("; Path="); 118 | buffer.append(path); 119 | } 120 | if (secure) { 121 | buffer.append("; Secure"); 122 | } 123 | if (httpOnly) { 124 | buffer.append("; HttpOnly"); 125 | } 126 | buffer.append("; Version="); 127 | buffer.append(QByteArray::number(version)); 128 | return buffer; 129 | } 130 | 131 | void HttpCookie::setName(const QByteArray name) 132 | { 133 | this->name=name; 134 | } 135 | 136 | void HttpCookie::setValue(const QByteArray value) 137 | { 138 | this->value=value; 139 | } 140 | 141 | void HttpCookie::setComment(const QByteArray comment) 142 | { 143 | this->comment=comment; 144 | } 145 | 146 | void HttpCookie::setDomain(const QByteArray domain) 147 | { 148 | this->domain=domain; 149 | } 150 | 151 | void HttpCookie::setMaxAge(const int maxAge) 152 | { 153 | this->maxAge=maxAge; 154 | } 155 | 156 | void HttpCookie::setPath(const QByteArray path) 157 | { 158 | this->path=path; 159 | } 160 | 161 | void HttpCookie::setSecure(const bool secure) 162 | { 163 | this->secure=secure; 164 | } 165 | 166 | void HttpCookie::setHttpOnly(const bool httpOnly) 167 | { 168 | this->httpOnly=httpOnly; 169 | } 170 | 171 | QByteArray HttpCookie::getName() const 172 | { 173 | return name; 174 | } 175 | 176 | QByteArray HttpCookie::getValue() const 177 | { 178 | return value; 179 | } 180 | 181 | QByteArray HttpCookie::getComment() const 182 | { 183 | return comment; 184 | } 185 | 186 | QByteArray HttpCookie::getDomain() const 187 | { 188 | return domain; 189 | } 190 | 191 | int HttpCookie::getMaxAge() const 192 | { 193 | return maxAge; 194 | } 195 | 196 | QByteArray HttpCookie::getPath() const 197 | { 198 | return path; 199 | } 200 | 201 | bool HttpCookie::getSecure() const 202 | { 203 | return secure; 204 | } 205 | 206 | bool HttpCookie::getHttpOnly() const 207 | { 208 | return httpOnly; 209 | } 210 | 211 | int HttpCookie::getVersion() const 212 | { 213 | return version; 214 | } 215 | 216 | QList HttpCookie::splitCSV(const QByteArray source) 217 | { 218 | bool inString=false; 219 | QList list; 220 | QByteArray buffer; 221 | for (int i=0; i [OPTIONS] 134 | This program adds a software license agreement to a DMG file. 135 | It requires Xcode and either a plain ascii text 136 | or a with the RTF contents. 137 | 138 | See --help for more details.""") 139 | parser.add_option( 140 | '--rez', 141 | '-r', 142 | action='store', 143 | default='/Applications/Xcode.app/Contents/Developer/Tools/Rez', 144 | help='The path to the Rez tool. Defaults to %default' 145 | ) 146 | parser.add_option( 147 | '--compression', 148 | '-c', 149 | action='store', 150 | choices=['bz2', 'gz'], 151 | default=None, 152 | help='Optionally compress dmg using specified compression type. ' 153 | 'Choices are bz2 and gz.' 154 | ) 155 | options, args = parser.parse_args() 156 | cond = len(args) != 2 157 | if not os.path.exists(options.rez): 158 | print 'Failed to find Rez at "%s"!\n' % options.rez 159 | cond = True 160 | if cond: 161 | parser.print_usage() 162 | sys.exit(1) 163 | main(options, args) 164 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | //QT core includes 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //Disable SSL on OSx 10 | #ifdef __APPLE__ 11 | #include "TargetConditionals.h" 12 | #if TARGET_OS_MAC 13 | #define QT_NO_SSL 14 | #endif 15 | #endif 16 | 17 | //HTTP core includes 18 | #include "httplistener.h" 19 | 20 | //WFL Agent HTTP includes 21 | #include "httpServer/httpRouter.h" 22 | #include "httpServer/debugController.h" 23 | 24 | //WFL Agent includes 25 | #include "core/agent.h" 26 | #include "core/utils/runGuard.h" 27 | #include "wflDevice/wflDevice.h" 28 | 29 | #ifndef QT_NO_SYSTEMTRAYICON 30 | #include "mainWindow.h" 31 | 32 | //Forward declarations 33 | QString searchConfigFile(); 34 | QString createNewConfigFile(); 35 | 36 | 37 | #ifdef Q_OS_LINUX 38 | QString iniPath = QString(QDir::homePath() + "/.config/digilent/digilent-agent.ini"); 39 | QString wwwRoot = "/usr/share/digilent/digilent-agent/www"; 40 | #elif defined(_WIN32) 41 | QString iniPath = QString(QDir::homePath() + "/AppData/Local/Digilent/Digilent Agent/digilent-agent.ini"); 42 | QString wwwRoot = QString(QDir::homePath() + "/AppData/Local/Digilent/Digilent Agent/www/"); 43 | #elif TARGET_OS_MAC 44 | QString iniPath = QString(QDir::homePath() + "/.config/digilent/digilent-agent.ini"); 45 | QString wwwRoot = "/Users/Shared/digilent/digilent-agent/www"; 46 | #endif 47 | 48 | int main(int argc, char *argv[]) 49 | { 50 | //Prevent multiple instances of this agent 51 | RunGuard guard( "Digilent_Agent_1.x.x" ); 52 | if ( !guard.tryToRun() ) { 53 | return 0; 54 | } 55 | 56 | QApplication app(argc, argv); 57 | 58 | //Instantiate the agent and mainWindow 59 | Agent* agent = new Agent(&app); 60 | 61 | MainWindow mainWindow(agent); 62 | 63 | 64 | QObject::connect(&mainWindow, SIGNAL(releaseActiveDeviceSignal()), agent, SLOT(releaseActiveDevice())); 65 | //, SIGNAL(finished()), &loop, SLOT(quit())); 66 | 67 | 68 | // Load the http configuration file 69 | QString configFileName = searchConfigFile(); 70 | QSettings* listenerSettings; 71 | 72 | 73 | if(configFileName != "") { 74 | listenerSettings = new QSettings(configFileName, QSettings::IniFormat, &app); 75 | listenerSettings->sync(); 76 | } else { 77 | qDebug("Failed to load digilent-agent.ini"); 78 | return -1; 79 | } 80 | 81 | //Pass ini values to agent 82 | agent->waveFormsLiveBrowserPath = listenerSettings->value("waveforms-live/wwwRoot").toString(); 83 | 84 | // Static file controller 85 | QSettings* fileSettings=new QSettings(configFileName, QSettings::IniFormat, &app); 86 | fileSettings->beginGroup("files"); 87 | fileSettings->setValue("path", agent->waveFormsLiveBrowserPath); 88 | HttpRouter::staticFileController = new StaticFileController(fileSettings, &app); 89 | 90 | //Create and start the HTTP Server 91 | //new HttpListener(listenerSettings, new HttpRouter(&app, &mainWindow.activeDevice), &app); 92 | listenerSettings->beginGroup("listener"); 93 | new HttpListener(listenerSettings, new HttpRouter(agent, &app), &app); 94 | 95 | mainWindow.hide(); 96 | 97 | return app.exec(); 98 | } 99 | 100 | //Search for the digilent-agent config ini 101 | QString searchConfigFile() { 102 | QFile file; 103 | file.setFileName(iniPath); 104 | QString binDir = QCoreApplication::applicationDirPath(); 105 | QString appName = QCoreApplication::applicationName(); 106 | 107 | #ifdef Q_OS_LINUX_LINUX 108 | file.setFileName(QDir::homePath() + "/.config/digilent-agent.ini"); 109 | #elif defined(W_OS_WIN32) 110 | 111 | #endif 112 | if (!file.exists()) { 113 | file.setFileName(binDir+"/digilent-agent.ini"); 114 | if (!file.exists()) { 115 | file.setFileName(binDir+"/../digilent-agent.ini"); 116 | if (!file.exists()) { 117 | file.setFileName(binDir+"/../"+appName+"/digilent-agent.ini"); 118 | if (!file.exists()) { 119 | file.setFileName(binDir+"/../../"+appName+"/digilent-agent.ini"); 120 | if (!file.exists()) { 121 | file.setFileName(binDir+"/../../../"+appName+"/digilent-agent.ini"); 122 | if (!file.exists()) { 123 | file.setFileName(binDir+"/../../../../"+appName+"/digilent-agent.ini"); 124 | if (!file.exists()) { 125 | file.setFileName(binDir+"/../../../../../"+appName+"/digilent-agent.ini"); 126 | if (!file.exists()) { 127 | file.setFileName(QDir::rootPath()+"digilent-agent.ini"); 128 | if (!file.exists()) { 129 | file.setFileName(createNewConfigFile()); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | if (file.exists()) { 140 | QString configFileName = QDir(file.fileName()).canonicalPath(); 141 | qDebug("Using config file %s", qPrintable(configFileName)); 142 | return configFileName; 143 | } 144 | else { 145 | return QString(); 146 | } 147 | } 148 | 149 | QString createNewConfigFile(){ 150 | //Create default config data 151 | QSettings* listenerSettings = new QSettings(iniPath, QSettings::IniFormat); 152 | listenerSettings->beginGroup("listener"); 153 | listenerSettings->setValue("port", 42135); 154 | listenerSettings->setValue("minThreads", 4); 155 | listenerSettings->setValue("maxThreads", 100); 156 | listenerSettings->setValue("cleanupInterval", 60000); 157 | listenerSettings->setValue("readTimeout", 60000); 158 | listenerSettings->setValue("maxRequestSize", 16000000); 159 | listenerSettings->setValue("maxMultiPartSize", 16000000); 160 | listenerSettings->endGroup(); 161 | 162 | listenerSettings->beginGroup("files"); 163 | listenerSettings->setValue("encoding", "UTF-8"); 164 | listenerSettings->setValue("maxAge", 90000); 165 | listenerSettings->setValue("cacheTime", 60000); 166 | listenerSettings->setValue("cacheSize", 1000000); 167 | listenerSettings->setValue("maxCachedFileSize", 65536); 168 | listenerSettings->endGroup(); 169 | 170 | listenerSettings->beginGroup("waveforms-live"); 171 | listenerSettings->setValue("wwwRoot", wwwRoot); 172 | 173 | listenerSettings->sync(); 174 | 175 | return iniPath; 176 | } 177 | #else 178 | 179 | 180 | #include 181 | #include 182 | 183 | int main(int argc, char *argv[]) 184 | { 185 | QApplication app(argc, argv); 186 | QString text("QSystemTrayIcon is not supported on this platform"); 187 | 188 | QLabel *label = new QLabel(text); 189 | label->setWordWrap(true); 190 | 191 | label->show(); 192 | qDebug() << text; 193 | 194 | app.exec(); 195 | } 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /src/httpServer/core/staticfilecontroller.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #include "staticfilecontroller.h" 7 | #include 8 | #include 9 | #include 10 | 11 | StaticFileController::StaticFileController(QSettings* settings, QObject* parent) 12 | :HttpRequestHandler(parent) 13 | { 14 | maxAge=settings->value("maxAge","60000").toInt(); 15 | encoding=settings->value("encoding","UTF-8").toString(); 16 | docroot=settings->value("path",".").toString(); 17 | if(!(docroot.startsWith(":/") || docroot.startsWith("qrc://"))) 18 | { 19 | // Convert relative path to absolute, based on the directory of the config file. 20 | #ifdef Q_OS_WIN32 21 | if (QDir::isRelativePath(docroot) && settings->format()!=QSettings::NativeFormat) 22 | #else 23 | if (QDir::isRelativePath(docroot)) 24 | #endif 25 | { 26 | QFileInfo configFile(settings->fileName()); 27 | docroot=QFileInfo(configFile.absolutePath(),docroot).absoluteFilePath(); 28 | } 29 | } 30 | qDebug("StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge); 31 | maxCachedFileSize=settings->value("maxCachedFileSize","65536").toInt(); 32 | cache.setMaxCost(settings->value("cacheSize","1000000").toInt()); 33 | cacheTimeout=settings->value("cacheTime","60000").toInt(); 34 | qDebug("StaticFileController: cache timeout=%i, size=%i",cacheTimeout,cache.maxCost()); 35 | } 36 | 37 | 38 | void StaticFileController::service(HttpRequest& request, HttpResponse& response) 39 | { 40 | QByteArray path=request.getPath(); 41 | // Check if we have the file in cache 42 | qint64 now=QDateTime::currentMSecsSinceEpoch(); 43 | mutex.lock(); 44 | CacheEntry* entry=cache.object(path); 45 | if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) 46 | { 47 | QByteArray document=entry->document; //copy the cached document, because other threads may destroy the cached entry immediately after mutex unlock. 48 | QByteArray filename=entry->filename; 49 | mutex.unlock(); 50 | qDebug("StaticFileController: Cache hit for %s",path.data()); 51 | setContentType(filename,response); 52 | response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000)); 53 | response.write(document); 54 | } 55 | else 56 | { 57 | mutex.unlock(); 58 | // The file is not in cache. 59 | qDebug("StaticFileController: Cache miss for %s",path.data()); 60 | // Forbid access to files outside the docroot directory 61 | if (path.contains("/..")) 62 | { 63 | qWarning("StaticFileController: detected forbidden characters in path %s",path.data()); 64 | response.setStatus(403,"forbidden"); 65 | response.write("403 forbidden",true); 66 | return; 67 | } 68 | // If the filename is a directory, append index.html. 69 | if (QFileInfo(docroot+path).isDir()) 70 | { 71 | path+="/index.html"; 72 | } 73 | // Try to open the file 74 | QFile file(docroot+path); 75 | qDebug("StaticFileController: Open file %s",qPrintable(file.fileName())); 76 | if (file.open(QIODevice::ReadOnly)) 77 | { 78 | setContentType(path,response); 79 | response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000)); 80 | if (file.size()<=maxCachedFileSize) 81 | { 82 | // Return the file content and store it also in the cache 83 | entry=new CacheEntry(); 84 | while (!file.atEnd() && !file.error()) 85 | { 86 | QByteArray buffer=file.read(65536); 87 | response.write(buffer); 88 | entry->document.append(buffer); 89 | } 90 | entry->created=now; 91 | entry->filename=path; 92 | mutex.lock(); 93 | cache.insert(request.getPath(),entry,entry->document.size()); 94 | mutex.unlock(); 95 | } 96 | else 97 | { 98 | // Return the file content, do not store in cache 99 | while (!file.atEnd() && !file.error()) 100 | { 101 | response.write(file.read(65536)); 102 | } 103 | } 104 | file.close(); 105 | } 106 | else { 107 | if (file.exists()) 108 | { 109 | qWarning("StaticFileController: Cannot open existing file %s for reading",qPrintable(file.fileName())); 110 | response.setStatus(403,"forbidden"); 111 | response.write("403 forbidden",true); 112 | } 113 | else 114 | { 115 | response.setStatus(404,"not found"); 116 | response.write("404 not found",true); 117 | } 118 | } 119 | } 120 | } 121 | 122 | void StaticFileController::setContentType(QString fileName, HttpResponse& response) const 123 | { 124 | if (fileName.endsWith(".png")) 125 | { 126 | response.setHeader("Content-Type", "image/png"); 127 | } 128 | else if (fileName.endsWith(".jpg")) 129 | { 130 | response.setHeader("Content-Type", "image/jpeg"); 131 | } 132 | else if (fileName.endsWith(".gif")) 133 | { 134 | response.setHeader("Content-Type", "image/gif"); 135 | } 136 | else if (fileName.endsWith(".pdf")) 137 | { 138 | response.setHeader("Content-Type", "application/pdf"); 139 | } 140 | else if (fileName.endsWith(".txt")) 141 | { 142 | response.setHeader("Content-Type", qPrintable("text/plain; charset="+encoding)); 143 | } 144 | else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) 145 | { 146 | response.setHeader("Content-Type", qPrintable("text/html; charset="+encoding)); 147 | } 148 | else if (fileName.endsWith(".css")) 149 | { 150 | response.setHeader("Content-Type", "text/css"); 151 | } 152 | else if (fileName.endsWith(".js")) 153 | { 154 | response.setHeader("Content-Type", "text/javascript"); 155 | } 156 | else if (fileName.endsWith(".svg")) 157 | { 158 | response.setHeader("Content-Type", "image/svg+xml"); 159 | } 160 | else if (fileName.endsWith(".woff")) 161 | { 162 | response.setHeader("Content-Type", "font/woff"); 163 | } 164 | else if (fileName.endsWith(".woff2")) 165 | { 166 | response.setHeader("Content-Type", "font/woff2"); 167 | } 168 | else if (fileName.endsWith(".ttf")) 169 | { 170 | response.setHeader("Content-Type", "application/x-font-ttf"); 171 | } 172 | else if (fileName.endsWith(".eot")) 173 | { 174 | response.setHeader("Content-Type", "application/vnd.ms-fontobject"); 175 | } 176 | else if (fileName.endsWith(".otf")) 177 | { 178 | response.setHeader("Content-Type", "application/font-otf"); 179 | } 180 | // Todo: add all of your content types 181 | else 182 | { 183 | qDebug("StaticFileController: unknown MIME type for filename '%s'", qPrintable(fileName)); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/httpServer/core/httprequest.h: -------------------------------------------------------------------------------- 1 | /** 2 | @file 3 | @author Stefan Frings 4 | */ 5 | 6 | #ifndef HTTPREQUEST_H 7 | #define HTTPREQUEST_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "httpglobal.h" 18 | 19 | /** 20 | This object represents a single HTTP request. It reads the request 21 | from a TCP socket and provides getters for the individual parts 22 | of the request. 23 |

24 | The follwing config settings are required: 25 |

 26 |   maxRequestSize=16000
 27 |   maxMultiPartSize=1000000
 28 |   
29 |

30 | MaxRequestSize is the maximum size of a HTTP request. In case of 31 | multipart/form-data requests (also known as file-upload), the maximum 32 | size of the body must not exceed maxMultiPartSize. 33 | The body is always a little larger than the file itself. 34 | */ 35 | 36 | class DECLSPEC HttpRequest { 37 | Q_DISABLE_COPY(HttpRequest) 38 | friend class HttpSessionStore; 39 | 40 | public: 41 | 42 | /** Values for getStatus() */ 43 | enum RequestStatus {waitForRequest, waitForHeader, waitForBody, complete, abort}; 44 | 45 | /** 46 | Constructor. 47 | @param settings Configuration settings 48 | */ 49 | HttpRequest(QSettings* settings); 50 | 51 | /** 52 | Destructor. 53 | */ 54 | virtual ~HttpRequest(); 55 | 56 | /** 57 | Read the HTTP request from a socket. 58 | This method is called by the connection handler repeatedly 59 | until the status is RequestStatus::complete or RequestStatus::abort. 60 | @param socket Source of the data 61 | */ 62 | void readFromSocket(QTcpSocket* socket); 63 | 64 | /** 65 | Get the status of this reqeust. 66 | @see RequestStatus 67 | */ 68 | RequestStatus getStatus() const; 69 | 70 | /** Get the method of the HTTP request (e.g. "GET") */ 71 | QByteArray getMethod() const; 72 | 73 | /** Get the decoded path of the HTPP request (e.g. "/index.html") */ 74 | QByteArray getPath() const; 75 | 76 | /** Get the raw path of the HTTP request (e.g. "/file%20with%20spaces.html") */ 77 | const QByteArray& getRawPath() const; 78 | 79 | /** Get the version of the HTPP request (e.g. "HTTP/1.1") */ 80 | QByteArray getVersion() const; 81 | 82 | /** 83 | Get the value of a HTTP request header. 84 | @param name Name of the header, not case-senitive. 85 | @return If the header occurs multiple times, only the last 86 | one is returned. 87 | */ 88 | QByteArray getHeader(const QByteArray& name) const; 89 | 90 | /** 91 | Get the values of a HTTP request header. 92 | @param name Name of the header, not case-senitive. 93 | */ 94 | QList getHeaders(const QByteArray& name) const; 95 | 96 | /** 97 | * Get all HTTP request headers. Note that the header names 98 | * are returned in lower-case. 99 | */ 100 | QMultiMap getHeaderMap() const; 101 | 102 | /** 103 | Get the value of a HTTP request parameter. 104 | @param name Name of the parameter, case-sensitive. 105 | @return If the parameter occurs multiple times, only the last 106 | one is returned. 107 | */ 108 | QByteArray getParameter(const QByteArray& name) const; 109 | 110 | /** 111 | Get the values of a HTTP request parameter. 112 | @param name Name of the parameter, case-sensitive. 113 | */ 114 | QList getParameters(const QByteArray& name) const; 115 | 116 | /** Get all HTTP request parameters. */ 117 | QMultiMap getParameterMap() const; 118 | 119 | /** Get the HTTP request body. */ 120 | QByteArray getBody() const; 121 | 122 | /** 123 | Decode an URL parameter. 124 | E.g. replace "%23" by '#' and replace '+' by ' '. 125 | @param source The url encoded strings 126 | @see QUrl::toPercentEncoding for the reverse direction 127 | */ 128 | static QByteArray urlDecode(const QByteArray source); 129 | 130 | /** 131 | Get an uploaded file. The file is already open. It will 132 | be closed and deleted by the destructor of this HttpRequest 133 | object (after processing the request). 134 |

135 | For uploaded files, the method getParameters() returns 136 | the original fileName as provided by the calling web browser. 137 | */ 138 | QTemporaryFile* getUploadedFile(const QByteArray fieldName) const; 139 | 140 | /** 141 | Get the value of a cookie. 142 | @param name Name of the cookie 143 | */ 144 | QByteArray getCookie(const QByteArray& name) const; 145 | 146 | /** Get all cookies. */ 147 | QMap& getCookieMap(); 148 | 149 | /** 150 | Get the address of the connected client. 151 | Note that multiple clients may have the same IP address, if they 152 | share an internet connection (which is very common). 153 | */ 154 | QHostAddress getPeerAddress() const; 155 | 156 | private: 157 | 158 | /** Request headers */ 159 | QMultiMap headers; 160 | 161 | /** Parameters of the request */ 162 | QMultiMap parameters; 163 | 164 | /** Uploaded files of the request, key is the field name. */ 165 | QMap uploadedFiles; 166 | 167 | /** Received cookies */ 168 | QMap cookies; 169 | 170 | /** Storage for raw body data */ 171 | QByteArray bodyData; 172 | 173 | /** Request method */ 174 | QByteArray method; 175 | 176 | /** Request path (in raw encoded format) */ 177 | QByteArray path; 178 | 179 | /** Request protocol version */ 180 | QByteArray version; 181 | 182 | /** 183 | Status of this request. For the state engine. 184 | @see RequestStatus 185 | */ 186 | RequestStatus status; 187 | 188 | /** Address of the connected peer. */ 189 | QHostAddress peerAddress; 190 | 191 | /** Maximum size of requests in bytes. */ 192 | int maxSize; 193 | 194 | /** Maximum allowed size of multipart forms in bytes. */ 195 | int maxMultiPartSize; 196 | 197 | /** Current size */ 198 | int currentSize; 199 | 200 | /** Expected size of body */ 201 | int expectedBodySize; 202 | 203 | /** Name of the current header, or empty if no header is being processed */ 204 | QByteArray currentHeader; 205 | 206 | /** Boundary of multipart/form-data body. Empty if there is no such header */ 207 | QByteArray boundary; 208 | 209 | /** Temp file, that is used to store the multipart/form-data body */ 210 | QTemporaryFile tempFile; 211 | 212 | /** Parset he multipart body, that has been stored in the temp file. */ 213 | void parseMultiPartFile(); 214 | 215 | /** Sub-procedure of readFromSocket(), read the first line of a request. */ 216 | void readRequest(QTcpSocket* socket); 217 | 218 | /** Sub-procedure of readFromSocket(), read header lines. */ 219 | void readHeader(QTcpSocket* socket); 220 | 221 | /** Sub-procedure of readFromSocket(), read the request body. */ 222 | void readBody(QTcpSocket* socket); 223 | 224 | /** Sub-procedure of readFromSocket(), extract and decode request parameters. */ 225 | void decodeRequestParams(); 226 | 227 | /** Sub-procedure of readFromSocket(), extract cookies from headers */ 228 | void extractCookies(); 229 | 230 | /** Buffer for collecting characters of request and header lines */ 231 | QByteArray lineBuffer; 232 | 233 | }; 234 | 235 | #endif // HTTPREQUEST_H 236 | -------------------------------------------------------------------------------- /installer/create-dmg/create-dmg.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Create a read-only disk image of the contents of a folder 4 | 5 | set -e; 6 | 7 | function pure_version() { 8 | echo '1.0.0.2' 9 | } 10 | 11 | function version() { 12 | echo "create-dmg $(pure_version)" 13 | } 14 | 15 | function usage() { 16 | version 17 | echo "Creates a fancy DMG file." 18 | echo "Usage: $(basename $0) options... image.dmg source_folder" 19 | echo "All contents of source_folder will be copied into the disk image." 20 | echo "Options:" 21 | echo " --volname name" 22 | echo " set volume name (displayed in the Finder sidebar and window title)" 23 | echo " --volicon icon.icns" 24 | echo " set volume icon" 25 | echo " --background pic.png" 26 | echo " set folder background image (provide png, gif, jpg)" 27 | echo " --window-pos x y" 28 | echo " set position the folder window" 29 | echo " --window-size width height" 30 | echo " set size of the folder window" 31 | echo " --text-size text_size" 32 | echo " set window text size (10-16)" 33 | echo " --icon-size icon_size" 34 | echo " set window icons size (up to 128)" 35 | echo " --icon file_name x y" 36 | echo " set position of the file's icon" 37 | echo " --hide-extension file_name" 38 | echo " hide the extension of file" 39 | echo " --custom-icon file_name custom_icon_or_sample_file x y" 40 | echo " set position and custom icon" 41 | echo " --app-drop-link x y" 42 | echo " make a drop link to Applications, at location x,y" 43 | echo " --eula eula_file" 44 | echo " attach a license file to the dmg" 45 | echo " --no-internet-enable" 46 | echo " disable automatic mount©" 47 | echo " --version show tool version number" 48 | echo " -h, --help display this help" 49 | exit 0 50 | } 51 | 52 | WINX=10 53 | WINY=60 54 | WINW=500 55 | WINH=350 56 | ICON_SIZE=128 57 | TEXT_SIZE=16 58 | 59 | while test "${1:0:1}" = "-"; do 60 | case $1 in 61 | --volname) 62 | VOLUME_NAME="$2" 63 | shift; shift;; 64 | --volicon) 65 | VOLUME_ICON_FILE="$2" 66 | shift; shift;; 67 | --background) 68 | BACKGROUND_FILE="$2" 69 | BACKGROUND_FILE_NAME="$(basename $BACKGROUND_FILE)" 70 | BACKGROUND_CLAUSE="set background picture of opts to file \".background:$BACKGROUND_FILE_NAME\"" 71 | REPOSITION_HIDDEN_FILES_CLAUSE="set position of every item to {theBottomRightX + 100, 100}" 72 | shift; shift;; 73 | --icon-size) 74 | ICON_SIZE="$2" 75 | shift; shift;; 76 | --text-size) 77 | TEXT_SIZE="$2" 78 | shift; shift;; 79 | --window-pos) 80 | WINX=$2; WINY=$3 81 | shift; shift; shift;; 82 | --window-size) 83 | WINW=$2; WINH=$3 84 | shift; shift; shift;; 85 | --icon) 86 | POSITION_CLAUSE="${POSITION_CLAUSE}set position of item \"$2\" to {$3, $4} 87 | " 88 | shift; shift; shift; shift;; 89 | --hide-extension) 90 | HIDING_CLAUSE="${HIDING_CLAUSE}set the extension hidden of item \"$2\" to true 91 | " 92 | shift; shift;; 93 | --custom-icon) 94 | shift; shift; shift; shift; shift;; 95 | -h | --help) 96 | usage;; 97 | --version) 98 | version; exit 0;; 99 | --pure-version) 100 | pure_version; exit 0;; 101 | --app-drop-link) 102 | APPLICATION_LINK=$2 103 | APPLICATION_CLAUSE="set position of item \"Applications\" to {$2, $3} 104 | " 105 | shift; shift; shift;; 106 | --eula) 107 | EULA_RSRC=$2 108 | shift; shift;; 109 | --no-internet-enable) 110 | NOINTERNET=1 111 | shift;; 112 | -*) 113 | echo "Unknown option $1. Run with --help for help." 114 | exit 1;; 115 | esac 116 | done 117 | 118 | test -z "$2" && { 119 | echo "Not enough arguments. Invoke with --help for help." 120 | exit 1 121 | } 122 | 123 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 124 | DMG_PATH="$1" 125 | DMG_DIRNAME="$(dirname "$DMG_PATH")" 126 | DMG_DIR="$(cd "$DMG_DIRNAME" > /dev/null; pwd)" 127 | DMG_NAME="$(basename "$DMG_PATH")" 128 | DMG_TEMP_NAME="$DMG_DIR/rw.${DMG_NAME}" 129 | SRC_FOLDER="$(cd "$2" > /dev/null; pwd)" 130 | test -z "$VOLUME_NAME" && VOLUME_NAME="$(basename "$DMG_PATH" .dmg)" 131 | 132 | AUX_PATH="$SCRIPT_DIR/support" 133 | 134 | test -d "$AUX_PATH" || { 135 | echo "Cannot find support directory: $AUX_PATH" 136 | exit 1 137 | } 138 | 139 | if [ -f "$SRC_FOLDER/.DS_Store" ]; then 140 | echo "Deleting any .DS_Store in source folder" 141 | rm "$SRC_FOLDER/.DS_Store" 142 | fi 143 | 144 | # Create the image 145 | echo "Creating disk image..." 146 | test -f "${DMG_TEMP_NAME}" && rm -f "${DMG_TEMP_NAME}" 147 | ACTUAL_SIZE=`du -sm "$SRC_FOLDER" | sed -e 's/ .*//g'` 148 | DISK_IMAGE_SIZE=$(expr $ACTUAL_SIZE + 20) 149 | hdiutil create -srcfolder "$SRC_FOLDER" -volname "${VOLUME_NAME}" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -size ${DISK_IMAGE_SIZE}m "${DMG_TEMP_NAME}" 150 | 151 | # mount it 152 | echo "Mounting disk image..." 153 | MOUNT_DIR="/Volumes/${VOLUME_NAME}" 154 | 155 | # try unmount dmg if it was mounted previously (e.g. developer mounted dmg, installed app and forgot to unmount it) 156 | echo "Unmounting disk image..." 157 | DEV_NAME=$(hdiutil info | egrep '^/dev/' | sed 1q | awk '{print $1}') 158 | test -d "${MOUNT_DIR}" && hdiutil detach "${DEV_NAME}" 159 | 160 | echo "Mount directory: $MOUNT_DIR" 161 | DEV_NAME=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_TEMP_NAME}" | egrep '^/dev/' | sed 1q | awk '{print $1}') 162 | echo "Device name: $DEV_NAME" 163 | 164 | if ! test -z "$BACKGROUND_FILE"; then 165 | echo "Copying background file..." 166 | test -d "$MOUNT_DIR/.background" || mkdir "$MOUNT_DIR/.background" 167 | cp "$BACKGROUND_FILE" "$MOUNT_DIR/.background/$BACKGROUND_FILE_NAME" 168 | fi 169 | 170 | if ! test -z "$APPLICATION_LINK"; then 171 | echo "making link to Applications dir" 172 | echo $MOUNT_DIR 173 | ln -s /Applications "$MOUNT_DIR/Applications" 174 | fi 175 | 176 | if ! test -z "$VOLUME_ICON_FILE"; then 177 | echo "Copying volume icon file '$VOLUME_ICON_FILE'..." 178 | cp "$VOLUME_ICON_FILE" "$MOUNT_DIR/.VolumeIcon.icns" 179 | SetFile -c icnC "$MOUNT_DIR/.VolumeIcon.icns" 180 | fi 181 | 182 | # run applescript 183 | APPLESCRIPT=$(mktemp -t createdmg) 184 | cat "$AUX_PATH/template.applescript" | sed -e "s/WINX/$WINX/g" -e "s/WINY/$WINY/g" -e "s/WINW/$WINW/g" -e "s/WINH/$WINH/g" -e "s/BACKGROUND_CLAUSE/$BACKGROUND_CLAUSE/g" -e "s/REPOSITION_HIDDEN_FILES_CLAUSE/$REPOSITION_HIDDEN_FILES_CLAUSE/g" -e "s/ICON_SIZE/$ICON_SIZE/g" -e "s/TEXT_SIZE/$TEXT_SIZE/g" | perl -pe "s/POSITION_CLAUSE/$POSITION_CLAUSE/g" | perl -pe "s/APPLICATION_CLAUSE/$APPLICATION_CLAUSE/g" | perl -pe "s/HIDING_CLAUSE/$HIDING_CLAUSE/" >"$APPLESCRIPT" 185 | 186 | echo "Running Applescript: /usr/bin/osascript \"${APPLESCRIPT}\" \"${VOLUME_NAME}\"" 187 | "/usr/bin/osascript" "${APPLESCRIPT}" "${VOLUME_NAME}" || true 188 | echo "Done running the applescript..." 189 | sleep 4 190 | 191 | rm "$APPLESCRIPT" 192 | 193 | # make sure it's not world writeable 194 | echo "Fixing permissions..." 195 | chmod -Rf go-w "${MOUNT_DIR}" &> /dev/null || true 196 | echo "Done fixing permissions." 197 | 198 | # make the top window open itself on mount: 199 | echo "Blessing started" 200 | bless --folder "${MOUNT_DIR}" --openfolder "${MOUNT_DIR}" 201 | echo "Blessing finished" 202 | 203 | if ! test -z "$VOLUME_ICON_FILE"; then 204 | # tell the volume that it has a special file attribute 205 | SetFile -a C "$MOUNT_DIR" 206 | fi 207 | 208 | # unmount 209 | echo "Unmounting disk image..." 210 | hdiutil detach "${DEV_NAME}" 211 | 212 | # compress image 213 | echo "Compressing disk image..." 214 | hdiutil convert "${DMG_TEMP_NAME}" -format UDZO -imagekey zlib-level=9 -o "${DMG_DIR}/${DMG_NAME}" 215 | rm -f "${DMG_TEMP_NAME}" 216 | 217 | # adding EULA resources 218 | if [ ! -z "${EULA_RSRC}" -a "${EULA_RSRC}" != "-null-" ]; then 219 | echo "adding EULA resources" 220 | "${AUX_PATH}/dmg-license.py" "${DMG_DIR}/${DMG_NAME}" "${EULA_RSRC}" 221 | fi 222 | 223 | if [ ! -z "${NOINTERNET}" -a "${NOINTERNET}" == 1 ]; then 224 | echo "not setting 'internet-enable' on the dmg" 225 | else 226 | hdiutil internet-enable -yes "${DMG_DIR}/${DMG_NAME}" 227 | fi 228 | 229 | echo "Disk image done" 230 | exit 0 231 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | This version of the GNU Lesser General Public License incorporates 9 | the terms and conditions of version 3 of the GNU General Public 10 | License, supplemented by the additional permissions listed below. 11 | 12 | 0. Additional Definitions. 13 | 14 | As used herein, "this License" refers to version 3 of the GNU Lesser 15 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 16 | General Public License. 17 | 18 | "The Library" refers to a covered work governed by this License, 19 | other than an Application or a Combined Work as defined below. 20 | 21 | An "Application" is any work that makes use of an interface provided 22 | by the Library, but which is not otherwise based on the Library. 23 | Defining a subclass of a class defined by the Library is deemed a mode 24 | of using an interface provided by the Library. 25 | 26 | A "Combined Work" is a work produced by combining or linking an 27 | Application with the Library. The particular version of the Library 28 | with which the Combined Work was made is also called the "Linked 29 | Version". 30 | 31 | The "Minimal Corresponding Source" for a Combined Work means the 32 | Corresponding Source for the Combined Work, excluding any source code 33 | for portions of the Combined Work that, considered in isolation, are 34 | based on the Application, and not on the Linked Version. 35 | 36 | The "Corresponding Application Code" for a Combined Work means the 37 | object code and/or source code for the Application, including any data 38 | and utility programs needed for reproducing the Combined Work from the 39 | Application, but excluding the System Libraries of the Combined Work. 40 | 41 | 1. Exception to Section 3 of the GNU GPL. 42 | 43 | You may convey a covered work under sections 3 and 4 of this License 44 | without being bound by section 3 of the GNU GPL. 45 | 46 | 2. Conveying Modified Versions. 47 | 48 | If you modify a copy of the Library, and, in your modifications, a 49 | facility refers to a function or data to be supplied by an Application 50 | that uses the facility (other than as an argument passed when the 51 | facility is invoked), then you may convey a copy of the modified 52 | version: 53 | 54 | a) under this License, provided that you make a good faith effort to 55 | ensure that, in the event an Application does not supply the 56 | function or data, the facility still operates, and performs 57 | whatever part of its purpose remains meaningful, or 58 | 59 | b) under the GNU GPL, with none of the additional permissions of 60 | this License applicable to that copy. 61 | 62 | 3. Object Code Incorporating Material from Library Header Files. 63 | 64 | The object code form of an Application may incorporate material from 65 | a header file that is part of the Library. You may convey such object 66 | code under terms of your choice, provided that, if the incorporated 67 | material is not limited to numerical parameters, data structure 68 | layouts and accessors, or small macros, inline functions and templates 69 | (ten or fewer lines in length), you do both of the following: 70 | 71 | a) Give prominent notice with each copy of the object code that the 72 | Library is used in it and that the Library and its use are 73 | covered by this License. 74 | 75 | b) Accompany the object code with a copy of the GNU GPL and this license 76 | document. 77 | 78 | 4. Combined Works. 79 | 80 | You may convey a Combined Work under terms of your choice that, 81 | taken together, effectively do not restrict modification of the 82 | portions of the Library contained in the Combined Work and reverse 83 | engineering for debugging such modifications, if you also do each of 84 | the following: 85 | 86 | a) Give prominent notice with each copy of the Combined Work that 87 | the Library is used in it and that the Library and its use are 88 | covered by this License. 89 | 90 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 91 | document. 92 | 93 | c) For a Combined Work that displays copyright notices during 94 | execution, include the copyright notice for the Library among 95 | these notices, as well as a reference directing the user to the 96 | copies of the GNU GPL and this license document. 97 | 98 | d) Do one of the following: 99 | 100 | 0) Convey the Minimal Corresponding Source under the terms of this 101 | License, and the Corresponding Application Code in a form 102 | suitable for, and under terms that permit, the user to 103 | recombine or relink the Application with a modified version of 104 | the Linked Version to produce a modified Combined Work, in the 105 | manner specified by section 6 of the GNU GPL for conveying 106 | Corresponding Source. 107 | 108 | 1) Use a suitable shared library mechanism for linking with the 109 | Library. A suitable mechanism is one that (a) uses at run time 110 | a copy of the Library already present on the user's computer 111 | system, and (b) will operate properly with a modified version 112 | of the Library that is interface-compatible with the Linked 113 | Version. 114 | 115 | e) Provide Installation Information, but only if you would otherwise 116 | be required to provide such information under section 6 of the 117 | GNU GPL, and only to the extent that such information is 118 | necessary to install and execute a modified version of the 119 | Combined Work produced by recombining or relinking the 120 | Application with a modified version of the Linked Version. (If 121 | you use option 4d0, the Installation Information must accompany 122 | the Minimal Corresponding Source and Corresponding Application 123 | Code. If you use option 4d1, you must provide the Installation 124 | Information in the manner specified by section 6 of the GNU GPL 125 | for conveying Corresponding Source.) 126 | 127 | 5. Combined Libraries. 128 | 129 | You may place library facilities that are a work based on the 130 | Library side by side in a single library together with other library 131 | facilities that are not Applications and are not covered by this 132 | License, and convey such a combined library under terms of your 133 | choice, if you do both of the following: 134 | 135 | a) Accompany the combined library with a copy of the same work based 136 | on the Library, uncombined with any other library facilities, 137 | conveyed under the terms of this License. 138 | 139 | b) Give prominent notice with the combined library that part of it 140 | is a work based on the Library, and explaining where to find the 141 | accompanying uncombined form of the same work. 142 | 143 | 6. Revised Versions of the GNU Lesser General Public License. 144 | 145 | The Free Software Foundation may publish revised and/or new versions 146 | of the GNU Lesser General Public License from time to time. Such new 147 | versions will be similar in spirit to the present version, but may 148 | differ in detail to address new problems or concerns. 149 | 150 | Each version is given a distinguishing version number. If the 151 | Library as you received it specifies that a certain numbered version 152 | of the GNU Lesser General Public License "or any later version" 153 | applies to it, you have the option of following the terms and 154 | conditions either of that published version or of any later version 155 | published by the Free Software Foundation. If the Library as you 156 | received it does not specify a version number of the GNU Lesser 157 | General Public License, you may choose any version of the GNU Lesser 158 | General Public License ever published by the Free Software Foundation. 159 | 160 | If the Library as you received it specifies that a proxy can decide 161 | whether future versions of the GNU Lesser General Public License shall 162 | apply, that proxy's public statement of acceptance of any version is 163 | permanent authorization for you to choose that version for the 164 | Library. 165 | 166 | Thanks to: 167 | Dmitry Sazonov for RunGuard example. 168 | Mark Adler and Jean-loup Gailly for zlib (http://www.zlib.net/). 169 | Sergey A. Tachenov for quazip (http://quazip.sourceforge.net/). 170 | --------------------------------------------------------------------------------