├── resources
├── icon.rc
├── PXM_Icon.ico
├── message.wav
├── PXMessenger.png
├── PXMessenger_wBackground.png
├── PXMessenger_TightCrop_100px.png
├── pxmessenger.desktop
├── resources.qrc
└── updates.json
├── include
├── QSimpleUpdater
│ ├── .gitattributes
│ ├── etc
│ │ ├── resources
│ │ │ ├── update.png
│ │ │ └── qsimpleupdater.qrc
│ │ ├── screenshots
│ │ │ ├── tutorial.png
│ │ │ ├── downloading.png
│ │ │ └── download-complete.png
│ │ └── scripts
│ │ │ ├── format-code.sh
│ │ │ └── format-code.bat
│ ├── .gitignore
│ ├── .travis.yml
│ ├── COPYING.md
│ ├── QSimpleUpdater.pro
│ ├── QSimpleUpdater.pri
│ ├── src
│ │ ├── Downloader.h
│ │ ├── Updater.h
│ │ ├── Downloader.ui
│ │ ├── Downloader.cpp
│ │ ├── Updater.cpp
│ │ └── QSimpleUpdater.cpp
│ ├── README.md
│ └── include
│ │ └── QSimpleUpdater.h
├── pxmsync.h
├── pxmagent.h
├── pxminireader.h
├── netcompression.h
├── pxmsettingsdialog.h
├── pxmconsts.h
├── pxmclient.h
├── pxmpeerworker.h
├── pxmconsole.h
├── pxmpeers.h
├── timedvector.h
├── pxmstackwidget.h
├── pxmserver.h
└── pxmmainwindow.h
├── .gitignore
├── .travis.yml
├── docker
└── Dockerfile
├── src
├── pxmsync.cpp
├── netcompression.cpp
├── pxmessenger.cpp
├── pxmpeers.cpp
├── pxmconsole.cpp
├── pxminireader.cpp
├── pxmclient.cpp
├── pxmstackwidget.cpp
└── pxmagent.cpp
├── README.md
├── PXMessenger.pro
└── ui
├── manualconnect.ui
├── pxmaboutdialog.ui
├── pxmmainwindow.ui
└── pxmsettingsdialog.ui
/resources/icon.rc:
--------------------------------------------------------------------------------
1 | IDI_ICON1 ICON DISCARDABLE "PXM_Icon.ico"
2 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/.gitattributes:
--------------------------------------------------------------------------------
1 | doc/* linguist-documentation
2 |
--------------------------------------------------------------------------------
/resources/PXM_Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/resources/PXM_Icon.ico
--------------------------------------------------------------------------------
/resources/message.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/resources/message.wav
--------------------------------------------------------------------------------
/resources/PXMessenger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/resources/PXMessenger.png
--------------------------------------------------------------------------------
/resources/PXMessenger_wBackground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/resources/PXMessenger_wBackground.png
--------------------------------------------------------------------------------
/resources/PXMessenger_TightCrop_100px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/resources/PXMessenger_TightCrop_100px.png
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/resources/update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/include/QSimpleUpdater/etc/resources/update.png
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/screenshots/tutorial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/include/QSimpleUpdater/etc/screenshots/tutorial.png
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/screenshots/downloading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/include/QSimpleUpdater/etc/screenshots/downloading.png
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/screenshots/download-complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corybolar/PXMessenger/HEAD/include/QSimpleUpdater/etc/screenshots/download-complete.png
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/resources/qsimpleupdater.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | update.png
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /PXMessenger.pro.user
2 | /*.exe
3 | /PXMessenger
4 | /object_script*
5 | /build-unix
6 | /build-win*
7 | /.qmake.stash
8 | /Makefile*
9 | /*_plugin_import.cpp
10 | /PXMessenger*_resource.rc
11 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 | *.obj
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Fortran module files
12 | *.mod
13 |
14 | # Executables
15 | *.exe
16 | *.out
17 | *.app
18 |
19 | *.user
20 |
--------------------------------------------------------------------------------
/resources/pxmessenger.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Exec=PXMessenger
4 | Terminal=false
5 | Name=PXMessenger
6 | Icon=/usr/share/pixmaps/PXMessenger.png
7 | GenericName=Instant Messenger
8 | Comment=P2P Instant Messenger
9 | Categories=Network;InstantMessaging;Chat
10 |
--------------------------------------------------------------------------------
/resources/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | PXM_Icon.ico
4 | PXMessenger_TightCrop_100px.png
5 | PXMessenger_wBackground.png
6 | message.wav
7 | icon.rc
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: none
2 | sudo: required
3 |
4 | services:
5 | - docker
6 |
7 | before_install:
8 | - docker build -t xenial-pxm ./docker
9 | - docker run -t -d -p 127.0.0.1:80:80 --name build xenial-pxm /bin/sh
10 |
11 | script:
12 | - docker ps -a
13 | - docker exec build sh -c "cd pxmessenger && qmake && make -j4"
14 | - docker stop build
15 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/scripts/format-code.sh:
--------------------------------------------------------------------------------
1 | # Style and format recursively
2 | astyle --style=linux --indent=spaces --align-pointer=type --indent-preproc-block --indent-preproc-define --indent-col1-comments --pad-first-paren-out --pad-oper --attach-namespaces --remove-brackets --convert-tabs --close-templates --max-code-length=100 --max-instatement-indent=50 --lineend=windows --suffix=none --recursive ../../*.h ../../*.c ../../*.cpp ../../*.cc
3 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:xenial
2 |
3 | RUN apt-get update -q && apt-get install -y software-properties-common
4 | RUN add-apt-repository ppa:ubuntu-toolchain-r/test -y
5 | RUN apt-get update -q && apt-get install -y libqt5gui5 \
6 | qtbase5-dev \
7 | libqt5multimedia5 \
8 | qtmultimedia5-dev \
9 | libevent-2.0-5 \
10 | libevent-dev \
11 | g++-5 \
12 | make \
13 | git \
14 | qt5-default \
15 | g++
16 |
17 | RUN git clone https://github.com/cbpeckles/pxmessenger
18 |
19 | ENTRYPOINT /bin/bash
20 |
--------------------------------------------------------------------------------
/resources/updates.json:
--------------------------------------------------------------------------------
1 | {
2 | "updates": {
3 | "windows32": {
4 | "open-url": "",
5 | "latest-version": "1.6.0",
6 | "download-url": "https://github.com/cbpeckles/PXMessenger/releases/download/v1.6.0/PXMessenger-Setup-v1.6.0-x86.exe",
7 | "changelog": ""
8 | },
9 | "windows64": {
10 | "open-url": "",
11 | "latest-version": "1.6.0",
12 | "download-url": "https://github.com/cbpeckles/PXMessenger/releases/download/v1.6.0/PXMessenger-Setup-v1.6.0-x86_64.exe",
13 | "changelog": ""
14 | }
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 | compiler: gcc
3 |
4 | dist: trusty
5 | sudo: required
6 |
7 | before_install:
8 | - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
9 | - sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa
10 | - sudo apt-get update -qq
11 |
12 | install:
13 | - sudo apt-get install -y --force-yes build-essential g++-4.8 -y
14 | - sudo apt-get install -y --force-yes libudev-dev libts-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev -y
15 | - sudo apt-get install -y --force-yes qtbase5-dev qtdeclarative5-dev libqt5gui5 qttools5-dev-tools qttools5-dev qtmultimedia5-dev
16 |
17 | script:
18 | - qmake -qt=qt5 QSimpleUpdater.pro
19 | - make -j4
20 |
--------------------------------------------------------------------------------
/include/pxmsync.h:
--------------------------------------------------------------------------------
1 | #ifndef PXMSYNC_H
2 | #define PXMSYNC_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "pxmpeers.h"
10 |
11 | namespace Peers
12 | {
13 | class BevWrapper;
14 | class PeerData;
15 | }
16 |
17 | class PXMSync : public QObject
18 | {
19 | Q_OBJECT
20 | QHash syncHash;
21 |
22 | public:
23 | PXMSync(QObject* parent, QHash &hash);
24 | void setsyncHash(const QHash &hash);
25 | QHash::iterator hashIterator;
26 | void setIteratorToStart();
27 | public slots:
28 | void syncNext();
29 | signals:
30 | void requestIps(QSharedPointer, QUuid);
31 | void syncComplete();
32 | };
33 |
34 | #endif // MESSSYNC_H
35 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/etc/scripts/format-code.bat:
--------------------------------------------------------------------------------
1 | :: Description: This script changes the style format of
2 | :: all the source code of the project.
3 |
4 | :: Setup the command line
5 | @echo off
6 | title Code Formatter
7 |
8 | :: Go to the directory where the script is run
9 | cd /d %~dp0
10 |
11 | :: Style and format the source code recursively
12 | astyle --style=linux --indent=spaces --align-pointer=type --indent-preproc-block --indent-preproc-define --indent-col1-comments --pad-first-paren-out --pad-oper --attach-namespaces --remove-brackets --convert-tabs --close-templates --max-code-length=100 --max-instatement-indent=50 --lineend=windows --suffix=none --recursive ../../*.h ../../*.cpp ../../*.c
13 |
14 | :: Notify the user that we have finished
15 | echo.
16 | echo Code styling complete!
17 | echo.
18 |
19 | :: Let the user see the output
20 | pause
21 |
--------------------------------------------------------------------------------
/src/pxmsync.cpp:
--------------------------------------------------------------------------------
1 | #include "pxmsync.h"
2 |
3 | #include
4 |
5 | #include "pxmpeers.h"
6 |
7 | PXMSync::PXMSync(QObject* parent, QHash& hash) : QObject(parent), syncHash(hash)
8 | {
9 | }
10 | void PXMSync::syncNext()
11 | {
12 | while (hashIterator != syncHash.end() && !(hashIterator.value().isAuthed)) {
13 | hashIterator++;
14 | }
15 | if (hashIterator == syncHash.end()) {
16 | emit syncComplete();
17 | return;
18 | } else {
19 | emit requestIps(hashIterator.value().bw, hashIterator.value().uuid);
20 | }
21 | hashIterator++;
22 | }
23 |
24 | void PXMSync::setsyncHash(const QHash& hash)
25 | {
26 | syncHash = hash;
27 | hashIterator = QHash::iterator();
28 | }
29 | void PXMSync::setIteratorToStart()
30 | {
31 | hashIterator = syncHash.begin();
32 | }
33 |
--------------------------------------------------------------------------------
/include/pxmagent.h:
--------------------------------------------------------------------------------
1 | #ifndef PXMAGENT_H
2 | #define PXMAGENT_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 | #include
10 |
11 | class PXMAgentPrivate;
12 | class PXMAgent : public QObject
13 | {
14 | Q_OBJECT
15 |
16 | QScopedPointer d_ptr;
17 |
18 | public:
19 | // Default
20 | PXMAgent(QObject* parent = 0);
21 | // Copy
22 | PXMAgent(const PXMAgent& agent) = delete;
23 | // Copy Assignment
24 | PXMAgent& operator=(const PXMAgent& agent) = delete;
25 | // Move
26 | PXMAgent(PXMAgent&& agent) noexcept = delete;
27 | // Move Assignment
28 | PXMAgent& operator=(PXMAgent&& agent) noexcept = delete;
29 | // Destructor
30 | ~PXMAgent();
31 |
32 | static QPalette defaultPalette;
33 | static void changeToDark();
34 |
35 | public slots:
36 | void doneChkUpdt(const QString &);
37 | int init();
38 | private slots:
39 | int postInit();
40 | signals:
41 | void alreadyRunning();
42 | };
43 |
44 | #endif // PXMAGENT_H
45 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/COPYING.md:
--------------------------------------------------------------------------------
1 | # DON'T BE A DICK PUBLIC LICENSE
2 |
3 | > Version 1, December 2009
4 |
5 | > Copyright (C) 2009 Philip Sturgeon
6 |
7 | Everyone is permitted to copy and distribute verbatim or modified
8 | copies of this license document, and changing it is allowed as long
9 | as the name is changed.
10 |
11 | > DON'T BE A DICK PUBLIC LICENSE
12 | > TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13 |
14 | 1. Do whatever you like with the original work, just don't be a dick.
15 |
16 | Being a dick includes - but is not limited to - the following instances:
17 |
18 | 1a. Outright copyright infringement - Don't just copy this and change the name.
19 | 1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick.
20 | 1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick.
21 |
22 | 2. If you become rich through modifications, related works/services, or supporting the original work,
23 | share the love. Only a dick would make loads off this work and not buy the original work's
24 | creator(s) a pint.
25 |
26 | 3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes
27 | you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back.
28 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/QSimpleUpdater.pro:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2014-2016 Alex Spataru
3 | #
4 | # This file is part of the QSimpleUpdater library, which is released under
5 | # the DBAD license, you can read a copy of it below:
6 | #
7 | # DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION
8 | # AND MODIFICATION:
9 | #
10 | # Do whatever you like with the original work, just don't be a dick.
11 | # Being a dick includes - but is not limited to - the following instances:
12 | #
13 | # 1a. Outright copyright infringement - Don't just copy this and change the
14 | # name.
15 | # 1b. Selling the unmodified original with no work done what-so-ever, that's
16 | # REALLY being a dick.
17 | # 1c. Modifying the original work to contain hidden harmful content.
18 | # That would make you a PROPER dick.
19 | #
20 | # If you become rich through modifications, related works/services, or
21 | # supporting the original work, share the love.
22 | # Only a dick would make loads off this work and not buy the original works
23 | # creator(s) a pint.
24 | #
25 | # Code is provided with no warranty. Using somebody else's code and bitching
26 | # when it goes wrong makes you a DONKEY dick.
27 | # Fix the problem yourself. A non-dick would submit the fix back.
28 |
29 | TEMPLATE = lib
30 | DEFINES += QSU_SHARED
31 | include ($$PWD/QSimpleUpdater.pri)
32 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/QSimpleUpdater.pri:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2014-2016 Alex Spataru
3 | #
4 | # This file is part of the QSimpleUpdater library, which is released under
5 | # the DBAD license, you can read a copy of it below:
6 | #
7 | # DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION
8 | # AND MODIFICATION:
9 | #
10 | # Do whatever you like with the original work, just don't be a dick.
11 | # Being a dick includes - but is not limited to - the following instances:
12 | #
13 | # 1a. Outright copyright infringement - Don't just copy this and change the
14 | # name.
15 | # 1b. Selling the unmodified original with no work done what-so-ever, that's
16 | # REALLY being a dick.
17 | # 1c. Modifying the original work to contain hidden harmful content.
18 | # That would make you a PROPER dick.
19 | #
20 | # If you become rich through modifications, related works/services, or
21 | # supporting the original work, share the love.
22 | # Only a dick would make loads off this work and not buy the original works
23 | # creator(s) a pint.
24 | #
25 | # Code is provided with no warranty. Using somebody else's code and bitching
26 | # when it goes wrong makes you a DONKEY dick.
27 | # Fix the problem yourself. A non-dick would submit the fix back.
28 |
29 | QT += gui
30 | QT += core
31 | QT += network
32 | QT += widgets
33 |
34 | INCLUDEPATH += $$PWD/include
35 |
36 | SOURCES += \
37 | $$PWD/src/Updater.cpp \
38 | $$PWD/src/Downloader.cpp \
39 | $$PWD/src/QSimpleUpdater.cpp
40 |
41 | HEADERS += \
42 | $$PWD/include/QSimpleUpdater.h \
43 | $$PWD/src/Updater.h \
44 | $$PWD/src/Downloader.h
45 |
46 | FORMS += $$PWD/src/Downloader.ui
47 | RESOURCES += $$PWD/etc/resources/qsimpleupdater.qrc
48 |
--------------------------------------------------------------------------------
/src/netcompression.cpp:
--------------------------------------------------------------------------------
1 | #include "netcompression.h"
2 |
3 | #include
4 | #ifdef _WIN32
5 | #include
6 | #elif __unix__
7 | #include
8 | #else
9 | #error "include header that defines sockaddr_in"
10 | #endif
11 |
12 | static_assert(sizeof(uint8_t) == 1, "uint8_t not defined as 1 byte");
13 | static_assert(sizeof(uint16_t) == 2, "uint16_t not defined as 2 bytes");
14 | static_assert(sizeof(uint32_t) == 4, "uint32_t not defined as 4 bytes");
15 |
16 | size_t NetCompression::unpackUUID(const unsigned char* src, QUuid& uuid)
17 | {
18 | // Use QT implementation of converting to NBO, its better
19 | uuid = QUuid::fromRfc4122(QByteArray::fromRawData(reinterpret_cast(&src[0]), PACKED_UUID_LENGTH));
20 | return PACKED_UUID_LENGTH;
21 | }
22 | size_t NetCompression::packUUID(unsigned char* buf, const QUuid& uuid)
23 | {
24 | // Use QT implementation of converting from NBO, its better
25 | // because it will return a null uuid if it fails
26 | memcpy(&buf[0], uuid.toRfc4122().constData(), PACKED_UUID_LENGTH);
27 | return PACKED_UUID_LENGTH;
28 | }
29 |
30 | size_t NetCompression::packSockaddr_in(unsigned char* buf, const sockaddr_in& addr)
31 | {
32 | size_t index = 0;
33 | memcpy(&buf[index], &(addr.sin_addr.s_addr), sizeof(uint32_t));
34 | index += sizeof(uint32_t);
35 | memcpy(&buf[index], &(addr.sin_port), sizeof(uint16_t));
36 | index += sizeof(uint16_t);
37 | return index;
38 | }
39 |
40 | size_t NetCompression::unpackSockaddr_in(const unsigned char* buf, sockaddr_in& addr)
41 | {
42 | size_t index = 0;
43 | memcpy(&(addr.sin_addr.s_addr), &buf[index], sizeof(uint32_t));
44 | index += sizeof(uint32_t);
45 | memcpy(&(addr.sin_port), &buf[index], sizeof(uint16_t));
46 | index += sizeof(uint16_t);
47 |
48 | return index;
49 | }
50 |
--------------------------------------------------------------------------------
/include/pxminireader.h:
--------------------------------------------------------------------------------
1 | /** @file pxminireader.h
2 | * @brief Public header for pxminireader.cpp
3 | *
4 | * pxminireader reads our ini for initial values. I bet you couldn't have
5 | * guessed that. The .ini should be located under ~/.config/PXMessenger on
6 | * unix, c:/User/[username]/AppData/Roaming/PXMessenger on windows.
7 | */
8 |
9 | #ifndef MESSINIREADER_H
10 | #define MESSINIREADER_H
11 |
12 | #include "pxmconsts.h"
13 |
14 | #include
15 |
16 | class QSettings;
17 | class QString;
18 | class QSize;
19 | class PXMIniReader {
20 | QScopedPointer iniFile;
21 |
22 | public:
23 | PXMIniReader();
24 | ~PXMIniReader();
25 | bool checkAllowMoreThanOne();
26 | unsigned int getUUIDNumber() const;
27 | QUuid getUUID(unsigned int num, bool takeIt) const;
28 | int resetUUID(unsigned int num, QUuid uuid);
29 | unsigned short getPort(QString protocol);
30 | QString getHostname(QString defaultHostname);
31 | void setHostname(QString hostname);
32 | void setPort(QString protocol, int portNumber);
33 | void setWindowSize(QSize windowSize);
34 | QSize getWindowSize(QSize defaultSize) const;
35 | void setMute(bool mute);
36 | bool getMute() const;
37 | void setFocus(bool focus);
38 | bool getFocus() const;
39 | QString getFont();
40 | void setFont(QString font);
41 | int getFontSize() const;
42 | void setFontSize(int size);
43 | void setAllowMoreThanOne(bool value);
44 | int setMulticastAddress(QString ip);
45 | QString getMulticastAddress() const;
46 | int getVerbosity() const;
47 | void setVerbosity(int level) const;
48 | bool getLogActive() const;
49 | void setLogActive(bool status) const;
50 | bool getDarkColorScheme() const;
51 | void setDarkColorScheme(bool status) const;
52 | bool getUpdates() const;
53 | void setUpdates(bool status) const;
54 | };
55 |
56 | #endif // MESSINIREADER_H
57 |
--------------------------------------------------------------------------------
/include/netcompression.h:
--------------------------------------------------------------------------------
1 | #ifndef NETCOMPRESSION_H
2 | #define NETCOMPRESSION_H
3 |
4 | #include
5 |
6 | #ifdef __WIN32
7 | #include
8 | #elif __unix__
9 | #include
10 | #else
11 | #error "include header for sockaddr_in"
12 | #endif
13 |
14 | class QUuid;
15 | namespace NetCompression
16 | {
17 | const size_t PACKED_UUID_LENGTH = 16;
18 | /*!
19 | * \brief packUUID
20 | * Compresses and packs a UUID by converting it into Network Byte Order.
21 | * \param buf supplied buffer to pack into
22 | * \param uuid uuid to compress
23 | * \return the size of the packed UUID that was added to buf
24 | */
25 | size_t packUUID(unsigned char* buf, const QUuid& uuid);
26 | /*!
27 | * \brief unpackUUID
28 | * Convert a UUID that was in Network Byte Order back to normal format
29 | * \param src a buffer where a packed UUID is stored
30 | * \param uuid a supplied UUID to store the unpacked UUID to
31 | * \return the size of the unpacked UUID that was read from src
32 | */
33 | size_t unpackUUID(const unsigned char* src, QUuid &uuid);
34 |
35 | const size_t PACKED_SOCKADDR_IN_LENGTH = 6;
36 | /*!
37 | * \brief packSockaddr_in
38 | * Pack a sockaddr_in structure into a supplied buffer. Only the in_addr_t and
39 | * in_port_t are packed. IPv4 only!
40 | * \param buf supplied buffer to store data to
41 | * \param addr sockaddr_in to pack
42 | * \return the size of the packed sockaddr_in that was stored in buf
43 | */
44 | size_t packSockaddr_in(unsigned char* buf, const sockaddr_in &addr);
45 | /*!
46 | * \brief unpackSockaddr_in
47 | * Unpacks a sockaddr_in structure that was packed using packSockaddr_in. IPv4
48 | * only!
49 | * \param buf supplied buffer which contains the packed sockaddr_in
50 | * \param addr a supplied sockaddr_in structure to store the result to
51 | * \return the size of the unpacked sockaddr_in that was unpacked from buf
52 | */
53 | size_t unpackSockaddr_in(const unsigned char* buf, sockaddr_in &addr);
54 | }
55 |
56 | #endif // NETCOMPRESSION_H
57 |
--------------------------------------------------------------------------------
/include/pxmsettingsdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef DIALOG_20__2D__20_UNTITLEDXQ7926_H
2 | #define DIALOG_20__2D__20_UNTITLEDXQ7926_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include "pxminireader.h"
22 | #include "pxmdefinitions.h"
23 | #include "pxmconsolewindow.h"
24 |
25 | #ifdef _WIN32
26 | #include
27 | #else
28 | #include
29 | #include
30 | #include
31 | #endif
32 |
33 | class PXMSettingsDialog : public QDialog
34 | {
35 | Q_OBJECT
36 |
37 | bool AllowMoreThanOneInstance;
38 | QString hostname;
39 | int tcpPort;
40 | int udpPort;
41 | QFont iniFont;
42 | int fontSize;
43 |
44 | QGridLayout *gridLayout;
45 | QSpacerItem *verticalSpacer;
46 | QCheckBox *checkBox;
47 | QLabel *label_2;
48 | QLineEdit *lineEdit;
49 | QLabel *label;
50 | QLabel *label_3;
51 | QLabel *label_4;
52 | QLabel *label_5;
53 | QLabel *label_6;
54 | QLabel *label_7;
55 | QDialogButtonBox *buttonBox;
56 | QSpinBox *spinBox;
57 | QSpinBox *spinBox_2;
58 | QFontComboBox *fontComboBox;
59 | QSpinBox *spinBox_3;
60 | QSpinBox *spinBox_4;
61 | private slots:
62 | void clickedme(QAbstractButton *button);
63 | void accept();
64 | void currentFontChanged(QFont font);
65 | void valueChanged(int size);
66 |
67 | public:
68 | explicit PXMSettingsDialog(QWidget* parent);
69 |
70 | void setupUi();
71 | void retranslateUi();
72 | void readIni();
73 | signals:
74 | void nameChange(QString);
75 | };
76 |
77 | #endif
78 |
--------------------------------------------------------------------------------
/include/pxmconsts.h:
--------------------------------------------------------------------------------
1 | /** @file pxmconsts.h
2 | * @brief various constants used throughout pxmessenger
3 | */
4 |
5 | #ifndef PXMCONSTS_H
6 | #define PXMCONSTS_H
7 |
8 | #include "netcompression.h"
9 |
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | static_assert(sizeof(uint32_t) == 4, "uint32_t not defined as 4 bytes");
17 |
18 | namespace PXMConsts
19 | {
20 | const char DEFAULT_MULTICAST_ADDRESS[] = "239.192.13.13";
21 | const int MESSAGE_HISTORY_LENGTH = 500;
22 | #ifdef QT_DEBUG
23 | const size_t DEBUG_PADDING = 23;
24 | #else
25 | const size_t DEBUG_PADDING = 0;
26 | #endif
27 | const unsigned short DEFAULT_UDP_PORT = 53273;
28 | const int TEXT_EDIT_MAX_LENGTH = 2000;
29 | const size_t MAX_HOSTNAME_LENGTH = 24;
30 | const size_t MAX_COMPUTER_NAME_LENGTH = 36;
31 | const char AUTH_SEPERATOR[] = ":::";
32 | enum MESSAGE_TYPE : const uint32_t {
33 | MSG_TEXT = 0x11111111,
34 | MSG_GLOBAL = 0x22222222,
35 | MSG_SYNC = 0x33333333,
36 | MSG_SYNC_REQUEST = 0x44444444,
37 | MSG_AUTH = 0x55555555,
38 | MSG_NAME = 0x66666666,
39 | MSG_DISOVER = 0x77777777,
40 | MSG_ID = 0x88888888,
41 | MSG_TYPING = 0x99999999,
42 | MSG_TEXTENTERED = 0x21132398,
43 | MSG_ENDTEXTENTERED = 0x29932398
44 | };
45 | //This works around a compiler warning in pxmserver when building a reply
46 | //message for udp discover packets. See updReceive in pxmserver.cpp
47 | constexpr size_t ct_strlen(const char* s) noexcept
48 | {
49 | return *s ? 1 + ct_strlen(s + 1) : 0;
50 | }
51 | const size_t MAX_AUTH_PACKET_LEN =
52 | sizeof(MESSAGE_TYPE) +
53 | NetCompression::PACKED_UUID_LENGTH +
54 | MAX_HOSTNAME_LENGTH +
55 | MAX_COMPUTER_NAME_LENGTH +
56 | strlen(AUTH_SEPERATOR) +
57 | 5 /*port number*/ +
58 | strlen(AUTH_SEPERATOR) +
59 | strlen("001.001.001") +
60 | 1 /*null*/;
61 | }
62 | Q_DECLARE_METATYPE(PXMConsts::MESSAGE_TYPE)
63 |
64 | #endif // PXMCONSTS_H
65 |
--------------------------------------------------------------------------------
/include/pxmclient.h:
--------------------------------------------------------------------------------
1 | /** @file pxmclient.h
2 | * @brief Public header for pxmclient.cpp
3 | *
4 | * Primary class used to send messages over the network
5 | */
6 |
7 | #ifndef PXMCLIENT_H
8 | #define PXMCLIENT_H
9 |
10 | #include "pxmconsts.h"
11 | #include
12 | #include
13 |
14 | #include
15 |
16 | struct bufferevent;
17 | namespace Peers
18 | {
19 | class BevWrapper;
20 | }
21 |
22 | struct PXMClientPrivate;
23 | class PXMClient : public QObject
24 | {
25 | Q_OBJECT
26 | QScopedPointer d_ptr;
27 |
28 | public:
29 | PXMClient(QObject* parent, in_addr multicast, QUuid localUUID);
30 | ~PXMClient();
31 | /** Sets the uuid for use in comms
32 | * @brief setLocalUUID
33 | * @param uuid QUuid to set
34 | */
35 | void setLocalUUID(QUuid uuid);
36 | public slots:
37 | /*!
38 | * \brief sendMsgSlot
39 | * Function for sending data to already connected peers.
40 | * \param bw pointer containing a Bevwrapper, which contains a bufferevent
41 | * \param msg bytes to send, does not need to be null terminated
42 | * \param len length of bytes to send
43 | * \param type type of message to send in header
44 | * \param theiruuid recipients uuid, only used when confirming message was
45 | * sent
46 | */
47 | void sendMsgSlot(QSharedPointer bw,
48 | QByteArray msg,
49 | size_t len,
50 | PXMConsts::MESSAGE_TYPE type,
51 | QUuid theiruuid = QUuid());
52 | /*!
53 | * \brief sendUDP
54 | * Sends a UDP packet to the multicast group
55 | * \param msg message to send, must be null-terminated
56 | * \param port port on the multicast to send to
57 | * \return 0 on success, -1 on error
58 | */
59 | int sendUDP(const char* msg, unsigned short port);
60 | void sendSingleType(QSharedPointer bw, PXMConsts::MESSAGE_TYPE type);
61 | signals:
62 | /*!
63 | * \brief resultOfTCPSend
64 | * This returns the result of the sendMsgSlot, with information about how
65 | * successful it was contained in the first integer.
66 | */
67 | void resultOfTCPSend(int, QUuid, QUuid, QString, bool, QSharedPointer);
68 | };
69 |
70 | #endif // PXMCLIENT_H
71 |
--------------------------------------------------------------------------------
/include/pxmpeerworker.h:
--------------------------------------------------------------------------------
1 | /** @file pxmpeerworker.h
2 | * @brief public header for pxmpeerworker.cpp
3 | *
4 | * This is the manager for pxmserver and pxmclient. Meant to be used in it own
5 | * thread but will spawn another thread for the server to work from.
6 | */
7 |
8 | #ifndef PXMPEERWORKER_H
9 | #define PXMPEERWORKER_H
10 |
11 | #include
12 | #include
13 |
14 | #include
15 |
16 | #include "pxmpeers.h"
17 | #include "pxmconsts.h"
18 |
19 | class PXMPeerWorkerPrivate;
20 |
21 | class PXMPeerWorker : public QObject
22 | {
23 | Q_OBJECT
24 |
25 | friend class PXMPeerWorkerPrivate;
26 | const QScopedPointer d_ptr;
27 | public:
28 | explicit PXMPeerWorker(QObject* parent,
29 | QString username,
30 | QUuid selfUUID,
31 | QString multicast,
32 | unsigned short tcpPort,
33 | unsigned short udpPort,
34 | QUuid globaluuid);
35 | ~PXMPeerWorker();
36 | PXMPeerWorker(PXMPeerWorker const&) = delete;
37 | PXMPeerWorker& operator=(PXMPeerWorker const&) = delete;
38 | PXMPeerWorker& operator=(PXMPeerWorker&&) noexcept = delete;
39 | PXMPeerWorker(PXMPeerWorker&&) noexcept = delete;
40 | public slots:
41 | int addMessageToPeer(QString str, QUuid ruuid, QUuid suuid, bool alert, bool fromServer);
42 |
43 | void sendMsgAccessor(QByteArray msg, PXMConsts::MESSAGE_TYPE type,
44 | QUuid uuid = QUuid());
45 | void sendUDPAccessor(const char* msg);
46 |
47 | //void setupTimers();
48 | void printInfoToDebug();
49 | void beginPeerSync();
50 | void typing(QUuid uuid);
51 | void textEntered(QUuid uuid);
52 | void endOfTextEntered(QUuid uuid);
53 | // void restartServer();
54 | signals:
55 | void msgRecieved(QSharedPointer, QString, QUuid, QUuid, bool, bool, bool);
56 | void newAuthedPeer(QUuid, QString);
57 | void sendMsg(QSharedPointer, QByteArray, size_t,
58 | PXMConsts::MESSAGE_TYPE, QUuid = QUuid());
59 | void sendUDP(const char*, unsigned short);
60 | void sendSingleType(QSharedPointer, PXMConsts::MESSAGE_TYPE);
61 | void connectionStatusChange(QUuid, bool);
62 | void ipsReceivedFrom(QUuid);
63 | void warnBox(QString, QString);
64 | void typingAlert(QUuid);
65 | void textEnteredAlert(QUuid);
66 | void endOfTextEnteredAlert(QUuid);
67 |
68 | };
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/include/pxmconsole.h:
--------------------------------------------------------------------------------
1 | /** @file pxmconsole.h
2 | * @brief Public header for pxmconsole.cpp
3 | *
4 | * PXMConsole is what handles all logging in PXMessenger as well as drive the
5 | * debug console available through the menu bar. It needs to be used in the
6 | * main gui thread as it updates a textbox by default.
7 | */
8 |
9 | #ifndef PXMCONSOLE_H
10 | #define PXMCONSOLE_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | class QPushButton;
20 | namespace PXMConsole
21 | {
22 | const int HISTORY_LIMIT = 2000;
23 | static QFile file;
24 | struct WindowPrivate;
25 | class Window : public QMainWindow
26 | {
27 | Q_OBJECT
28 | QScopedPointer d_ptr;
29 |
30 | public:
31 | explicit Window(QWidget* parent = 0);
32 | ~Window();
33 | QPushButton* pushButton;
34 | QPushButton* pushButton1;
35 | static QTextEdit* textEdit;
36 | public slots:
37 | void verbosityChanged();
38 | private slots:
39 | void adjustScrollBar(int i);
40 | void rangeChanged(int, int i2);
41 | };
42 |
43 | class AppendTextEvent : public QEvent
44 | {
45 | public:
46 | AppendTextEvent(QString text, QColor color) : QEvent(static_cast(type)), text(text), textColor(color) {}
47 | QString getText() { return text; }
48 | QColor getColor() { return textColor; }
49 | private:
50 | static int type;
51 | QString text;
52 | QColor textColor;
53 | };
54 |
55 | class Logger : public QObject
56 | {
57 | public:
58 | static Logger* getInstance()
59 | {
60 | if (!loggerInstance) {
61 | loggerInstance = new Logger;
62 | #ifdef __WIN32
63 | loggerInstance->logFile.reset(new QFile(QDir::currentPath() + "/log.txt", loggerInstance));
64 | #else
65 | loggerInstance->logFile.reset(new QFile(QDir::homePath() + "/.pxmessenger-log", loggerInstance));
66 | #endif
67 | }
68 |
69 | return loggerInstance;
70 | }
71 | void setTextEdit(QTextEdit* textEdit) { logTextEdit = textEdit; }
72 | int getVerbosityLevel() { return verbosityLevel; }
73 | void setVerbosityLevel(int value) { verbosityLevel = value; }
74 | bool getLogStatus() { return logActive; }
75 | void setLogStatus(bool stat);
76 | QScopedPointer logFile;
77 |
78 | private:
79 | Logger() : QObject() {}
80 | static Logger* loggerInstance;
81 | QTextEdit* logTextEdit = 0;
82 | int verbosityLevel = 0;
83 | bool logActive = 0;
84 |
85 | protected:
86 | virtual void customEvent(QEvent* event);
87 | };
88 | }
89 |
90 | #endif // PXMCONSOLE_H
91 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/src/Downloader.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2016 Alex Spataru
3 | *
4 | * This file is part of the QSimpleUpdater library, which is released under
5 | * the DBAD license, you can read a copy of it below:
6 | *
7 | * DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
8 | * DISTRIBUTION AND MODIFICATION:
9 | *
10 | * Do whatever you like with the original work, just don't be a dick.
11 | * Being a dick includes - but is not limited to - the following instances:
12 | *
13 | * 1a. Outright copyright infringement - Don't just copy this and change the
14 | * name.
15 | * 1b. Selling the unmodified original with no work done what-so-ever, that's
16 | * REALLY being a dick.
17 | * 1c. Modifying the original work to contain hidden harmful content.
18 | * That would make you a PROPER dick.
19 | *
20 | * If you become rich through modifications, related works/services, or
21 | * supporting the original work, share the love.
22 | * Only a dick would make loads off this work and not buy the original works
23 | * creator(s) a pint.
24 | *
25 | * Code is provided with no warranty. Using somebody else's code and bitching
26 | * when it goes wrong makes you a DONKEY dick.
27 | * Fix the problem yourself. A non-dick would submit the fix back.
28 | */
29 |
30 | #ifndef DOWNLOAD_DIALOG_H
31 | #define DOWNLOAD_DIALOG_H
32 |
33 | #include
34 | #include
35 |
36 | namespace Ui {
37 | class Downloader;
38 | }
39 |
40 | class QNetworkReply;
41 | class QNetworkAccessManager;
42 |
43 | /**
44 | * \brief Implements an integrated file downloader with a nice UI
45 | */
46 | class Downloader : public QWidget
47 | {
48 | Q_OBJECT
49 |
50 | signals:
51 | void downloadFinished (const QString& url, const QString& filepath);
52 | void installerOpened();
53 | void downloadCanceled();
54 |
55 | public:
56 | explicit Downloader (QWidget* parent = 0);
57 | ~Downloader();
58 |
59 | bool useCustomInstallProcedures() const;
60 |
61 | public slots:
62 | void setUrlId (const QString& url);
63 | void startDownload (const QUrl& url);
64 | void setFileName (const QString& file);
65 | void setUseCustomInstallProcedures (const bool custom);
66 |
67 | private slots:
68 | void openDownload();
69 | void installUpdate();
70 | void cancelDownload();
71 | void saveFile (qint64 received, qint64 total);
72 | void calculateSizes (qint64 received, qint64 total);
73 | void updateProgress (qint64 received, qint64 total);
74 | void calculateTimeRemaining (qint64 received, qint64 total);
75 |
76 | private:
77 | qreal round (const qreal& input);
78 |
79 | private:
80 | QString m_url;
81 | uint m_startTime;
82 | QString m_fileName;
83 | Ui::Downloader* m_ui;
84 | QNetworkReply* m_reply;
85 | bool m_useCustomProcedures;
86 | QNetworkAccessManager* m_manager;
87 | };
88 |
89 | #endif
90 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | P2P cross platform home or small office instant messenger. Written in C++ with Qt.
5 |
6 |
7 |
8 |
9 | #### Status
10 |
11 | [](https://travis-ci.org/cbpeckles/PXMessenger)
12 |
13 | #### Dependencies:
14 |
15 | qt5 >= qt5.5.0
16 |
17 | qtmultimedia
18 |
19 | gcc > 4.9.0 or clang > 3.5.0
20 |
21 | libevent >= 2.0.22
22 |
23 |
24 | #### BUILD INSTRUCTIONS
25 |
26 | git clone
27 |
28 | cd ./PXMessenger
29 |
30 | qmake
31 |
32 | make
33 |
34 | sudo make install (optional; installs a desktop entry as well)
35 |
36 | ./build-*/PXMessenger
37 |
38 | If compiling on Windows, the .pro file will have to be edited to point to your
39 | installation of libevent. Specifically the lines
40 |
41 | ```
42 | win32 {
43 | LIBS += -L$$PWD/../libevent/build/lib -levent -levent_core
44 | INCLUDEPATH += $$PWD/../libevent/include \
45 | $$PWD/../libevent/build/include
46 | }
47 | ```
48 |
49 | #### USAGE
50 |
51 | PXMessenger is a cross platform instant messaging client that does not need a
52 | central server. It will automatically discover other users of the client
53 | through the use of a multicast group. All running clients have a UUID
54 | associated with them for verification purposes and history. The UUID's are
55 | saved in an .ini file in the users home directory (See QSettings in the Qt5 docs
56 | for more details). This program can be run multiple times on the same computer
57 | and login. The Global send item will send the message to all known peers. It
58 | is essentially a global chat room.
59 |
60 | ##### Settings
61 |
62 | The multicast group that PXMessenger uses is 239.192.13.13. This can be changed
63 | in the settings window.
64 |
65 | Adjustments can be made to the ports that are used for PXMessenger if firewall
66 | rules only allow specific ones. By default, PXMessenger allows the operating
67 | system to choose the TCP port. The UDP port defaults to 53723. The UDP port
68 | must be the same for all connected computers however the TCP port can be
69 | whichever you prefer for each.
70 |
71 | The "Bloom" setting should not be needed under normal circumstances and only
72 | resends the discovery packed to the multicast group. This is useful if you
73 | believe that an exisiting group of computers have missed all discovery packets.
74 | (very rare)
75 |
76 | PXMessenger will minimize to a tray if the system supports one and will alert
77 | itself in the event of receiving a message.
78 |
79 | ##### Notes
80 |
81 | Bugs are possible, please report them here under the issues tab and they will be
82 | responded to.
83 |
84 | Windows executable and setup included in the releases section
85 |
86 | While this should theoretically work under Mac OSX, it has never been
87 | tested as I do not have access to a Mac.
88 |
89 | Artwork created by Scott Bolar.
90 |
91 | QSimpleUpdater credit to https://github.com/alex-spataru
92 |
--------------------------------------------------------------------------------
/include/pxmpeers.h:
--------------------------------------------------------------------------------
1 | /** @file pxmpeers.h
2 | * @brief public header for pxmpeers.cpp
3 | *
4 | * Defines multiple structures and classes used for storing other connected
5 | * computers information such as hostname, connection information, etc.
6 | *
7 | * Bevwrapper is a mutex wrapped bufferevent
8 | * PeerData is everything else we know about them
9 | */
10 |
11 | #ifndef PXMPEERS_H
12 | #define PXMPEERS_H
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | struct bufferevent;
23 |
24 | Q_DECLARE_METATYPE(struct sockaddr_in)
25 | Q_DECLARE_METATYPE(size_t)
26 | Q_DECLARE_OPAQUE_POINTER(bufferevent*)
27 | Q_DECLARE_METATYPE(bufferevent*)
28 | Q_DECLARE_OPAQUE_POINTER(const bufferevent*)
29 | Q_DECLARE_METATYPE(const bufferevent*)
30 |
31 | class QMutex;
32 | namespace Peers {
33 | /*
34 | const QString selfColor = "#6495ED"; // Cornflower Blue
35 | const QString peerColor = "#FF0000"; // Red
36 | const QVector textColors = {
37 | "#808000", // Olive
38 | "#FFA500", // Orange
39 | "#FF00FF", // Fuschia
40 | "#DC143C", // Crimson
41 | "#FF69B4", // HotPink
42 | "#708090", // SlateGrey
43 | "#008000", // Green
44 | "#00FF00" // Lime
45 | };
46 | extern int textColorsNext;
47 | */
48 | class BevWrapper {
49 | bufferevent* bev;
50 | QMutex* locker;
51 |
52 | public:
53 | // Default Constructor
54 | BevWrapper();
55 | // Constructor with a bufferevent
56 | BevWrapper(bufferevent* buf);
57 | // Destructor
58 | ~BevWrapper();
59 | // Copy Constructor
60 | BevWrapper(const BevWrapper& b) : bev(b.bev), locker(b.locker) {}
61 | // Move Constructor
62 | BevWrapper(BevWrapper&& b) noexcept;
63 | // Move Assignment
64 | BevWrapper& operator=(BevWrapper&& b) noexcept;
65 | // Eqaul
66 | bool operator==(const BevWrapper& b) { return bev == b.bev; }
67 | // Not Equal
68 | bool operator!=(const BevWrapper& b) { return !(bev == b.bev); }
69 |
70 | void setBev(bufferevent* buf) { bev = buf; }
71 | bufferevent* getBev() const { return bev; }
72 | void lockBev();
73 | void unlockBev();
74 | int freeBev();
75 | };
76 |
77 | class PeerData {
78 | public:
79 | QUuid uuid;
80 | struct sockaddr_in addrRaw;
81 | QString hostname;
82 | //QString textColor;
83 | QString progVersion;
84 | QSharedPointer bw;
85 | evutil_socket_t socket;
86 | qint64 timeOfTyping;
87 | bool connectTo;
88 | bool isAuthed;
89 |
90 | // Default Constructor
91 | PeerData();
92 |
93 | // Copy
94 | PeerData(const PeerData& pd);
95 |
96 | // Move
97 | PeerData(PeerData&& pd) noexcept;
98 |
99 | // Destructor
100 | ~PeerData() noexcept {}
101 |
102 | // Move assignment
103 | PeerData& operator=(PeerData&& pd) noexcept;
104 |
105 | // Copy assignment
106 | PeerData& operator=(const PeerData& pd);
107 |
108 | // Return data of this struct as a string padded with the value in 'pad'
109 | QString toInfoString();
110 | };
111 | }
112 | Q_DECLARE_METATYPE(QSharedPointer)
113 |
114 | #endif
115 |
--------------------------------------------------------------------------------
/include/timedvector.h:
--------------------------------------------------------------------------------
1 | #ifndef TIMEDVECTOR_H
2 | #define TIMEDVECTOR_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | template
11 | class TimedVector
12 | {
13 | struct TimedStruct {
14 | T* t;
15 | qint64 epoch;
16 |
17 | TimedStruct() : t(new T()), epoch(QDateTime::currentMSecsSinceEpoch()) {}
18 | TimedStruct(T t1) : t(new T(t1)), epoch(QDateTime::currentMSecsSinceEpoch()) {}
19 | ~TimedStruct() noexcept { delete t; }
20 | TimedStruct(TimedStruct&& v) noexcept : t(v.t), epoch(v.epoch) { v.t = nullptr; }
21 | TimedStruct(const TimedStruct& v) : t(new T(*(v.t))), epoch(v.epoch) {}
22 | TimedStruct& operator=(const TimedStruct& v)
23 | {
24 | TimedStruct tmp(v);
25 | *this = std::move(tmp);
26 | return *this;
27 | }
28 |
29 | TimedStruct& operator=(TimedStruct&& v) noexcept
30 | {
31 | delete t;
32 | t = v.t;
33 | v.t = nullptr;
34 | epoch = v.epoch;
35 | return *this;
36 | }
37 |
38 | inline bool operator==(TimedStruct v) { return (*v.t == *t && v.epoch == epoch); }
39 | };
40 | QVector rawVector;
41 | unsigned int ItemLifeMsecs;
42 |
43 | public:
44 | TimedVector(unsigned int itemLife) : ItemLifeMsecs(itemLife) {}
45 | ~TimedVector() {}
46 | TimedVector(const TimedVector& tv) : ItemLifeMsecs(tv.ItemLifeMsecs)
47 | {
48 | for (TimedStruct itr : tv.rawVector) {
49 | rawVector.append(TimedStruct(itr));
50 | }
51 | }
52 |
53 | // TimedVector(TimedVector&& tv) noexcept {}
54 |
55 | inline void append(const T t) { rawVector.append(TimedStruct(t)); }
56 | bool contains(T t)
57 | {
58 | if (rawVector.isEmpty())
59 | return false;
60 |
61 | for (TimedStruct &itr : rawVector) {
62 | if (*(itr.t) == t) {
63 | if (itr.epoch + ItemLifeMsecs > QDateTime::currentMSecsSinceEpoch())
64 | return true;
65 | else {
66 | rawVector.takeAt(rawVector.indexOf(itr));
67 | return false;
68 | }
69 | }
70 | }
71 | return false;
72 | }
73 |
74 | int length()
75 | {
76 | pruneItems();
77 | return rawVector.length();
78 | }
79 |
80 | int pruneItems()
81 | {
82 | int count = 0;
83 | for (TimedVector::TimedStruct itr : rawVector) {
84 | if (itr.epoch + ItemLifeMsecs < QDateTime::currentMSecsSinceEpoch()) {
85 | int index = rawVector.indexOf(itr);
86 | rawVector.takeAt(index);
87 | count++;
88 | }
89 | }
90 | return count;
91 | }
92 |
93 | int remove(T t)
94 | {
95 | for (TimedVector::TimedStruct itr : rawVector) {
96 | if (*(itr.t) == t) {
97 | rawVector.takeAt(rawVector.indexOf(itr));
98 | return 0;
99 | }
100 | }
101 | return -1;
102 | }
103 | };
104 | #endif // TIMEDVECTOR_H
105 |
--------------------------------------------------------------------------------
/PXMessenger.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | TARGET = PXMessenger
3 | VERSION = 1.6.0
4 | QMAKE_TARGET_COMPANY = Bolar Code Solutions
5 | QMAKE_TARGET_PRODUCT = PXMessenger
6 | QMAKE_TARGET_DESCRIPTION = Instant Messenger
7 | QMAKE_TARGET_COPYRIGHT = GPLv3
8 |
9 | target.path = /usr/local/bin
10 | desktop.path = /usr/share/applications
11 | desktop.files += $$PWD/resources/pxmessenger.desktop
12 | icon.path = /usr/share/pixmaps
13 | icon.files += $$PWD/resources/PXMessenger.png
14 | INSTALLS += target desktop icon
15 |
16 | QT = core gui widgets multimedia
17 | CONFIG += DEBUG \
18 | RELEASE
19 | win32: CONFIG += windows
20 |
21 | unix: LIBS += -levent -levent_pthreads
22 |
23 | win32 {
24 | LIBS += -L$$PWD/../libevent/build/lib -levent -levent_core
25 | INCLUDEPATH += $$PWD/../libevent/include \
26 | $$PWD/../libevent/build/include
27 | }
28 |
29 | INCLUDEPATH += $$PWD/include
30 |
31 | win32 {
32 | LIBS += -lws2_32
33 | RC_ICONS = $$PWD/resources/PXM_Icon.ico
34 | }
35 |
36 | win32 {
37 | contains(QMAKE_HOST.arch, x86_64):{
38 | TARGET =$$TARGET-x86_64
39 | BUILDDIR = build-win64
40 | }
41 | contains(QMAKE_HOST.arch, x86):{
42 | TARGET =$$TARGET-x86
43 | BUILDDIR = build-win32
44 | }
45 | }
46 |
47 | QMAKE_CXXFLAGS += -Wall \
48 | -std=c++14
49 |
50 | SOURCES += \
51 | $$PWD/src/pxmclient.cpp \
52 | $$PWD/src/pxmpeerworker.cpp \
53 | $$PWD/src/pxmsync.cpp \
54 | $$PWD/src/pxminireader.cpp \
55 | $$PWD/src/pxmserver.cpp \
56 | $$PWD/src/pxmmainwindow.cpp \
57 | $$PWD/src/pxmessenger.cpp \
58 | $$PWD/src/netcompression.cpp \
59 | $$PWD/src/pxmstackwidget.cpp \
60 | $$PWD/src/pxmconsole.cpp \
61 | $$PWD/src/pxmpeers.cpp \
62 | $$PWD/src/pxmagent.cpp
63 |
64 | HEADERS += \
65 | $$PWD/include/pxmpeerworker.h \
66 | $$PWD/include/pxmmainwindow.h \
67 | $$PWD/include/pxmsync.h \
68 | $$PWD/include/pxminireader.h \
69 | $$PWD/include/pxmserver.h \
70 | $$PWD/include/pxmclient.h \
71 | $$PWD/include/netcompression.h \
72 | $$PWD/include/timedvector.h \
73 | $$PWD/include/pxmstackwidget.h \
74 | $$PWD/include/pxmconsole.h \
75 | $$PWD/include/pxmconsts.h \
76 | $$PWD/include/pxmpeers.h \
77 | $$PWD/include/pxmagent.h
78 |
79 | FORMS += \
80 | $$PWD/ui/pxmmainwindow.ui \
81 | $$PWD/ui/pxmaboutdialog.ui \
82 | $$PWD/ui/pxmsettingsdialog.ui \
83 | ui/manualconnect.ui
84 |
85 | DISTFILES += \
86 | resources/updates.json
87 |
88 | RESOURCES += $$PWD/resources/resources.qrc
89 |
90 | win32 {
91 | release:DESTDIR = $$PWD/$$BUILDDIR/
92 | debug:DESTDIR = $$PWD/$$BUILDDIR/
93 | OBJECTS_DIR = $$PWD/$$BUILDDIR/obj
94 | MOC_DIR = $$PWD/$$BUILDDIR/moc
95 | RCC_DIR = $$PWD/$$BUILDDIR/rcc
96 | UI_DIR = $$PWD/$$BUILDDIR/ui
97 | QMAKE_CLEAN += $$PWD/object_script.* \
98 | $$PWD/PXMessenger_resource.rc
99 | }
100 | unix {
101 | release:DESTDIR = $$PWD/
102 | debug:DESTDIR = $$PWD/
103 | OBJECTS_DIR = $$PWD/build-unix/obj
104 | MOC_DIR = $$PWD/build-unix/moc
105 | RCC_DIR = $$PWD/build-unix/rcc
106 | UI_DIR = $$PWD/build-unix/ui
107 | }
108 |
109 | INCLUDEPATH += MOC_DIR
110 |
111 | win32 {
112 | include($$PWD/include/QSimpleUpdater/QSimpleUpdater.pri)
113 | }
114 | #QMAKE_CXXFLAGS+="-fsanitize=undefined -fno-omit-frame-pointer"
115 | #QMAKE_CFLAGS+="-fsanitize=address -fno-omit-frame-pointer"
116 | #QMAKE_LFLAGS+="-fsanitize=undefined"
117 |
--------------------------------------------------------------------------------
/ui/manualconnect.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ManualConnect
4 |
5 |
6 |
7 | 0
8 | 0
9 | 399
10 | 188
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
23 |
24 |
25 |
26 | -
27 |
28 |
29 | Manually connect to address
30 |
31 |
32 | Qt::AlignCenter
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Ip Address
40 |
41 |
42 |
43 | -
44 |
45 |
46 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
47 |
48 |
49 | 65535
50 |
51 |
52 |
53 | -
54 |
55 |
56 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
57 |
58 |
59 |
60 | -
61 |
62 |
63 | Listener Port
64 |
65 |
66 |
67 | -
68 |
69 |
70 | Qt::Horizontal
71 |
72 |
73 | QSizePolicy::Preferred
74 |
75 |
76 |
77 | 30
78 | 20
79 |
80 |
81 |
82 |
83 | -
84 |
85 |
86 | Qt::Horizontal
87 |
88 |
89 | QSizePolicy::Preferred
90 |
91 |
92 |
93 | 100
94 | 20
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/include/pxmstackwidget.h:
--------------------------------------------------------------------------------
1 | #ifndef PXMSTACKWIDGET_H
2 | #define PXMSTACKWIDGET_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | namespace PXMMessageViewer {
16 |
17 | const QString infoTyping = " is typing...";
18 | const QString infoEntered = " has entered text.";
19 | const int typeTimerInterval = 1500;
20 | const QString infoBarStyle = "QLineEdit { background-color : rgb(255,255,160); color : black; }";
21 | class History {
22 | QUuid identifier;
23 | QString text;
24 | public:
25 | History() : identifier(QUuid()), text(QString()) {}
26 | History(QUuid id, QString text = QString()) : identifier(id), text(text) {}
27 | QString getText() const {return text;}
28 | QUuid getUuid() const {return identifier;}
29 | void append(const QString& str);
30 | };
31 |
32 | // subclass this to allow the stackwidget to search for it by uuid
33 | class MVBase {
34 | QUuid identifier;
35 |
36 | public:
37 | explicit MVBase(const QUuid& uuid) : identifier(uuid) {}
38 | QUuid getIdentifier() const { return identifier; }
39 | };
40 | class LabelWidget : public QLabel, public MVBase {
41 | Q_OBJECT
42 | public:
43 | explicit LabelWidget(QWidget* parent, const QUuid& uuid);
44 | };
45 |
46 | class TextWidget : public QTextBrowser, public MVBase {
47 | Q_OBJECT
48 | bool typing;
49 | void resizeEvent(QResizeEvent *event)
50 | {
51 | rlabel();
52 | QTextBrowser::resizeEvent(event);
53 | }
54 |
55 | void rlabel();
56 |
57 | public:
58 | qint64 typingTime;
59 | QLineEdit* info;
60 | bool textEntered;
61 | explicit TextWidget(QWidget* parent, const QUuid& uuid);
62 | //Copy
63 | TextWidget (const TextWidget& other) :
64 | QTextBrowser(other.parentWidget()),
65 | MVBase(other.getIdentifier()),
66 | typing(other.typing),
67 | info(new QLineEdit(other.info)),
68 | textEntered(other.textEntered)
69 | {
70 |
71 | }
72 | //Move
73 | TextWidget (TextWidget&& other) noexcept :
74 | MVBase(other.getIdentifier()),
75 | typing(other.typing),
76 | info(other.info),
77 | textEntered(other.textEntered)
78 | {
79 | other.info = nullptr;
80 | }
81 | ~TextWidget() noexcept
82 | {
83 | }
84 | //Copy Assignment
85 | TextWidget& operator= (const TextWidget& other)
86 | {
87 | TextWidget tmp(other);
88 | *this = std::move(tmp);
89 | return *this;
90 | }
91 | //Move Assignment
92 | TextWidget& operator= (TextWidget&& other) noexcept
93 | {
94 | info->deleteLater();
95 | info = other.info;
96 | other.info = nullptr;
97 | textEntered = other.textEntered;
98 | typing = other.typing;
99 | return *this;
100 | }
101 |
102 | void showTyping(QString hostname);
103 | void showEntered(QString hostname);
104 | void clearInfoLine();
105 | void timerCallback();
106 | void invert();
107 | };
108 |
109 | class StackedWidget : public QStackedWidget {
110 | Q_OBJECT
111 | QHash history;
112 | int removeLastWidget();
113 | QTimer *typingTimer;
114 | public:
115 | StackedWidget(QWidget* parent);
116 | int append(QString str, QUuid& uuid);
117 | int switchToUuid(QUuid& uuid);
118 | int newHistory(QUuid &uuid);
119 | TextWidget *getItem(QUuid &uuid);
120 | int showTyping(QUuid &uuid, QString hostname);
121 | int showEntered(QUuid &uuid, QString hostname);
122 | int clearInfoLine(QUuid &uuid);
123 | void invert(QUuid uuid);
124 | private slots:
125 | void timerCallback();
126 | };
127 |
128 | }
129 |
130 | #endif // PXMMESSAGEVIEWER_H
131 |
--------------------------------------------------------------------------------
/ui/pxmaboutdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | PXMAboutDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 250
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 400
22 | 250
23 |
24 |
25 |
26 |
27 | 400
28 | 300
29 |
30 |
31 |
32 | Qt::NoFocus
33 |
34 |
35 | About PXMessenger
36 |
37 |
38 | true
39 |
40 |
41 |
42 |
43 | 30
44 | 200
45 | 341
46 | 32
47 |
48 |
49 |
50 | Qt::Horizontal
51 |
52 |
53 | QDialogButtonBox::Close|QDialogButtonBox::Ok
54 |
55 |
56 | true
57 |
58 |
59 |
60 |
61 |
62 | 0
63 | 0
64 | 400
65 | 250
66 |
67 |
68 |
69 |
70 | 0
71 | 0
72 |
73 |
74 |
75 |
76 | 400
77 | 250
78 |
79 |
80 |
81 |
82 | 600
83 | 350
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | 30
94 | 30
95 | 64
96 | 64
97 |
98 |
99 |
100 |
101 |
102 |
103 | label
104 | buttonBox
105 | label_2
106 |
107 |
108 |
109 |
110 | buttonBox
111 | accepted()
112 | PXMAboutDialog
113 | accept()
114 |
115 |
116 | 248
117 | 254
118 |
119 |
120 | 157
121 | 274
122 |
123 |
124 |
125 |
126 | buttonBox
127 | rejected()
128 | PXMAboutDialog
129 | reject()
130 |
131 |
132 | 316
133 | 260
134 |
135 |
136 | 286
137 | 274
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/include/pxmserver.h:
--------------------------------------------------------------------------------
1 | /*! @file pxmserver.h
2 | * @brief public header for for pxmserver.cpp
3 | *
4 | * Manages the listener socket and all subsequent connections made to this
5 | * device.
6 | */
7 |
8 | #ifndef PXMSERVER_H
9 | #define PXMSERVER_H
10 |
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 |
21 | struct bufferevent;
22 | struct event_base;
23 | class ServerThreadPrivate;
24 |
25 | namespace PXMServer
26 | {
27 | const timeval READ_TIMEOUT = {1, 0}; /*!< timeout if we receive partial
28 | packets */
29 | const timeval READ_TIMEOUT_RESET = {3600, 0}; /*!< workaround for libevent
30 | bug, fixed in 2.1 */
31 | const uint8_t PACKET_HEADER_LEN = 2;
32 | const size_t INTERNAL_MSG_LENGTH = 200;
33 | enum INTERNAL_MSG : uint16_t {
34 | ADD_DEFAULT_BEV = 0x1111,
35 | EXIT = 0x2222,
36 | CONNECT_TO_ADDR = 0x3333,
37 | TCP_PORT_CHANGE = 0x8888, // Under Construction
38 | UDP_PORT_CHANGE = 0x9999 // Under Construction
39 | };
40 | class ServerThread : public QThread
41 | {
42 | Q_OBJECT
43 | QScopedPointer d_ptr;
44 |
45 | public:
46 | // Default
47 | ServerThread(QObject* parent,
48 | QUuid uuid,
49 | in_addr multicast,
50 | unsigned short tcpPort = 0,
51 | unsigned short udpPort = 0);
52 |
53 | // Copy
54 | ServerThread(ServerThread const&) = delete;
55 | // Copy assignment
56 | ServerThread& operator=(ServerThread const&) = delete;
57 | // Move
58 | ServerThread(ServerThread&& st) noexcept = delete;
59 | // Move assignment
60 | ServerThread& operator=(ServerThread&& st) noexcept = delete;
61 | // Destructor
62 | ~ServerThread();
63 |
64 | void run() Q_DECL_OVERRIDE;
65 | signals:
66 | /*!
67 | * \brief packetHandler
68 | * Send a received packet to a handler to be dealt with
69 | */
70 | void packetHandler(const QSharedPointer, const size_t, const PXMConsts::MESSAGE_TYPE, const QUuid, const bufferevent*);
71 | /*!
72 | * \brief newTCPConnection
73 | * New connection has been received via accept(). No action has been taken
74 | * with it yet.
75 | */
76 | void newTCPConnection(bufferevent*);
77 | /*!
78 | * \brief authHandler
79 | * Authentication packet has been received and needs to be dealt with.
80 | */
81 | void authHandler(QString, unsigned short, QString,
82 | evutil_socket_t, QUuid, bufferevent*);
83 | /*!
84 | * \brief peerQuit
85 | * A connection has been terminated
86 | */
87 | void peerQuit(evutil_socket_t, bufferevent*);
88 | /*!
89 | * \brief attemptConnection
90 | * Recieved a udp "name" packet, we probably want to connect to the address
91 | * that came with it. Pass this info along to see if we are already
92 | * connected to it.
93 | */
94 | void attemptConnection(struct sockaddr_in, QUuid);
95 | void sendName(bufferevent*, QString, QString);
96 | void setPeerHostname(QString, QUuid);
97 | void sendUDP(const char*, unsigned short);
98 | void setListenerPorts(unsigned short, unsigned short);
99 | void libeventBackend(QString, QString);
100 | void setInternalBufferevent(bufferevent*);
101 | void setSelfCommsBufferevent(bufferevent*);
102 | void multicastIsFunctional();
103 | void serverSetupFailure(QString);
104 | void resultOfConnectionAttempt(evutil_socket_t, bool, bufferevent*, QUuid);
105 | };
106 | }
107 |
108 | #endif // MESS_SERV_H
109 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/src/Updater.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2016 Alex Spataru
3 | *
4 | * This file is part of the QSimpleUpdater library, which is released under
5 | * the DBAD license, you can read a copy of it below:
6 | *
7 | * DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
8 | * DISTRIBUTION AND MODIFICATION:
9 | *
10 | * Do whatever you like with the original work, just don't be a dick.
11 | * Being a dick includes - but is not limited to - the following instances:
12 | *
13 | * 1a. Outright copyright infringement - Don't just copy this and change the
14 | * name.
15 | * 1b. Selling the unmodified original with no work done what-so-ever, that's
16 | * REALLY being a dick.
17 | * 1c. Modifying the original work to contain hidden harmful content.
18 | * That would make you a PROPER dick.
19 | *
20 | * If you become rich through modifications, related works/services, or
21 | * supporting the original work, share the love.
22 | * Only a dick would make loads off this work and not buy the original works
23 | * creator(s) a pint.
24 | *
25 | * Code is provided with no warranty. Using somebody else's code and bitching
26 | * when it goes wrong makes you a DONKEY dick.
27 | * Fix the problem yourself. A non-dick would submit the fix back.
28 | */
29 |
30 | #ifndef _QSIMPLEUPDATER_UPDATER_H
31 | #define _QSIMPLEUPDATER_UPDATER_H
32 |
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include
39 |
40 | class Downloader;
41 |
42 | /**
43 | * \brief Downloads and interprests the update definition file
44 | */
45 | class QSU_DECL Updater : public QObject
46 | {
47 | Q_OBJECT
48 |
49 | signals:
50 | void checkingFinished (const QString& url);
51 | void downloadFinished (const QString& url, const QString& filepath);
52 | void appcastDownloaded (const QString& url, const QByteArray& data);
53 | void installerOpened();
54 | void updateDeclined();
55 |
56 | public:
57 | Updater();
58 | ~Updater();
59 |
60 | QString url() const;
61 | QString openUrl() const;
62 | QString changelog() const;
63 | QString moduleName() const;
64 | QString downloadUrl() const;
65 | QString platformKey() const;
66 | QString moduleVersion() const;
67 | QString latestVersion() const;
68 |
69 | bool customAppcast() const;
70 | bool notifyOnUpdate() const;
71 | bool notifyOnFinish() const;
72 | bool updateAvailable() const;
73 | bool downloaderEnabled() const;
74 | bool useCustomInstallProcedures() const;
75 |
76 | public slots:
77 | void checkForUpdates();
78 | void setUrl (const QString& url);
79 | void setModuleName (const QString& name);
80 | void setNotifyOnUpdate (const bool notify);
81 | void setNotifyOnFinish (const bool notify);
82 | void setModuleVersion (const QString& version);
83 | void setDownloaderEnabled (const bool enabled);
84 | void setPlatformKey (const QString& platformKey);
85 | void setUseCustomAppcast (const bool customAppcast);
86 | void setUseCustomInstallProcedures (const bool custom);
87 |
88 | private slots:
89 | void onReply (QNetworkReply* reply);
90 | void setUpdateAvailable (const bool available);
91 |
92 | private:
93 | bool compare (const QString& x, const QString& y);
94 |
95 | private:
96 | QString m_url;
97 |
98 | bool m_customAppcast;
99 | bool m_notifyOnUpdate;
100 | bool m_notifyOnFinish;
101 | bool m_updateAvailable;
102 | bool m_downloaderEnabled;
103 |
104 | QString m_openUrl;
105 | QString m_platform;
106 | QString m_changelog;
107 | QString m_moduleName;
108 | QString m_downloadUrl;
109 | QString m_moduleVersion;
110 | QString m_latestVersion;
111 |
112 | Downloader* m_downloader;
113 | QNetworkAccessManager* m_manager;
114 | };
115 |
116 | #endif
117 |
--------------------------------------------------------------------------------
/src/pxmessenger.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "pxmagent.h"
9 | #include "pxmconsole.h"
10 |
11 | #ifdef _WIN32
12 | static QLatin1Char seperator = QLatin1Char('\\');
13 | #define WIN32_LEAN_AND_MEAN
14 | #else
15 | QLatin1Char seperator = QLatin1Char('/');
16 | #endif
17 |
18 |
19 | #ifdef QT_DEBUG
20 | void debugMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg)
21 | #else
22 | void debugMessageOutput(QtMsgType type, const QMessageLogContext&, const QString& msg)
23 | #endif
24 | {
25 | using namespace PXMConsole;
26 | Logger* logger = Logger::getInstance();
27 |
28 | switch (logger->getVerbosityLevel()) {
29 | case 0:
30 | if (type == QtDebugMsg || type == QtWarningMsg)
31 | return;
32 | break;
33 | case 1:
34 | if (type == QtDebugMsg)
35 | return;
36 | break;
37 | default:
38 | break;
39 | }
40 |
41 | QByteArray localMsg = QByteArray();
42 | localMsg.append(QDateTime::currentDateTime().time().toString(QStringLiteral("[hh:mm:ss] ")));
43 |
44 | QColor msgColor;
45 | switch (type) {
46 | case QtDebugMsg:
47 | localMsg.append(QString("%1").arg(QStringLiteral("DEBUG:"), -7, QChar(' ')));
48 | msgColor = Qt::gray;
49 | break;
50 | case QtWarningMsg:
51 | localMsg.append(QString("%1").arg(QStringLiteral("WARN:"), -7, QChar(' ')));
52 | msgColor = Qt::darkYellow;
53 | break;
54 | case QtCriticalMsg:
55 | localMsg.append(QString("%1").arg(QStringLiteral("CRIT:"), -7, QChar(' ')));
56 | msgColor = Qt::red;
57 | break;
58 | case QtFatalMsg:
59 | localMsg.append(QString("%1").arg(QStringLiteral("FATAL:"), -7, QChar(' ')));
60 | abort();
61 | case QtInfoMsg:
62 | localMsg.append(QString("%1").arg(QStringLiteral("INFO:"), -7, QChar(' ')));
63 | msgColor = QGuiApplication::palette().foreground().color();
64 | break;
65 | }
66 |
67 | QString filename = QString();
68 | #ifdef QT_DEBUG
69 | filename = QString::fromUtf8(context.file);
70 | filename = filename.right(filename.length() - filename.lastIndexOf(seperator) - 1);
71 | filename = QString("%1").arg(filename.append(':' + QString::number(context.line)), -(static_cast(PXMConsts::DEBUG_PADDING)),
72 | QChar(' '));
73 | #endif /* end QT_DEBUG */
74 | localMsg.append(filename.toUtf8() % msg.toLatin1());
75 |
76 | localMsg.append(QChar('\n'));
77 | const char* cmsg = localMsg.constData();
78 | fprintf(stderr, "%s", cmsg);
79 | if (Window::textEdit) {
80 | qApp->postEvent(logger, new AppendTextEvent(localMsg, msgColor), Qt::LowEventPriority);
81 | }
82 | if (logger->getLogStatus() && logger->logFile->isOpen()) {
83 | logger->logFile->write(cmsg, strlen(cmsg));
84 | logger->logFile->flush();
85 | }
86 | }
87 |
88 | int main(int argc, char** argv)
89 | {
90 | qInstallMessageHandler(debugMessageOutput);
91 |
92 | QApplication app(argc, argv);
93 | QObject::connect(&app, &QApplication::lastWindowClosed, &app, &QApplication::quit);
94 |
95 | app.setApplicationName("PXMessenger");
96 | app.setOrganizationName("PXMessenger");
97 | app.setOrganizationDomain("PXMessenger");
98 | app.setApplicationVersion("1.6.0");
99 |
100 | //QFontDatabase::addApplicationFont(":/resources/EmojiOneColor-SVGinOT.ttf");
101 | int result;
102 | {
103 | PXMAgent overlord;
104 |
105 | QMetaObject::invokeMethod(&overlord, "init", Qt::QueuedConnection);
106 | QObject::connect(&overlord, &PXMAgent::alreadyRunning, &app, &QApplication::quit);
107 |
108 | result = app.exec();
109 |
110 | qInfo().noquote() << QStringLiteral("Exiting PXMessenger");
111 | }
112 | qInfo().noquote() << QStringLiteral("Successful Shutdown with code:") << result;
113 |
114 | return result;
115 | }
116 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/README.md:
--------------------------------------------------------------------------------
1 | # QSimpleUpdater
2 |
3 | [](https://travis-ci.org/alex-spataru/QSimpleUpdater)
4 | [](https://blockchain.info/address/1K85yLxjuqUmhkjP839R7C23XFhSxrefMx "Donate once-off to this project using BitCoin")
5 | [](https://github.com/alex-spataru/qsimpleupdater/releases/latest)
6 |
7 | QSimpleUpdater is an implementation of an auto-updating system to be used with Qt projects. It allows you to easily check for updates, download them and install them. Additionally, the QSimpleUpdater allows you to check for updates for different "modules" of your application. Check the [WTFs Section](#wtfs-section) for more information.
8 |
9 | Online documentation can be found [here](http://frc-utilities.github.io/documentation/qsimpleupdater/).
10 |
11 | [](etc/screenshots/)
12 |
13 | ## Integrating QSimpleUpdater with your projects
14 | 1. Copy the QSimpleUpdater folder in your "3rd-party" folder.
15 | 2. Include the QSimpleUpdater project include (*pri*) file using the include() function.
16 | 3. That's all! Check the [tutorial project](/tutorial) as a reference for your project.
17 |
18 | ## WTFs Section
19 |
20 | ### 1. How does the QSimpleUpdater check for updates?
21 |
22 | The QSimpleUpdater downloads an update definition file stored in JSON format. This file specifies the latest version, the download links and changelogs for each platform (you can also register your own platform easily if needed).
23 |
24 | After downloading this file, the library analyzes the local version and the remote version. If the remote version is greater than the local version, then the library infers that there is an update available and notifies the user.
25 |
26 | An example update definition file can be found [here](https://github.com/alex-spataru/QSimpleUpdater/blob/master/tutorial/definitions/updates.json).
27 |
28 | ### 2. Can I customize the update notifications shown to the user?
29 |
30 | Yes! You can "toggle" which notifications to show using the library's functions or re-implement by yourself the notifications by "reacting" to the signals emitted by the QSimpleUpdater.
31 |
32 | ```c++
33 | QString url = "https://MyBadassApplication.com/updates.json";
34 |
35 | QSimpleUpdater::getInstance()->setNotifyOnUpdate (url, true);
36 | QSimpleUpdater::getInstance()->setNotifyOnFinish (url, false);
37 |
38 | QSimpleUpdater::getInstance()->checkForUpdates (url);
39 | ```
40 |
41 | ### 3. Is the application able to download the updates directly?
42 |
43 | Yes. If there is an update available, the library will prompt the user if he/she wants to download the update. You can enable or disable the integrated downloader with the following code:
44 |
45 | ```c++
46 | QString url = "https://MyBadassApplication.com/updates.json";
47 | QSimpleUpdater::getInstance()->setDownloaderEnabled (url, true);
48 | ```
49 |
50 | ### 4. Why do I need to specify an URL for each function of the library?
51 |
52 | The QSimpleUpdater allows you to use different updater instances, which can be accessed with the URL of the update definitions.
53 | While it is not obligatory to use multiple updater instances, this can be useful for applications that make use of plugins or different modules.
54 |
55 | Say that you are developing a game, in this case, you could use the following code:
56 |
57 | ```c++
58 | // Update the game textures
59 | QString textures_url = "https://MyBadassGame.com/textures.json"
60 | QSimpleUpdater::getInstance()->setModuleName (textures_url, "textures");
61 | QSimpleUpdater::getInstance()->setModuleVersion (textures_url, "0.4");
62 | QSimpleUpdater::getInstance()->checkForUpdates (textures_url);
63 |
64 | // Update the game sounds
65 | QString sounds_url = "https://MyBadassGame.com/sounds.json"
66 | QSimpleUpdater::getInstance()->setModuleName (sounds_url, "sounds");
67 | QSimpleUpdater::getInstance()->setModuleVersion (sounds_url, "0.6");
68 | QSimpleUpdater::getInstance()->checkForUpdates (sounds_url);
69 |
70 | // Update the client (name & versions are already stored in qApp)
71 | QString client_url = "https://MyBadassGame.com/client.json"
72 | QSimpleUpdater::getInstance()->checkForUpdates (client_url);
73 | ```
74 |
75 | ## License
76 | QSimpleUpdater is free and open-source software, it is released under the [DBAD](COPYING.md) license.
77 |
--------------------------------------------------------------------------------
/src/pxmpeers.cpp:
--------------------------------------------------------------------------------
1 | #include "pxmpeers.h"
2 |
3 | #ifdef _WIN32
4 | #include
5 | #include
6 | Q_DECLARE_METATYPE(intptr_t)
7 | #else
8 | #include
9 | #endif
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 |
17 | using namespace Peers;
18 |
19 | // int Peers::textColorsNext = 0;
20 |
21 | PeerData::PeerData()
22 | : uuid(QUuid()),
23 | addrRaw(sockaddr_in()),
24 | hostname(QString()),
25 | progVersion(QString()),
26 | bw(QSharedPointer(new BevWrapper)),
27 | socket(-1),
28 | timeOfTyping(QDateTime::currentMSecsSinceEpoch()),
29 | connectTo(false),
30 | isAuthed(false)
31 | {
32 | // textColor = textColors.at(textColorsNext % textColors.length());
33 | // textColorsNext++;
34 | }
35 |
36 | PeerData::PeerData(const PeerData& pd)
37 | : uuid(pd.uuid),
38 | addrRaw(pd.addrRaw),
39 | hostname(pd.hostname),
40 | // textColor(pd.textColor),
41 | progVersion(pd.progVersion),
42 | bw(pd.bw),
43 | socket(pd.socket),
44 | timeOfTyping(pd.timeOfTyping),
45 | connectTo(pd.connectTo),
46 | isAuthed(pd.isAuthed)
47 | {
48 | }
49 |
50 | PeerData::PeerData(PeerData&& pd) noexcept
51 | : uuid(pd.uuid),
52 | addrRaw(pd.addrRaw),
53 | hostname(pd.hostname),
54 | // textColor(pd.textColor),
55 | progVersion(pd.progVersion),
56 | bw(pd.bw),
57 | socket(pd.socket),
58 | timeOfTyping(pd.timeOfTyping),
59 | connectTo(pd.connectTo),
60 | isAuthed(pd.isAuthed)
61 | {
62 | pd.bw.clear();
63 | }
64 |
65 | PeerData& PeerData::operator=(PeerData&& p) noexcept
66 | {
67 | if (this != &p) {
68 | bw = p.bw;
69 | p.bw.clear();
70 | uuid = p.uuid;
71 | addrRaw = p.addrRaw;
72 | hostname = p.hostname;
73 | // textColor = p.textColor;
74 | progVersion = p.progVersion;
75 | socket = p.socket;
76 | timeOfTyping = p.timeOfTyping;
77 | connectTo = p.connectTo;
78 | isAuthed = p.isAuthed;
79 | }
80 | return *this;
81 | }
82 |
83 | PeerData& PeerData::operator=(const PeerData& p)
84 | {
85 | Peers::PeerData temp(p);
86 | *this = std::move(temp);
87 | return *this;
88 | }
89 |
90 | QString PeerData::toInfoString()
91 | {
92 | return QString(
93 | QStringLiteral("Hostname: ") % hostname % QStringLiteral("\nUUID: ") % uuid.toString() %
94 | QStringLiteral("\nProgram Version: ") % progVersion % QStringLiteral("\nIP Address: ") %
95 | QString::fromLocal8Bit(inet_ntoa(addrRaw.sin_addr)) % QStringLiteral(":") %
96 | QString::number(ntohs(addrRaw.sin_port)) % QStringLiteral("\nIsAuthenticated: ") %
97 | QString::fromLocal8Bit((isAuthed ? "true" : "false")) % QStringLiteral("\npreventAttemptConnection: ") %
98 | QString::fromLocal8Bit((connectTo ? "true" : "false")) % QStringLiteral("\nSocketDescriptor: ") %
99 | QString::number(socket) % QStringLiteral("\nBufferevent: ") %
100 | (bw->getBev() ? QString::asprintf("%8p", static_cast(bw->getBev())) : QStringLiteral("NULL")) %
101 | QStringLiteral("\n"));
102 | }
103 |
104 | BevWrapper::BevWrapper() : bev(nullptr), locker(new QMutex)
105 | {
106 | }
107 |
108 | BevWrapper::BevWrapper(bufferevent* buf) : bev(buf), locker(new QMutex)
109 | {
110 | }
111 |
112 | BevWrapper::~BevWrapper()
113 | {
114 | if (locker) {
115 | locker->tryLock(500);
116 | if (bev) {
117 | bufferevent_free(bev);
118 | bev = nullptr;
119 | }
120 | locker->unlock();
121 | delete locker;
122 | locker = nullptr;
123 | } else if (bev) {
124 | bufferevent_free(bev);
125 | bev = nullptr;
126 | }
127 | }
128 |
129 | BevWrapper::BevWrapper(BevWrapper&& b) noexcept : bev(b.bev), locker(b.locker)
130 | {
131 | b.bev = nullptr;
132 | b.locker = nullptr;
133 | }
134 |
135 | BevWrapper& BevWrapper::operator=(BevWrapper&& b) noexcept
136 | {
137 | if (this != &b) {
138 | bev = b.bev;
139 | locker = b.locker;
140 | b.bev = nullptr;
141 | b.locker = nullptr;
142 | }
143 | return *this;
144 | }
145 |
146 | void BevWrapper::lockBev()
147 | {
148 | locker->lock();
149 | }
150 |
151 | void BevWrapper::unlockBev()
152 | {
153 | locker->unlock();
154 | }
155 |
156 | int BevWrapper::freeBev()
157 | {
158 | if (bev) {
159 | lockBev();
160 | bufferevent_free(bev);
161 | bev = nullptr;
162 | unlockBev();
163 | return 0;
164 | } else {
165 | return -1;
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/include/QSimpleUpdater.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2016 Alex Spataru
3 | *
4 | * This file is part of the QSimpleUpdater library, which is released under
5 | * the DBAD license, you can read a copy of it below:
6 | *
7 | * DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
8 | * DISTRIBUTION AND MODIFICATION:
9 | *
10 | * Do whatever you like with the original work, just don't be a dick.
11 | * Being a dick includes - but is not limited to - the following instances:
12 | *
13 | * 1a. Outright copyright infringement - Don't just copy this and change the
14 | * name.
15 | * 1b. Selling the unmodified original with no work done what-so-ever, that's
16 | * REALLY being a dick.
17 | * 1c. Modifying the original work to contain hidden harmful content.
18 | * That would make you a PROPER dick.
19 | *
20 | * If you become rich through modifications, related works/services, or
21 | * supporting the original work, share the love.
22 | * Only a dick would make loads off this work and not buy the original works
23 | * creator(s) a pint.
24 | *
25 | * Code is provided with no warranty. Using somebody else's code and bitching
26 | * when it goes wrong makes you a DONKEY dick.
27 | * Fix the problem yourself. A non-dick would submit the fix back.
28 | */
29 |
30 | #ifndef _QSIMPLEUPDATER_MAIN_H
31 | #define _QSIMPLEUPDATER_MAIN_H
32 |
33 | #include
34 | #include
35 | #include
36 |
37 | #if defined (QSU_SHARED)
38 | #define QSU_DECL Q_DECL_EXPORT
39 | #elif defined (QSU_IMPORT)
40 | #define QSU_DECL Q_DECL_IMPORT
41 | #else
42 | #define QSU_DECL
43 | #endif
44 |
45 | class Updater;
46 |
47 | /**
48 | * \brief Manages the updater instances
49 | *
50 | * The \c QSimpleUpdater class manages the updater system and allows for
51 | * parallel application modules to check for updates and download them.
52 | *
53 | * The behavior of each updater can be regulated by specifying the update
54 | * definitions URL (from where we download the individual update definitions)
55 | * and defining the desired options by calling the individual "setter"
56 | * functions (e.g. \c setNotifyOnUpdate()).
57 | *
58 | * The \c QSimpleUpdater also implements an integrated downloader.
59 | * If you need to use a custom install procedure/code, just create a function
60 | * that is called when the \c downloadFinished() signal is emitted to
61 | * implement your own install procedures.
62 | *
63 | * By default, the downloader will try to open the file as if you opened it
64 | * from a file manager or a web browser (with the "file:*" url).
65 | */
66 | class QSU_DECL QSimpleUpdater : public QObject
67 | {
68 | Q_OBJECT
69 |
70 | signals:
71 | void checkingFinished (const QString& url);
72 | void appcastDownloaded (const QString& url, const QByteArray& data);
73 | void downloadFinished (const QString& url, const QString& filepath);
74 | void installerOpened();
75 | void updateDeclined();
76 |
77 | public:
78 | static QSimpleUpdater* getInstance();
79 |
80 | bool usesCustomAppcast (const QString& url) const;
81 | bool getNotifyOnUpdate (const QString& url) const;
82 | bool getNotifyOnFinish (const QString& url) const;
83 | bool getUpdateAvailable (const QString& url) const;
84 | bool getDownloaderEnabled (const QString& url) const;
85 | bool usesCustomInstallProcedures (const QString& url) const;
86 |
87 | QString getOpenUrl (const QString& url) const;
88 | QString getChangelog (const QString& url) const;
89 | QString getModuleName (const QString& url) const;
90 | QString getDownloadUrl (const QString& url) const;
91 | QString getPlatformKey (const QString& url) const;
92 | QString getLatestVersion (const QString& url) const;
93 | QString getModuleVersion (const QString& url) const;
94 |
95 | public slots:
96 | void checkForUpdates (const QString& url);
97 | void setModuleName (const QString& url, const QString& name);
98 | void setNotifyOnUpdate (const QString& url, const bool notify);
99 | void setNotifyOnFinish (const QString& url, const bool notify);
100 | void setPlatformKey (const QString& url, const QString& platform);
101 | void setModuleVersion (const QString& url, const QString& version);
102 | void setDownloaderEnabled (const QString& url, const bool enabled);
103 | void setUseCustomAppcast (const QString& url, const bool customAppcast);
104 | void setUseCustomInstallProcedures (const QString& url, const bool custom);
105 |
106 | protected:
107 | ~QSimpleUpdater();
108 |
109 | private:
110 | Updater* getUpdater (const QString& url) const;
111 | };
112 |
113 | #endif
114 |
--------------------------------------------------------------------------------
/src/pxmconsole.cpp:
--------------------------------------------------------------------------------
1 | #include "pxmconsole.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | using namespace PXMConsole;
13 | struct PXMConsole::WindowPrivate {
14 | QWidget* centralwidget;
15 | QGridLayout* gridLayout;
16 | QGridLayout* gridLayout_2;
17 | QScrollBar* sb;
18 | QLabel* verbosity;
19 | bool atMaximum = false;
20 | };
21 |
22 | QTextEdit* Window::textEdit = 0;
23 | int AppendTextEvent::type = QEvent::registerEventType();
24 | Logger* Logger::loggerInstance = nullptr;
25 |
26 | Window::Window(QWidget* parent) : QMainWindow(parent), d_ptr(new PXMConsole::WindowPrivate())
27 | {
28 | this->setObjectName("Debug Console");
29 | this->setWindowTitle("Debug Console");
30 | d_ptr->centralwidget = new QWidget(this);
31 | d_ptr->centralwidget->setObjectName(QStringLiteral("centralwidget"));
32 | d_ptr->gridLayout_2 = new QGridLayout(d_ptr->centralwidget);
33 | d_ptr->gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
34 | d_ptr->gridLayout = new QGridLayout();
35 | d_ptr->gridLayout->setObjectName(QStringLiteral("gridLayout"));
36 | textEdit = new QTextEdit(d_ptr->centralwidget);
37 | textEdit->setObjectName(QStringLiteral("plainTextEdit"));
38 | textEdit->setReadOnly(true);
39 | textEdit->document()->setMaximumBlockCount(HISTORY_LIMIT);
40 | QFont font("Monospaced");
41 | font.setStyleHint(QFont::TypeWriter);
42 | textEdit->setFont(font);
43 | Logger::getInstance()->setTextEdit(textEdit);
44 | pushButton = new QPushButton(d_ptr->centralwidget);
45 | pushButton->setText("Print Info");
46 | pushButton->setMaximumSize(QSize(250, 16777215));
47 | pushButton1 = new QPushButton(d_ptr->centralwidget);
48 | pushButton1->setText("Clear");
49 | pushButton1->setMaximumSize(QSize(250, 16777215));
50 |
51 | d_ptr->verbosity = new QLabel(d_ptr->centralwidget);
52 | d_ptr->verbosity->setText("Debug Verbosity: " % QString::number(Logger::getInstance()->getVerbosityLevel()));
53 | d_ptr->gridLayout->addWidget(d_ptr->verbosity, 1, 3, 1, 1);
54 |
55 | d_ptr->gridLayout->addWidget(textEdit, 0, 0, 1, 4);
56 | d_ptr->gridLayout->addWidget(pushButton, 1, 0, 1, 1);
57 | d_ptr->gridLayout->addWidget(pushButton1, 1, 1, 1, 1);
58 |
59 | d_ptr->gridLayout_2->addLayout(d_ptr->gridLayout, 0, 0, 1, 1);
60 |
61 | d_ptr->sb = Window::textEdit->verticalScrollBar();
62 | d_ptr->sb->setTracking(true);
63 |
64 | this->setCentralWidget(d_ptr->centralwidget);
65 | this->resize(1000, 300);
66 | d_ptr->sb->setValue(d_ptr->sb->maximum());
67 | d_ptr->atMaximum = true;
68 | QObject::connect(d_ptr->sb, &QScrollBar::valueChanged, this, &Window::adjustScrollBar);
69 | QObject::connect(d_ptr->sb, &QScrollBar::rangeChanged, this, &Window::rangeChanged);
70 | QObject::connect(pushButton1, &QPushButton::clicked, textEdit, &QTextEdit::clear);
71 |
72 | if (Logger::getInstance()->getLogStatus()) {
73 | Logger::getInstance()->logFile->remove();
74 | Logger::getInstance()->logFile->open(QIODevice::ReadWrite);
75 | }
76 | }
77 |
78 | Window::~Window()
79 | {
80 | }
81 | void Window::adjustScrollBar(int i)
82 | {
83 | if (i == d_ptr->sb->maximum()) {
84 | d_ptr->atMaximum = true;
85 | } else {
86 | d_ptr->atMaximum = false;
87 | }
88 | }
89 | void Window::rangeChanged(int, int i2)
90 | {
91 | if (d_ptr->atMaximum) {
92 | d_ptr->sb->setValue(i2);
93 | }
94 | }
95 | void Window::verbosityChanged()
96 | {
97 | d_ptr->verbosity->setText("Debug Verbosity: " % QString::number(Logger::getInstance()->getVerbosityLevel()));
98 | }
99 |
100 | void Logger::setLogStatus(bool stat)
101 | {
102 | if (logActive != stat && stat == true && logFile) {
103 | logFile->remove();
104 | if (logFile->open(QIODevice::ReadWrite)) {
105 | logActive = true;
106 | } else {
107 | logActive = false;
108 | }
109 | } else if (logActive != stat && stat == false && logFile) {
110 | logActive = false;
111 | logFile->flush();
112 | logFile->close();
113 | }
114 | }
115 |
116 | void Logger::customEvent(QEvent* event)
117 | {
118 | AppendTextEvent* text = dynamic_cast(event);
119 | if (text) {
120 | logTextEdit->setTextColor(text->getColor());
121 | /*
122 | QTextCursor curs = logTextEdit->textCursor();
123 | QTextCursor insert = curs;
124 | insert.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
125 | logTextEdit->setTextCursor(insert);
126 | */
127 | logTextEdit->insertPlainText(text->getText());
128 | // logTextEdit->setTextCursor(curs);
129 | event->accept();
130 | } else {
131 | QObject::customEvent(event);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/src/Downloader.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Downloader
4 |
5 |
6 |
7 | 0
8 | 0
9 | 464
10 | 164
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 | Updater
21 |
22 |
23 |
24 | 0
25 |
26 |
27 | 12
28 |
29 |
30 | 12
31 |
32 |
33 | 12
34 |
35 |
36 | 12
37 |
38 | -
39 |
40 |
41 |
42 | 0
43 |
44 |
45 | 0
46 |
47 |
48 | 0
49 |
50 |
51 | 0
52 |
53 |
54 | 0
55 |
56 |
-
57 |
58 |
59 |
60 | 96
61 | 96
62 |
63 |
64 |
65 |
66 |
67 |
68 | :/icons/update.png
69 |
70 |
71 |
72 | -
73 |
74 |
75 |
76 | 0
77 |
78 |
-
79 |
80 |
81 |
82 | 75
83 | true
84 |
85 |
86 |
87 | Downloading updates
88 |
89 |
90 |
91 | -
92 |
93 |
94 |
95 | 320
96 | 0
97 |
98 |
99 |
100 | 0
101 |
102 |
103 | false
104 |
105 |
106 |
107 | -
108 |
109 |
110 | Time remaining: 0 minutes
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | -
121 |
122 |
123 |
124 | 12
125 |
126 |
127 | 12
128 |
129 |
130 | 12
131 |
132 |
133 | 12
134 |
135 |
-
136 |
137 |
138 | Qt::Horizontal
139 |
140 |
141 |
142 | 40
143 | 20
144 |
145 |
146 |
147 |
148 | -
149 |
150 |
151 | Open
152 |
153 |
154 |
155 | -
156 |
157 |
158 | Stop
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/src/pxminireader.cpp:
--------------------------------------------------------------------------------
1 | #include "pxminireader.h"
2 |
3 | #ifdef _WIN32
4 | #include
5 | #else
6 | #include
7 | #endif
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include "pxmconsts.h"
16 |
17 | PXMIniReader::PXMIniReader()
18 | : iniFile(new QSettings(QSettings::IniFormat, QSettings::UserScope, "PXMessenger", "PXMessenger", NULL))
19 | {
20 | }
21 | PXMIniReader::~PXMIniReader()
22 | {
23 | }
24 | bool PXMIniReader::checkAllowMoreThanOne()
25 | {
26 | if (iniFile->contains("config/AllowMoreThanOneInstance")) {
27 | return iniFile->value("config/AllowMoreThanOneInstance", false).toBool();
28 | }
29 | iniFile->setValue("config/AllowMoreThanOneInstance", false);
30 | return false;
31 | }
32 | void PXMIniReader::setAllowMoreThanOne(bool value)
33 | {
34 | iniFile->setValue("config/AllowMoreThanOneInstance", value);
35 | }
36 | unsigned int PXMIniReader::getUUIDNumber() const
37 | {
38 | unsigned int i = 0;
39 | QString uuidStr = "uuid/";
40 | while (iniFile->value(uuidStr + QString::number(i), QString()) == "INUSE") {
41 | i++;
42 | }
43 | if (iniFile->value(uuidStr + QString::number(i), QString()) == "") {
44 | iniFile->setValue(uuidStr + QString::number(i), QUuid::createUuid().toString());
45 | }
46 | return i;
47 | }
48 | QUuid PXMIniReader::getUUID(unsigned int num, bool takeIt) const
49 | {
50 | QUuid uuid = iniFile->value("uuid/" + QString::number(num), QUuid()).toUuid();
51 | if (uuid.isNull()) {
52 | uuid = QUuid::createUuid();
53 | iniFile->setValue("uuid/" + QString::number(num), uuid);
54 | }
55 | if (takeIt) {
56 | iniFile->setValue("uuid/" + QString::number(num), "INUSE");
57 | }
58 | return uuid;
59 | }
60 | int PXMIniReader::resetUUID(unsigned int num, QUuid uuid)
61 | {
62 | iniFile->setValue("uuid/" + QString::number(num), uuid.toString());
63 | return 1;
64 | }
65 | void PXMIniReader::setPort(QString protocol, int portNumber)
66 | {
67 | iniFile->setValue("net/" + protocol, portNumber);
68 | }
69 | unsigned short PXMIniReader::getPort(QString protocol)
70 | {
71 | unsigned int portNumber = iniFile->value("net/" + protocol, 0).toUInt();
72 | if (portNumber == 13649) {
73 | iniFile->setValue("net/" + protocol, 0);
74 | portNumber = 0;
75 | } else if (portNumber != 0 && protocol == QLatin1String("TCP")) {
76 | portNumber += getUUIDNumber();
77 | } else if (portNumber >= 65535) {
78 | qWarning() << "Bad port number in UUID..." << protocol << portNumber;
79 | portNumber = 0;
80 | }
81 | return static_cast(portNumber);
82 | }
83 | void PXMIniReader::setHostname(QString hostname)
84 | {
85 | iniFile->setValue("hostname/hostname", hostname.left(PXMConsts::MAX_HOSTNAME_LENGTH));
86 | }
87 | QString PXMIniReader::getHostname(QString defaultHostname)
88 | {
89 | QString hostname = iniFile->value("hostname/hostname", QString()).toString();
90 | if (hostname.isEmpty()) {
91 | iniFile->setValue("hostname/hostname", defaultHostname);
92 | hostname = defaultHostname;
93 | }
94 |
95 | return hostname.left(PXMConsts::MAX_HOSTNAME_LENGTH).simplified();
96 | }
97 | void PXMIniReader::setWindowSize(QSize windowSize)
98 | {
99 | if (windowSize.isValid())
100 | iniFile->setValue("WindowSize/QSize", windowSize);
101 | }
102 | QSize PXMIniReader::getWindowSize(QSize defaultSize) const
103 | {
104 | QSize windowSize = iniFile->value("WindowSize/QSize", defaultSize).toSize();
105 | if (windowSize.isValid()) {
106 | return windowSize;
107 | } else {
108 | windowSize = QSize(700, 500);
109 | iniFile->setValue("WindowSize/QSize", windowSize);
110 | return windowSize;
111 | }
112 | }
113 | void PXMIniReader::setMute(bool mute)
114 | {
115 | iniFile->setValue("config/Mute", mute);
116 | }
117 | bool PXMIniReader::getMute() const
118 | {
119 | return iniFile->value("config/Mute", false).toBool();
120 | }
121 | void PXMIniReader::setFocus(bool focus)
122 | {
123 | iniFile->setValue("config/PreventFocus", focus);
124 | }
125 | bool PXMIniReader::getFocus() const
126 | {
127 | return iniFile->value("config/PreventFocus", false).toBool();
128 | }
129 | QString PXMIniReader::getFont()
130 | {
131 | return iniFile->value("config/Font", "").toString();
132 | }
133 | void PXMIniReader::setFont(QString font)
134 | {
135 | iniFile->setValue("config/Font", font);
136 | }
137 | QString PXMIniReader::getMulticastAddress() const
138 | {
139 | QString ipFull = iniFile->value("net/MulticastAddress", "").toString();
140 | if (ipFull.isEmpty() || strlen(ipFull.toLatin1().constData()) > INET_ADDRSTRLEN) {
141 | return QString::fromLocal8Bit(PXMConsts::DEFAULT_MULTICAST_ADDRESS);
142 | }
143 | return ipFull;
144 | }
145 | int PXMIniReader::setMulticastAddress(QString ip)
146 | {
147 | iniFile->setValue("net/MulticastAddress", ip);
148 |
149 | return 0;
150 | }
151 | int PXMIniReader::getVerbosity() const
152 | {
153 | return iniFile->value("config/DebugVerbosity", 0).toInt();
154 | }
155 |
156 | void PXMIniReader::setVerbosity(int level) const
157 | {
158 | iniFile->setValue("config/DebugVerbosity", level);
159 | }
160 | bool PXMIniReader::getLogActive() const
161 | {
162 | return iniFile->value("config/LogActive", false).toBool();
163 | }
164 |
165 | void PXMIniReader::setLogActive(bool status) const
166 | {
167 | iniFile->setValue("config/LogActive", status);
168 | }
169 |
170 | bool PXMIniReader::getDarkColorScheme() const
171 | {
172 | return iniFile->value("config/DarkColorScheme", false).toBool();
173 | }
174 | void PXMIniReader::setDarkColorScheme(bool status) const
175 | {
176 | iniFile->setValue("config/DarkColorScheme", status);
177 | }
178 | void PXMIniReader::setUpdates(bool status) const
179 | {
180 | #ifdef _WIN32
181 | iniFile->setValue("config/Autoupdate", status);
182 | #endif
183 | (void)status;
184 | }
185 | bool PXMIniReader::getUpdates() const
186 | {
187 | #ifdef _WIN32
188 | return iniFile->value("config/Autoupdate", true).toBool();
189 | #endif
190 | return false;
191 | }
192 |
--------------------------------------------------------------------------------
/src/pxmclient.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #ifdef _WIN32
9 | #include
10 | #include
11 | #elif __unix__
12 | #include
13 | #include
14 | #include
15 | #include
16 | #else
17 | #error "include headers for socket implementation"
18 | #endif
19 |
20 | #include
21 |
22 | #include
23 | #include
24 |
25 | #include "pxmpeers.h"
26 | #include "netcompression.h"
27 |
28 | static_assert(sizeof(uint8_t) == 1, "uint8_t not defined as 1 byte");
29 | static_assert(sizeof(uint16_t) == 2, "uint16_t not defined as 2 bytes");
30 | static_assert(sizeof(uint32_t) == 4, "uint32_t not defined as 4 bytes");
31 |
32 | struct PXMClientPrivate {
33 | PXMClientPrivate(PXMClient* q) : q_ptr(q) {}
34 | PXMClient* q_ptr;
35 | in_addr multicastAddress;
36 | unsigned char packedLocalUUID[NetCompression::PACKED_UUID_LENGTH];
37 | size_t localUUIDLen;
38 |
39 | // Functions
40 | void sendMsg(const QSharedPointer bw,
41 | const char* msg,
42 | const size_t msgLen,
43 | const PXMConsts::MESSAGE_TYPE type,
44 | const QUuid uuidReceiver);
45 | };
46 | PXMClient::PXMClient(QObject* parent, in_addr multicast, QUuid localUUID)
47 | : QObject(parent), d_ptr(new PXMClientPrivate(this))
48 | {
49 | this->setObjectName("PXMClient");
50 |
51 | d_ptr->multicastAddress = multicast;
52 |
53 | setLocalUUID(localUUID);
54 | d_ptr->localUUIDLen = sizeof(d_ptr->packedLocalUUID) / sizeof(d_ptr->packedLocalUUID[0]);
55 | }
56 |
57 | PXMClient::~PXMClient()
58 | {
59 | qDebug() << "Shutdown of PXMClient Successful";
60 | }
61 |
62 | void PXMClient::setLocalUUID(const QUuid uuid)
63 | {
64 | NetCompression::packUUID(&d_ptr->packedLocalUUID[0], uuid);
65 | }
66 | int PXMClient::sendUDP(const char* msg, unsigned short port)
67 | {
68 | size_t len;
69 | struct sockaddr_in broadaddr;
70 | evutil_socket_t socketfd2;
71 |
72 | memset(&broadaddr, 0, sizeof(broadaddr));
73 | broadaddr.sin_family = AF_INET;
74 | broadaddr.sin_addr = d_ptr->multicastAddress;
75 | broadaddr.sin_port = htons(port);
76 |
77 | if ((socketfd2 = (socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) < 0) {
78 | qCritical() << "socket: " + QString::fromUtf8(strerror(errno));
79 | return -1;
80 | }
81 |
82 | len = strlen(msg);
83 |
84 | char loopback = 1;
85 | if (setsockopt(socketfd2, IPPROTO_IP, IP_MULTICAST_LOOP, &loopback, sizeof(loopback)) < 0) {
86 | qCritical() << "setsockopt: " + QString::fromUtf8(strerror(errno));
87 | evutil_closesocket(socketfd2);
88 | return -1;
89 | }
90 |
91 | for (int i = 0; i < 1; i++) {
92 | ssize_t bytesSent =
93 | sendto(socketfd2, msg, len + 1, 0, reinterpret_cast(&broadaddr), sizeof(broadaddr));
94 | if (bytesSent < 0) {
95 | qCritical() << "sendto: " + QString::fromUtf8(strerror(errno));
96 | evutil_closesocket(socketfd2);
97 | return -1;
98 | } else if (static_cast(bytesSent) != len + 1) {
99 | qWarning().noquote() << "Partial UDP send on port" << port;
100 | return -1;
101 | }
102 | }
103 | evutil_closesocket(socketfd2);
104 | return 0;
105 | }
106 |
107 | void PXMClient::sendSingleType(QSharedPointer bw, PXMConsts::MESSAGE_TYPE type)
108 | {
109 | const unsigned int packetLen = d_ptr->localUUIDLen + sizeof(type);
110 | unsigned char packet[packetLen];
111 |
112 | memcpy(&packet[0], d_ptr->packedLocalUUID, d_ptr->localUUIDLen);
113 | uint32_t typeNBO = htonl(type);
114 | memcpy(&packet[d_ptr->localUUIDLen], &typeNBO, sizeof(typeNBO));
115 |
116 | uint16_t packetLenNBO = htons(static_cast(packetLen));
117 | bw->lockBev();
118 |
119 | if ((bw->getBev() != nullptr) && (bufferevent_get_enabled(bw->getBev()) & EV_WRITE)) {
120 | if (bufferevent_write(bw->getBev(), &packetLenNBO, sizeof(packetLenNBO)) == 0) {
121 | if (bufferevent_write(bw->getBev(), packet, packetLen) == 0) {
122 | qDebug() << "Successful Type Send";
123 | }
124 | }
125 | }
126 |
127 | bw->unlockBev();
128 | }
129 |
130 | void PXMClientPrivate::sendMsg(const QSharedPointer bw,
131 | const char* msg,
132 | const size_t msgLen,
133 | const PXMConsts::MESSAGE_TYPE type,
134 | const QUuid uuidReceiver)
135 | {
136 | int bytesSent = -1;
137 | size_t packetLen;
138 | uint16_t packetLenNBO;
139 | bool print = false;
140 |
141 | QUuid uuidLocal;
142 | NetCompression::unpackUUID(packedLocalUUID, uuidLocal);
143 | if (msgLen > 65400) {
144 | emit q_ptr->resultOfTCPSend(-1, uuidReceiver, uuidLocal, QString("Message too Long!"), print, bw);
145 | return;
146 | }
147 | packetLen = localUUIDLen + sizeof(type) + msgLen;
148 |
149 | if (type == PXMConsts::MSG_TEXT)
150 | print = true;
151 |
152 | QScopedArrayPointer full_mess(new char[packetLen + 1]);
153 |
154 | packetLenNBO = htons(static_cast(packetLen));
155 | qDebug() << ntohs(packetLenNBO);
156 | uint32_t typeNBO = htonl(type);
157 |
158 | memcpy(&full_mess[0], packedLocalUUID, localUUIDLen);
159 | memcpy(&full_mess[localUUIDLen], &typeNBO, sizeof(typeNBO));
160 | memcpy(&full_mess[localUUIDLen + sizeof(typeNBO)], msg, msgLen);
161 | full_mess[packetLen] = 0;
162 |
163 | bw->lockBev();
164 |
165 | if ((bw->getBev() == nullptr) || !(bufferevent_get_enabled(bw->getBev()) & EV_WRITE)) {
166 | msg = "Peer is Disconnected, message not sent";
167 | } else {
168 | if (bufferevent_write(bw->getBev(), &packetLenNBO, sizeof(packetLenNBO)) == 0) {
169 | if (bufferevent_write(bw->getBev(), full_mess.data(), packetLen) == 0) {
170 | qDebug() << "Successful Send";
171 | bytesSent = 0;
172 | } else {
173 | msg = "Message send failure, not sent";
174 | }
175 | } else {
176 | msg = "Message send failure, not sent";
177 | }
178 | }
179 |
180 | bw->unlockBev();
181 |
182 | if (!uuidReceiver.isNull()) {
183 | emit q_ptr->resultOfTCPSend(bytesSent, uuidReceiver, uuidLocal, QString::fromUtf8(msg), print, bw);
184 | }
185 |
186 | return;
187 | }
188 | void PXMClient::sendMsgSlot(QSharedPointer bw,
189 | QByteArray msg,
190 | size_t len,
191 | PXMConsts::MESSAGE_TYPE type,
192 | QUuid theiruuid)
193 | {
194 | QByteArray test = QByteArray::fromRawData(msg.data(), len);
195 | d_ptr->sendMsg(bw, test.constData(), len, type, theiruuid);
196 | }
197 |
--------------------------------------------------------------------------------
/include/pxmmainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef PXMWINDOW_H
2 | #define PXMWINDOW_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include "pxmconsts.h"
12 | //#include "ui_pxmmainwindow.h"
13 | #include "ui_pxmaboutdialog.h"
14 | #include "ui_pxmsettingsdialog.h"
15 |
16 | namespace PXMConsole {
17 | class Window;
18 | }
19 | namespace Ui {
20 | class PXMWindow;
21 | class PXMAboutDialog;
22 | class PXMSettingsDialog;
23 | class ManualConnect;
24 | }
25 | class QListWidgetItem;
26 |
27 | class PXMWindow : public QMainWindow {
28 | Q_OBJECT
29 |
30 | const QString selfColor = "#6495ED"; // Cornflower Blue
31 | const QString peerColor = "#FF0000"; // Red
32 | const QVector textColors = {
33 | "#808000", // Olive
34 | "#FFA500", // Orange
35 | "#FF00FF", // Fuschia
36 | "#DC143C", // Crimson
37 | "#FF69B4", // HotPink
38 | "#708090", // SlateGrey
39 | "#008000", // Green
40 | "#00FF00" // Lime
41 | };
42 | unsigned int textColorsNext;
43 | QScopedPointer ui;
44 | QAction* messSystemTrayExitAction;
45 | QMenu* sysTrayMenu;
46 | QSystemTrayIcon* sysTray;
47 | QFrame* fsep;
48 | QString localHostname;
49 | QUuid localUuid;
50 | QUuid globalChatUuid;
51 | QScopedPointer debugWindow;
52 | QTimer* textEnteredTimer;
53 | QTimer* labelTest;
54 | bool ltBool = false;
55 | /*!
56 | * \brief focusWindow
57 | *
58 | * Brings the window to the foreground if allowed by the window manager.
59 | * Plays a sound when doing this.
60 | */
61 | int focusWindow();
62 | /*!
63 | * \brief changeListColor
64 | *
65 | * Changes the color of the background for an item in a given row of the
66 | * QListWidget. Changes to either red or default.
67 | * \param row Row of item in QListWidget to change
68 | * \param style Color to change to. 1 for red, 0 for default.
69 | */
70 | int changeListItemColor(QUuid uuid, int style);
71 | /*!
72 | * \brief createTextBrowser
73 | *
74 | * Initializes the text browser where messages are displayed upon sending
75 | * or receiving.
76 | */
77 | void setupLabels();
78 | /*!
79 | * \brief createListWidget
80 | *
81 | * Initializes the QListWidget that holds the connected computers. Two
82 | * items are added, a seperator and a "Global Chat"
83 | */
84 | void initListWidget();
85 | /*!
86 | * \brief createSystemTray
87 | *
88 | * Initializes the icon and menu for a system tray if it is supported.
89 | */
90 | void createSystemTray();
91 | /*!
92 | * \brief connectGuiSignalsAndSlots
93 | *
94 | * All widget slots are connected to the respective signals here
95 | */
96 | void connectGuiSignalsAndSlots();
97 | void setupTooltips();
98 | void setupMenuBar();
99 | void setupGui();
100 | int removeBodyFormatting(QByteArray& str);
101 | void redoFontStyling();
102 |
103 | int formatMessage(QString &str, QString& hostname, QString color);
104 | public:
105 | PXMWindow(QString hostname,
106 | QSize windowSize,
107 | bool mute,
108 | bool focus, QUuid local,
109 | QUuid globalChat,
110 | QWidget* parent = nullptr);
111 | ~PXMWindow();
112 | PXMWindow(PXMWindow const&) = delete;
113 | PXMWindow& operator=(PXMWindow const&) = delete;
114 | PXMWindow& operator=(PXMWindow&&) noexcept = delete;
115 | PXMWindow(PXMWindow&&) noexcept = delete;
116 | public slots:
117 | void bloomActionsSlot();
118 | int printToTextBrowser(QSharedPointer str, QString hostname, QUuid uuid, QUuid sender, bool alert, bool fromServer, bool global);
119 | void setItalicsOnItem(QUuid uuid, bool italics);
120 | void updateListWidget(QUuid uuid, QString hostname);
121 | void typingAlert(QUuid);
122 | void textEnteredAlert(QUuid);
123 | void endOfTextEnteredAlert(QUuid);
124 | void alertFontColor(int index);
125 |
126 | protected:
127 | void closeEvent(QCloseEvent* event) Q_DECL_OVERRIDE;
128 | void changeEvent(QEvent* event) Q_DECL_OVERRIDE;
129 | private slots:
130 | int sendButtonClicked();
131 | void quitButtonClicked();
132 | void currentItemChanged(QListWidgetItem* item1, QListWidgetItem *item2);
133 | void textEditChanged();
134 | void systemTrayAction(QSystemTrayIcon::ActivationReason reason);
135 | void aboutActionSlot();
136 | void settingsActionsSlot();
137 | void debugActionSlot();
138 | void syncActionsSlot();
139 | void manualConnect();
140 | void aboutToClose();
141 | void typingHandler();
142 | void endOfTypingHandler();
143 | void textEnteredCallback();
144 | signals:
145 | void sendMsg(QByteArray, PXMConsts::MESSAGE_TYPE, QUuid);
146 | void sendUDP(const char*);
147 | void syncWithPeers();
148 | void retryDiscover();
149 | void addMessageToPeer(QString, QUuid, QUuid, bool, bool);
150 | void printInfoToDebug();
151 | void manConnect(QString, int);
152 | void typing(QUuid uuid);
153 | void endOfTextEntered(QUuid uuid);
154 | void endOfTyping(QUuid uuid);
155 | void textEntered(QUuid uuid);
156 | void fontColorChange(QColor color, bool system);
157 | };
158 |
159 | class PXMAboutDialog : public QDialog {
160 | Q_OBJECT
161 |
162 | QScopedPointer ui;
163 | QIcon icon;
164 |
165 | public:
166 | PXMAboutDialog(QWidget* parent = 0, QIcon icon = QIcon());
167 | ~PXMAboutDialog() {}
168 | };
169 |
170 | class PXMSettingsDialogPrivate;
171 | class PXMSettingsDialog : public QDialog {
172 | Q_OBJECT
173 |
174 | PXMSettingsDialogPrivate *d_ptr;
175 | QScopedPointer ui;
176 |
177 | public:
178 | PXMSettingsDialog(QWidget* parent = 0);
179 | void readIni();
180 | ~PXMSettingsDialog();
181 | private slots:
182 | void resetDefaults(QAbstractButton* button);
183 | void accept();
184 | void currentFontChanged(QFont font);
185 | void valueChanged(int size);
186 | void logStateChange(int state);
187 | void colorSchemeChange(int index);
188 | signals:
189 | void nameChange(QString);
190 | void verbosityChanged();
191 | void colorSchemeAlert();
192 | };
193 |
194 | class PXMTextEdit : public QTextEdit
195 | {
196 | Q_OBJECT
197 | public:
198 | explicit PXMTextEdit(QWidget* parent);
199 | void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
200 | signals:
201 | void returnPressed();
202 | void typing();
203 | void endOfTyping();
204 | void endOfTextEntered();
205 | public slots:
206 | void toggleItalics(bool checked);
207 | void toggleBold(bool checked);
208 | void toggleUnderline(bool checked);
209 |
210 | void fontColorChange(QColor color, bool system);
211 | protected:
212 | void focusOutEvent(QFocusEvent* event) Q_DECL_OVERRIDE;
213 | void focusInEvent(QFocusEvent* event) Q_DECL_OVERRIDE;
214 | };
215 |
216 | class ManualConnect : public QDialog
217 | {
218 | Q_OBJECT
219 | Ui::ManualConnect* ui;
220 | void accept();
221 | public:
222 | ManualConnect(QWidget *parent);
223 | ~ManualConnect();
224 | signals:
225 | void manConnect(QString, int);
226 | };
227 |
228 | #endif
229 |
--------------------------------------------------------------------------------
/src/pxmstackwidget.cpp:
--------------------------------------------------------------------------------
1 | #include "pxmstackwidget.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | using namespace PXMMessageViewer;
12 |
13 | StackedWidget::StackedWidget(QWidget* parent) : QStackedWidget(parent)
14 | {
15 | LabelWidget* lw = new LabelWidget(this, QUuid::createUuid());
16 | lw->setText("Select a friend on the right to begin chatting!");
17 | lw->setAlignment(Qt::AlignCenter);
18 | this->addWidget(lw);
19 | typingTimer = new QTimer();
20 | typingTimer->setInterval(typeTimerInterval);
21 | typingTimer->start();
22 | QObject::connect(typingTimer, &QTimer::timeout, this, &StackedWidget::timerCallback);
23 | }
24 |
25 | void StackedWidget::timerCallback()
26 | {
27 | qint64 current = QDateTime::currentMSecsSinceEpoch();
28 | for (int i = 0; i < this->count(); i++) {
29 | TextWidget* tw = dynamic_cast(this->widget(i));
30 | if (tw) {
31 | if (tw->typingTime + 500 < current) {
32 | // QString temp = tw->info->text();
33 | tw->timerCallback();
34 | } else {
35 | continue;
36 | }
37 | }
38 | }
39 | }
40 |
41 | int StackedWidget::newHistory(QUuid& uuid)
42 | {
43 | if (this->count() < 10) {
44 | TextWidget* tw = new TextWidget(this, uuid);
45 | this->addWidget(tw);
46 | } else {
47 | History newHist(uuid);
48 | history.insert(uuid, newHist);
49 | }
50 | return 0;
51 | }
52 |
53 | TextWidget* StackedWidget::getItem(QUuid& uuid)
54 | {
55 | for (int i = 0; i < this->count(); i++) {
56 | TextWidget* mvb = dynamic_cast(this->widget(i));
57 | if (mvb && mvb->getIdentifier() == uuid) {
58 | return mvb;
59 | }
60 | }
61 | return nullptr;
62 | }
63 |
64 | int StackedWidget::append(QString str, QUuid& uuid)
65 | {
66 | for (int i = 0; i < this->count(); i++) {
67 | MVBase* mvb = dynamic_cast(this->widget(i));
68 | if (mvb && mvb->getIdentifier() == uuid) {
69 | TextWidget* tw = qobject_cast(this->widget(i));
70 | if (tw) {
71 | tw->append(str);
72 | return 0;
73 | } else {
74 | return -1;
75 | }
76 | }
77 | }
78 | // not in stackwidget
79 | if (history.value(uuid).getUuid() == uuid) {
80 | history[uuid].append(str);
81 | } else {
82 | return -1;
83 | }
84 | return 0;
85 | }
86 |
87 | int StackedWidget::removeLastWidget()
88 | {
89 | if (this->count() < 10) {
90 | return 0;
91 | }
92 | QWidget* qw = this->widget(this->count() - 1);
93 | TextWidget* old = qobject_cast(qw);
94 | if (old) {
95 | History oldHist(old->getIdentifier(), old->toHtml());
96 | history.insert(oldHist.getUuid(), oldHist);
97 | } else {
98 | qWarning() << "Removing non textedit widget";
99 | }
100 | this->removeWidget(this->widget(this->count() - 1));
101 |
102 | return 0;
103 | }
104 |
105 | int StackedWidget::switchToUuid(QUuid& uuid)
106 | {
107 | for (int i = 0; i < this->count(); i++) {
108 | MVBase* mvb = dynamic_cast(this->widget(i));
109 | if (mvb->getIdentifier() == uuid) {
110 | QWidget* qw = this->widget(i);
111 | this->removeWidget(qw);
112 | this->insertWidget(0, qw);
113 | this->removeLastWidget();
114 | this->setCurrentIndex(0);
115 | return 0;
116 | }
117 | }
118 | // isnt in the list
119 | if (history.value(uuid).getUuid() == uuid) {
120 | TextWidget* tw = new TextWidget(this, uuid);
121 | tw->setHtml(history[uuid].getText());
122 | this->insertWidget(0, tw);
123 | this->setCurrentIndex(0);
124 | this->removeLastWidget();
125 | history.remove(uuid);
126 | qDebug() << "Made a new textedit" << history.count() << this->count();
127 | return 0;
128 | }
129 | return -1;
130 | }
131 |
132 | void StackedWidget::invert(QUuid uuid)
133 | {
134 | TextWidget* tw = getItem(uuid);
135 | if (tw) {
136 | tw->invert();
137 | }
138 | }
139 |
140 | LabelWidget::LabelWidget(QWidget* parent, const QUuid& uuid) : QLabel(parent), MVBase(uuid)
141 | {
142 | this->setBackgroundRole(QPalette::Base);
143 | this->setAutoFillBackground(true);
144 | this->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
145 | }
146 |
147 | void History::append(const QString& str)
148 | {
149 | text.append(str);
150 | }
151 |
152 | void TextWidget::rlabel()
153 | {
154 | int ax, ay, aw, ah;
155 | this->frameRect().getRect(&ax, &ay, &aw, &ah);
156 | info->setGeometry(this->lineWidth() + this->midLineWidth(),
157 | ah - info->height() - this->lineWidth() - this->midLineWidth(),
158 | aw - 2 * this->lineWidth() - 2 * this->midLineWidth(), info->height());
159 | QString sheet = this->styleSheet();
160 | QRegularExpression qre = QRegularExpression("(QTextBrowser { padding-bottom:)([0-9]*)(.*)");
161 | if (info->isVisible()) {
162 | sheet.replace(qre, "\\1" + QString::number(info->height()) + "\\3");
163 |
164 | this->setStyleSheet(sheet);
165 | } else {
166 | sheet.replace(qre, "\\10\\3");
167 | this->setStyleSheet(sheet);
168 | }
169 | }
170 |
171 | void TextWidget::invert()
172 | {
173 | QString sheet = this->styleSheet();
174 | QPalette pal = this->palette();
175 | QColor col = pal.base().color();
176 | int r, g, b;
177 | col.getRgb(&r, &g, &b);
178 | r = 255 - r;
179 | g = 255 - g;
180 | b = 255 - b;
181 | QRegularExpression qre =
182 | QRegularExpression("(QTextBrowser {)(.*)(background-color: rgb\\()([0-9]*),([0-9]*),([0-9]*)(.*)");
183 | sheet.replace(qre, "\\1\\2\\3" + QString::number(r) + "," + QString::number(g) + "," + QString::number(b) + "\\7");
184 | this->setStyleSheet(sheet);
185 | sheet = this->styleSheet();
186 | }
187 |
188 | TextWidget::TextWidget(QWidget* parent, const QUuid& uuid)
189 | : QTextBrowser(parent), MVBase(uuid), typing(false), textEntered(false)
190 | {
191 | this->setOpenExternalLinks(true);
192 | this->setOpenLinks(true);
193 | this->setTextInteractionFlags(Qt::TextInteractionFlag::LinksAccessibleByMouse);
194 | info = new QLineEdit(this);
195 | info->setStyleSheet(infoBarStyle);
196 | info->setVisible(false);
197 | info->setReadOnly(true);
198 | info->setFocusPolicy(Qt::FocusPolicy::NoFocus);
199 | QPalette pal = this->palette();
200 | QColor col = pal.base().color();
201 | int r, g, b;
202 | col.getRgb(&r, &g, &b);
203 | if (r == 255 && g == 255 && b == 255) {
204 | pal.setColor(QPalette::Base, pal.alternateBase().color());
205 | this->setPalette(pal);
206 | col.getRgb(&r, &g, &b);
207 | // r = 230;
208 | // g = 230;
209 | // b = 230;
210 | }
211 | setStyleSheet("QTextBrowser { padding-bottom:0; background-color: rgb(" + QString::number(r) + "," +
212 | QString::number(g) + "," + QString::number(b) + ") }");
213 | }
214 |
215 | void TextWidget::showTyping(QString hostname)
216 | {
217 | QScrollBar* scroll = this->verticalScrollBar();
218 | bool scrollMax = false;
219 | if (scroll->sliderPosition() == scroll->maximum()) {
220 | scrollMax = true;
221 | }
222 | info->setText(hostname % infoTyping);
223 | info->setVisible(true);
224 | QString sheet = this->styleSheet();
225 | QRegularExpression qre = QRegularExpression("(QTextBrowser {)(.*)(padding-bottom:)([0-9]*)(.*)");
226 | sheet.replace(qre, "\\1\\2\\3" + QString::number(info->height()) + "\\5");
227 |
228 | this->setStyleSheet(sheet);
229 | if (scrollMax) {
230 | scroll->setSliderPosition(scroll->maximum());
231 | }
232 | // typingTimer->start();
233 | typing = true;
234 | typingTime = QDateTime::currentMSecsSinceEpoch();
235 | }
236 |
237 | void TextWidget::showEntered(QString hostname)
238 | {
239 | this->textEntered = true;
240 | if (typing) {
241 | return;
242 | }
243 | QScrollBar* scroll = this->verticalScrollBar();
244 | bool scrollMax = false;
245 | if (scroll->sliderPosition() == scroll->maximum()) {
246 | scrollMax = true;
247 | }
248 | info->setText(hostname % infoEntered);
249 | info->setVisible(true);
250 | QString sheet = this->styleSheet();
251 | QRegularExpression qre = QRegularExpression("(QTextBrowser {)(.*)(padding-bottom:)([0-9]*)(.*)");
252 | sheet.replace(qre, "\\1\\2\\3" + QString::number(info->height()) + "\\5");
253 |
254 | this->setStyleSheet(sheet);
255 | if (scrollMax) {
256 | scroll->setSliderPosition(scroll->maximum());
257 | }
258 | }
259 |
260 | void TextWidget::clearInfoLine()
261 | {
262 | // typingTimer->stop();
263 | typing = false;
264 | textEntered = false;
265 | info->setVisible(false);
266 | QString sheet = this->styleSheet();
267 | QRegularExpression qre = QRegularExpression("(QTextBrowser {)(.*)(padding-bottom:)([0-9]*)(.*)");
268 | sheet.replace(qre, "\\1\\2\\30\\5");
269 |
270 | this->setStyleSheet(sheet);
271 | }
272 |
273 | void TextWidget::timerCallback()
274 | {
275 | if (textEntered) {
276 | typing = false;
277 | QString temp = info->text();
278 | if (temp.endsWith(infoTyping)) {
279 | this->showEntered(temp.left(temp.length() - infoTyping.length()));
280 | }
281 | } else {
282 | clearInfoLine();
283 | }
284 | }
285 |
286 | int PXMMessageViewer::StackedWidget::showTyping(QUuid& uuid, QString hostname)
287 | {
288 | for (int i = 0; i < this->count(); i++) {
289 | TextWidget* tw = dynamic_cast(this->widget(i));
290 | if (tw && tw->getIdentifier() == uuid) {
291 | tw->showTyping(hostname);
292 | return 0;
293 | }
294 | }
295 | return 1;
296 | }
297 |
298 | int StackedWidget::showEntered(QUuid& uuid, QString hostname)
299 | {
300 | for (int i = 0; i < this->count(); i++) {
301 | TextWidget* tw = dynamic_cast(this->widget(i));
302 | if (tw && tw->getIdentifier() == uuid) {
303 | tw->showEntered(hostname);
304 | return 0;
305 | }
306 | }
307 | return 1;
308 | }
309 | int StackedWidget::clearInfoLine(QUuid& uuid)
310 | {
311 | for (int i = 0; i < this->count(); i++) {
312 | TextWidget* tw = dynamic_cast(this->widget(i));
313 | if (tw && tw->getIdentifier() == uuid) {
314 | tw->clearInfoLine();
315 | return 0;
316 | }
317 | }
318 | return 1;
319 | }
320 |
--------------------------------------------------------------------------------
/include/QSimpleUpdater/src/Downloader.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2016 Alex Spataru
3 | *
4 | * This file is part of the QSimpleUpdater library, which is released under
5 | * the DBAD license, you can read a copy of it below:
6 | *
7 | * DON'T BE A DICK PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING,
8 | * DISTRIBUTION AND MODIFICATION:
9 | *
10 | * Do whatever you like with the original work, just don't be a dick.
11 | * Being a dick includes - but is not limited to - the following instances:
12 | *
13 | * 1a. Outright copyright infringement - Don't just copy this and change the
14 | * name.
15 | * 1b. Selling the unmodified original with no work done what-so-ever, that's
16 | * REALLY being a dick.
17 | * 1c. Modifying the original work to contain hidden harmful content.
18 | * That would make you a PROPER dick.
19 | *
20 | * If you become rich through modifications, related works/services, or
21 | * supporting the original work, share the love.
22 | * Only a dick would make loads off this work and not buy the original works
23 | * creator(s) a pint.
24 | *
25 | * Code is provided with no warranty. Using somebody else's code and bitching
26 | * when it goes wrong makes you a DONKEY dick.
27 | * Fix the problem yourself. A non-dick would submit the fix back.
28 | */
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include
39 |
40 | #include "Downloader.h"
41 |
42 | static const QString PARTIAL_DOWN(".part");
43 | static const QDir DOWNLOAD_DIR(QDir::homePath() + "/Downloads/");
44 |
45 | Downloader::Downloader(QWidget* parent) : QWidget(parent)
46 | {
47 | m_ui = new Ui::Downloader;
48 | m_ui->setupUi(this);
49 |
50 | /* Initialize private members */
51 | m_manager = new QNetworkAccessManager();
52 |
53 | /* Initialize internal values */
54 | m_url = "";
55 | m_fileName = "";
56 | m_startTime = 0;
57 | m_useCustomProcedures = false;
58 |
59 | /* Make the window look like a modal dialog */
60 | setWindowIcon(QIcon());
61 | setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
62 |
63 | /* Configure the appearance and behavior of the buttons */
64 | m_ui->openButton->setEnabled(false);
65 | m_ui->openButton->setVisible(false);
66 | connect(m_ui->stopButton, SIGNAL(clicked()), this, SLOT(cancelDownload()));
67 | connect(m_ui->openButton, SIGNAL(clicked()), this, SLOT(installUpdate()));
68 |
69 | /* Resize to fit */
70 | setFixedSize(minimumSizeHint());
71 | }
72 |
73 | Downloader::~Downloader()
74 | {
75 | delete m_ui;
76 | delete m_reply;
77 | delete m_manager;
78 | }
79 |
80 | /**
81 | * Returns \c true if the updater shall not intervene when the download has
82 | * finished (you can use the \c QSimpleUpdater signals to know when the
83 | * download is completed).
84 | */
85 | bool Downloader::useCustomInstallProcedures() const
86 | {
87 | return m_useCustomProcedures;
88 | }
89 |
90 | /**
91 | * Changes the URL, which is used to indentify the downloader dialog
92 | * with an \c Updater instance
93 | *
94 | * \note the \a url parameter is not the download URL, it is the URL of
95 | * the AppCast file
96 | */
97 | void Downloader::setUrlId(const QString& url)
98 | {
99 | m_url = url;
100 | }
101 |
102 | /**
103 | * Begins downloading the file at the given \a url
104 | */
105 | void Downloader::startDownload(const QUrl& url)
106 | {
107 | /* Reset UI */
108 | m_ui->progressBar->setValue(0);
109 | m_ui->stopButton->setText(tr("Stop"));
110 | m_ui->downloadLabel->setText(tr("Downloading updates"));
111 | m_ui->timeLabel->setText(tr("Time remaining") + ": " + tr("unknown"));
112 |
113 | /* Start download */
114 | m_startTime = QDateTime::currentDateTime().toTime_t();
115 | m_reply = m_manager->get(QNetworkRequest(url));
116 |
117 | /* Ensure that downloads directory exists */
118 | if (!DOWNLOAD_DIR.exists())
119 | DOWNLOAD_DIR.mkpath(".");
120 |
121 | /* Remove old downloads */
122 | QFile::remove(DOWNLOAD_DIR.filePath(m_fileName));
123 | QFile::remove(DOWNLOAD_DIR.filePath(m_fileName + PARTIAL_DOWN));
124 |
125 | /* Update UI when download progress changes or download finishes */
126 | connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateProgress(qint64, qint64)));
127 | connect(m_reply, SIGNAL(redirected(QUrl)), this, SLOT(startDownload(QUrl)));
128 |
129 | showNormal();
130 | }
131 |
132 | /**
133 | * Changes the name of the downloaded file
134 | */
135 | void Downloader::setFileName(const QString& file)
136 | {
137 | m_fileName = file;
138 |
139 | if (m_fileName.isEmpty())
140 | m_fileName = "QSU_Update.bin";
141 | }
142 |
143 | /**
144 | * Opens the downloaded file.
145 | * \note If the downloaded file is not found, then the function will alert the
146 | * user about the error.
147 | */
148 | void Downloader::openDownload()
149 | {
150 | if (!m_fileName.isEmpty()) {
151 | QDesktopServices::openUrl(QUrl::fromLocalFile(DOWNLOAD_DIR.filePath(m_fileName)));
152 | emit installerOpened();
153 |
154 | } else {
155 | QMessageBox::critical(this, tr("Error"), tr("Cannot find downloaded update!"), QMessageBox::Close);
156 | }
157 | }
158 |
159 | /**
160 | * Instructs the OS to open the downloaded file.
161 | *
162 | * \note If \c useCustomInstallProcedures() returns \c true, the function will
163 | * not instruct the OS to open the downloaded file. You can use the
164 | * signals fired by the \c QSimpleUpdater to install the update with your
165 | * own implementations/code.
166 | */
167 | void Downloader::installUpdate()
168 | {
169 | if (useCustomInstallProcedures())
170 | return;
171 |
172 | /* Update labels */
173 | m_ui->stopButton->setText(tr("Close"));
174 | m_ui->downloadLabel->setText(tr("Download complete!"));
175 | m_ui->timeLabel->setText(tr("The installer will open separately") + "...");
176 |
177 | /* Ask the user to install the download */
178 | QMessageBox box;
179 | box.setIcon(QMessageBox::Question);
180 | box.setDefaultButton(QMessageBox::Ok);
181 | box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
182 | box.setInformativeText(tr("Click \"OK\" to begin installing the update"));
183 | box.setText("" + tr("In order to install the update, you may need to "
184 | "quit the application.") +
185 | "
");
186 |
187 | /* User wants to install the download */
188 | if (box.exec() == QMessageBox::Ok) {
189 | if (!useCustomInstallProcedures())
190 | openDownload();
191 | }
192 |
193 | /* Wait */
194 | else {
195 | m_ui->openButton->setEnabled(true);
196 | m_ui->openButton->setVisible(true);
197 | m_ui->timeLabel->setText(
198 | tr("Click the \"Open\" button to "
199 | "apply the update"));
200 | }
201 | }
202 |
203 | /**
204 | * Prompts the user if he/she wants to cancel the download and cancels the
205 | * download if the user agrees to do that.
206 | */
207 | void Downloader::cancelDownload()
208 | {
209 | if (!m_reply->isFinished()) {
210 | QMessageBox box;
211 | box.setWindowTitle(tr("Updater"));
212 | box.setIcon(QMessageBox::Question);
213 | box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
214 | box.setText(tr("Are you sure you want to cancel the download?"));
215 |
216 | if (box.exec() == QMessageBox::Yes) {
217 | hide();
218 | m_reply->abort();
219 | emit downloadCanceled();
220 | }
221 | }
222 |
223 | else
224 | hide();
225 | }
226 |
227 | /**
228 | * Writes the downloaded data to the disk
229 | */
230 | void Downloader::saveFile(qint64 received, qint64 total)
231 | {
232 | /* Check if we need to redirect */
233 | QUrl url = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
234 | if (!url.isEmpty()) {
235 | startDownload(url);
236 | return;
237 | }
238 |
239 | /* Save downloaded data to disk */
240 | QFile file(DOWNLOAD_DIR.filePath(m_fileName + PARTIAL_DOWN));
241 | if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
242 | file.write(m_reply->readAll());
243 | file.close();
244 | }
245 |
246 | /* Open downloaded update */
247 | if (received >= total && total > 0) {
248 | /* Rename file */
249 | QFile::rename(DOWNLOAD_DIR.filePath(m_fileName + PARTIAL_DOWN), DOWNLOAD_DIR.filePath(m_fileName));
250 |
251 | /* Notify application */
252 | emit downloadFinished(m_url, DOWNLOAD_DIR.filePath(m_fileName));
253 |
254 | /* Install the update */
255 | m_reply->close();
256 | installUpdate();
257 | }
258 | }
259 |
260 | /**
261 | * Calculates the appropiate size units (bytes, KB or MB) for the received
262 | * data and the total download size. Then, this function proceeds to update the
263 | * dialog controls/UI.
264 | */
265 | void Downloader::calculateSizes(qint64 received, qint64 total)
266 | {
267 | QString totalSize;
268 | QString receivedSize;
269 |
270 | if (total < 1024)
271 | totalSize = tr("%1 bytes").arg(total);
272 |
273 | else if (total < 1048576)
274 | totalSize = tr("%1 KB").arg(round(total / 1024));
275 |
276 | else
277 | totalSize = tr("%1 MB").arg(round(total / 1048576));
278 |
279 | if (received < 1024)
280 | receivedSize = tr("%1 bytes").arg(received);
281 |
282 | else if (received < 1048576)
283 | receivedSize = tr("%1 KB").arg(received / 1024);
284 |
285 | else
286 | receivedSize = tr("%1 MB").arg(received / 1048576);
287 |
288 | m_ui->downloadLabel->setText(tr("Downloading updates") + " (" + receivedSize + " " + tr("of") + " " + totalSize +
289 | ")");
290 | }
291 |
292 | /**
293 | * Uses the \a received and \a total parameters to get the download progress
294 | * and update the progressbar value on the dialog.
295 | */
296 | void Downloader::updateProgress(qint64 received, qint64 total)
297 | {
298 | if (total > 0) {
299 | m_ui->progressBar->setMinimum(0);
300 | m_ui->progressBar->setMaximum(100);
301 | m_ui->progressBar->setValue((received * 100) / total);
302 |
303 | calculateSizes(received, total);
304 | calculateTimeRemaining(received, total);
305 | saveFile(received, total);
306 | }
307 |
308 | else {
309 | m_ui->progressBar->setMinimum(0);
310 | m_ui->progressBar->setMaximum(0);
311 | m_ui->progressBar->setValue(-1);
312 | m_ui->downloadLabel->setText(tr("Downloading Updates") + "...");
313 | m_ui->timeLabel->setText(QString("%1: %2").arg(tr("Time Remaining")).arg(tr("Unknown")));
314 | }
315 | }
316 |
317 | /**
318 | * Uses two time samples (from the current time and a previous sample) to
319 | * calculate how many bytes have been downloaded.
320 | *
321 | * Then, this function proceeds to calculate the appropiate units of time
322 | * (hours, minutes or seconds) and constructs a user-friendly string, which
323 | * is displayed in the dialog.
324 | */
325 | void Downloader::calculateTimeRemaining(qint64 received, qint64 total)
326 | {
327 | uint difference = QDateTime::currentDateTime().toTime_t() - m_startTime;
328 |
329 | if (difference > 0) {
330 | QString timeString;
331 | qreal timeRemaining = total / (received / difference);
332 |
333 | if (timeRemaining > 7200) {
334 | timeRemaining /= 3600;
335 | int hours = int(timeRemaining + 0.5);
336 |
337 | if (hours > 1)
338 | timeString = tr("about %1 hours").arg(hours);
339 | else
340 | timeString = tr("about one hour");
341 | }
342 |
343 | else if (timeRemaining > 60) {
344 | timeRemaining /= 60;
345 | int minutes = int(timeRemaining + 0.5);
346 |
347 | if (minutes > 1)
348 | timeString = tr("%1 minutes").arg(minutes);
349 | else
350 | timeString = tr("1 minute");
351 | }
352 |
353 | else if (timeRemaining <= 60) {
354 | int seconds = int(timeRemaining + 0.5);
355 |
356 | if (seconds > 1)
357 | timeString = tr("%1 seconds").arg(seconds);
358 | else
359 | timeString = tr("1 second");
360 | }
361 |
362 | m_ui->timeLabel->setText(tr("Time remaining") + ": " + timeString);
363 | }
364 | }
365 |
366 | /**
367 | * Rounds the given \a input to two decimal places
368 | */
369 | qreal Downloader::round(const qreal& input)
370 | {
371 | return roundf(input * 100) / 100;
372 | }
373 |
374 | /**
375 | * If the \a custom parameter is set to \c true, then the \c Downloader will not
376 | * attempt to open the downloaded file.
377 | *
378 | * Use the signals fired by the \c QSimpleUpdater to implement your own install
379 | * procedures.
380 | */
381 | void Downloader::setUseCustomInstallProcedures(const bool custom)
382 | {
383 | m_useCustomProcedures = custom;
384 | }
385 |
--------------------------------------------------------------------------------
/src/pxmagent.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #ifdef _WIN32
4 | #include
5 | #include
6 |
7 | #ifdef _WIN64
8 | const char* modName = "windows64";
9 | const char* arch = "x86_64";
10 | #else
11 | const char* modName = "windows32";
12 | const char* arch = "x86";
13 | #endif
14 |
15 | #elif __unix__
16 | #include
17 | #include
18 | #include
19 | #else
20 | #error "include headers for querying username"
21 | #endif
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 | Q_DECLARE_METATYPE(QSharedPointer)
45 |
46 | QPalette PXMAgent::defaultPalette;
47 |
48 | struct initialSettings {
49 | QUuid uuid;
50 | QSize windowSize;
51 | QString username;
52 | QString multicast;
53 | unsigned int uuidNum;
54 | unsigned short tcpPort;
55 | unsigned short udpPort;
56 | bool mute;
57 | bool preventFocus;
58 | bool darkColor;
59 | initialSettings()
60 | : uuid(QUuid()),
61 | windowSize(QSize(800, 600)),
62 | username(QString()),
63 | multicast(QString()),
64 | uuidNum(0),
65 | tcpPort(0),
66 | udpPort(0),
67 | mute(false),
68 | preventFocus(false),
69 | darkColor(false)
70 | {
71 | }
72 | };
73 |
74 | class PXMAgentPrivate
75 | {
76 | public:
77 | PXMAgentPrivate() {}
78 | ~PXMAgentPrivate()
79 | {
80 | if (workerThread) {
81 | workerThread->quit();
82 | workerThread->wait(3000);
83 | qInfo() << "Shutdown of WorkerThread";
84 | }
85 |
86 | iniReader.resetUUID(presets.uuidNum, presets.uuid);
87 | }
88 |
89 | QScopedPointer window;
90 | PXMPeerWorker* peerWorker;
91 | PXMIniReader iniReader;
92 | PXMConsole::Logger* logger;
93 | QScopedPointer lockFile;
94 | QString address = "https://raw.githubusercontent.com/cbpeckles/PXMessenger/master/resources/updates.json";
95 |
96 | initialSettings presets;
97 |
98 | #ifdef __WIN32
99 | QSimpleUpdater* qupdater;
100 | #endif
101 | QThread* workerThread = nullptr;
102 | // Functions
103 | QByteArray getUsername();
104 | int setupHostname(const unsigned int uuidNum, QString& username);
105 | };
106 |
107 | PXMAgent::PXMAgent(QObject* parent) : QObject(parent), d_ptr(new PXMAgentPrivate)
108 | {
109 | PXMAgent::defaultPalette = QGuiApplication::palette();
110 | }
111 |
112 | PXMAgent::~PXMAgent()
113 | {
114 | }
115 |
116 | void PXMAgent::changeToDark()
117 | {
118 | qApp->setStyle(QStyleFactory::create("Fusion"));
119 |
120 | QPalette palette;
121 | palette.setColor(QPalette::Window, QColor(53, 53, 53));
122 | palette.setColor(QPalette::WindowText, Qt::white);
123 | palette.setColor(QPalette::Base, QColor(35, 35, 35));
124 | palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
125 | palette.setColor(QPalette::ToolTipBase, Qt::white);
126 | palette.setColor(QPalette::ToolTipText, Qt::white);
127 | palette.setColor(QPalette::Text, Qt::white);
128 | palette.setColor(QPalette::Button, QColor(53, 53, 53));
129 | palette.setColor(QPalette::ButtonText, Qt::white);
130 | palette.setColor(QPalette::BrightText, Qt::red);
131 |
132 | palette.setColor(QPalette::Highlight, QColor(142, 45, 197).lighter());
133 | palette.setColor(QPalette::HighlightedText, Qt::black);
134 | qApp->setPalette(palette);
135 | }
136 |
137 | int PXMAgent::init()
138 | {
139 | QThread::currentThread()->setObjectName("MainThread");
140 | #ifdef __WIN32
141 | if(d_ptr->iniReader.getUpdates())
142 | {
143 | d_ptr->qupdater = QSimpleUpdater::getInstance();
144 | connect(d_ptr->qupdater, SIGNAL(checkingFinished(QString)), this, SLOT(doneChkUpdt(QString)));
145 | connect(d_ptr->qupdater, &QSimpleUpdater::installerOpened, qApp, &QApplication::quit);
146 | connect(d_ptr->qupdater, &QSimpleUpdater::updateDeclined, this, &PXMAgent::postInit);
147 | d_ptr->qupdater->setModuleVersion(d_ptr->address, qApp->applicationVersion());
148 | d_ptr->qupdater->setModuleName(d_ptr->address, modName);
149 | d_ptr->qupdater->setNotifyOnUpdate(d_ptr->address, true);
150 | d_ptr->qupdater->checkForUpdates(d_ptr->address);
151 | }
152 | else
153 | {
154 | postInit();
155 | }
156 | #else
157 | this->postInit();
158 | #endif
159 | return 0;
160 | }
161 |
162 | int PXMAgent::postInit()
163 | {
164 | #ifndef QT_DEBUG
165 | QImage splashImage(":/resources/PXMessenger_wBackground.png");
166 | QSplashScreen splash(QPixmap::fromImage(splashImage));
167 | splash.show();
168 | QElapsedTimer startupTimer;
169 | startupTimer.start();
170 | qApp->processEvents();
171 | #endif
172 |
173 | #ifdef _WIN32
174 | try {
175 | WSADATA wsa;
176 | if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
177 | qCritical() << "Failed WSAStartup error:" << WSAGetLastError();
178 | throw(&"Failed WSAStartup error: "[WSAGetLastError()]);
179 | }
180 | } catch (const char* msg) {
181 | QMessageBox msgBox(QMessageBox::Critical, "WSAStartup Error", QString::fromUtf8(msg));
182 | msgBox.exec();
183 | emit alreadyRunning();
184 | return -1;
185 | }
186 |
187 | qRegisterMetaType("intptr_t");
188 | #endif
189 | qRegisterMetaType();
190 | qRegisterMetaType("size_t");
191 | qRegisterMetaType();
192 | qRegisterMetaType();
193 | qRegisterMetaType>();
194 | qRegisterMetaType