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 |
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 |
--------------------------------------------------------------------------------