Commit 210d2652ba1b511557ec5065768a02e10d0c7376

Authored by Steven de Ridder
0 parents

Initial commit.

.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +build/
  2 +CMakeLists.txt.user
CMakeLists.txt 0 → 100644
  1 +++ a/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +
  3 +# Check to see where cmake is located.
  4 +if( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake )
  5 + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
  6 +elseif( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../cmake )
  7 + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  8 +else()
  9 + return()
  10 +endif()
  11 +
  12 +# Check to see if there is versioning information available
  13 +if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/osdev_versioning/cmake)
  14 + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/osdev_versioning/cmake)
  15 + include(osdevversion)
  16 +endif()
  17 +
  18 +include(projectheader)
  19 +project_header(osdev_qt-mqtt)
  20 +
  21 +add_subdirectory(src)
  22 +add_subdirectory(tests)
  23 +
  24 +# include(packaging)
  25 +# package_component()
README.md 0 → 100644
  1 +++ a/README.md
src/CMakeLists.txt 0 → 100644
  1 +++ a/src/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +LIST( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  3 +include(projectheader)
  4 +project_header(qmqtt)
  5 +
  6 +option( ${PROJECT_NAME}_SHARED "Build a shared library. Turn off for static." ON )
  7 +option( ${PROJECT_NAME}_WEBSOCKETS "Enable WebSockets for MQTT" OFF )
  8 +option( ${PROJECT_NAME}_SSL "Enable SSL support for MQTT" OFF )
  9 +
  10 +set( ws_component )
  11 +set( ws_libname )
  12 +set( qt5_min_version "5.3.0" )
  13 +
  14 +if ( ${PROJECT_NAME}_WEBSOCKETS )
  15 + set( ws_component WebSockets )
  16 + set( ws_libname Qt5::WebSockets )
  17 + set( qt5_min_version "5.7.0" )
  18 +endif()
  19 +
  20 +if ( NOT ${PROJECT_NAME}_SSL)
  21 + set( ssl_defs QT_NO_SSL )
  22 +endif()
  23 +
  24 +find_package( Qt5 ${qt5_min_version} COMPONENTS Core Network ${ws_component} CONFIG REQUIRED )
  25 +
  26 +include_directories( SYSTEM
  27 + ${Qt5Core_INCLUDE_DIRS}
  28 + ${Qt5Network_INCLUDE_DIRS}
  29 + ${Qt5WebSockets_INCLUDE_DIRS}
  30 + ${CMAKE_CURRENT_SOURCE_DIR}/../logutils
  31 +)
  32 +
  33 +# include(compiler)
  34 +
  35 +set( SRC_LIST
  36 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt.cpp
  37 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_states.h
  38 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_configsettings.cpp
  39 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_pubsubclient.cpp
  40 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_client_p.cpp
  41 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_client.cpp
  42 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_frame.cpp
  43 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_message.cpp
  44 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_network.cpp
  45 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_routesubscription.cpp
  46 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_router.cpp
  47 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_socket.cpp
  48 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_timer.cpp
  49 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_websocket.cpp
  50 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_websocketiodevice.cpp
  51 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_ssl_socket.cpp
  52 +)
  53 +
  54 +include(qtmoc)
  55 +create_mocs( SRC_LIST MOC_LIST
  56 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt.h
  57 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_client.h
  58 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_pubsubclient.h
  59 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_routesubscription.h
  60 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_router.h
  61 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_networkinterface.h
  62 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_socketinterface.h
  63 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_timerinterface.h
  64 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_network_p.h
  65 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_socket_p.h
  66 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_timer_p.h
  67 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_websocket_p.h
  68 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_websocketiodevice_p.h
  69 + ${CMAKE_CURRENT_SOURCE_DIR}/qmqtt_ssl_socket_p.h
  70 +)
  71 +
  72 +link_directories(
  73 + ${CMAKE_BINARY_DIR}/lib
  74 +)
  75 +
  76 +include(library)
  77 +add_libraries(
  78 + ${Qt5Core_LIBRARIES}
  79 + ${Qt5Network_LIBRARIES}
  80 + ${Qt5WebSocket_LIBRARIES}
  81 + logutils
  82 +)
  83 +
  84 +include(installation)
  85 +install_component()
src/Doxyfile 0 → 100644
  1 +++ a/src/Doxyfile
  1 +# Doxyfile 1.8.15
  2 +
  3 +# This file describes the settings to be used by the documentation system
  4 +# doxygen (www.doxygen.org) for a project.
  5 +#
  6 +# All text after a double hash (##) is considered a comment and is placed in
  7 +# front of the TAG it is preceding.
  8 +#
  9 +# All text after a single hash (#) is considered a comment and will be ignored.
  10 +# The format is:
  11 +# TAG = value [value, ...]
  12 +# For lists, items can also be appended using:
  13 +# TAG += value [value, ...]
  14 +# Values that contain spaces should be placed between quotes (\" \").
  15 +
  16 +#---------------------------------------------------------------------------
  17 +# Project related configuration options
  18 +#---------------------------------------------------------------------------
  19 +
  20 +# This tag specifies the encoding used for all characters in the configuration
  21 +# file that follow. The default is UTF-8 which is also the encoding used for all
  22 +# text before the first occurrence of this tag. Doxygen uses libiconv (or the
  23 +# iconv built into libc) for the transcoding. See
  24 +# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
  25 +# The default value is: UTF-8.
  26 +
  27 +DOXYFILE_ENCODING = UTF-8
  28 +
  29 +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
  30 +# double-quotes, unless you are using Doxywizard) that should identify the
  31 +# project for which the documentation is generated. This name is used in the
  32 +# title of most generated pages and in a few other places.
  33 +# The default value is: My Project.
  34 +
  35 +PROJECT_NAME = QMQTT
  36 +
  37 +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
  38 +# could be handy for archiving the generated documentation or if some version
  39 +# control system is used.
  40 +
  41 +PROJECT_NUMBER =
  42 +
  43 +# Using the PROJECT_BRIEF tag one can provide an optional one line description
  44 +# for a project that appears at the top of each page and should give viewer a
  45 +# quick idea about the purpose of the project. Keep the description short.
  46 +
  47 +PROJECT_BRIEF =
  48 +
  49 +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
  50 +# in the documentation. The maximum height of the logo should not exceed 55
  51 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
  52 +# the logo to the output directory.
  53 +
  54 +PROJECT_LOGO =
  55 +
  56 +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
  57 +# into which the generated documentation will be written. If a relative path is
  58 +# entered, it will be relative to the location where doxygen was started. If
  59 +# left blank the current directory will be used.
  60 +
  61 +OUTPUT_DIRECTORY = /home/pgroen/projects/osdev_components/Documentation
  62 +
  63 +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
  64 +# directories (in 2 levels) under the output directory of each output format and
  65 +# will distribute the generated files over these directories. Enabling this
  66 +# option can be useful when feeding doxygen a huge amount of source files, where
  67 +# putting all generated files in the same directory would otherwise causes
  68 +# performance problems for the file system.
  69 +# The default value is: NO.
  70 +
  71 +CREATE_SUBDIRS = NO
  72 +
  73 +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
  74 +# characters to appear in the names of generated files. If set to NO, non-ASCII
  75 +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
  76 +# U+3044.
  77 +# The default value is: NO.
  78 +
  79 +ALLOW_UNICODE_NAMES = NO
  80 +
  81 +# The OUTPUT_LANGUAGE tag is used to specify the language in which all
  82 +# documentation generated by doxygen is written. Doxygen will use this
  83 +# information to generate all constant output in the proper language.
  84 +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
  85 +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
  86 +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
  87 +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
  88 +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
  89 +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
  90 +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
  91 +# Ukrainian and Vietnamese.
  92 +# The default value is: English.
  93 +
  94 +OUTPUT_LANGUAGE = English
  95 +
  96 +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
  97 +# documentation generated by doxygen is written. Doxygen will use this
  98 +# information to generate all generated output in the proper direction.
  99 +# Possible values are: None, LTR, RTL and Context.
  100 +# The default value is: None.
  101 +
  102 +OUTPUT_TEXT_DIRECTION = None
  103 +
  104 +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
  105 +# descriptions after the members that are listed in the file and class
  106 +# documentation (similar to Javadoc). Set to NO to disable this.
  107 +# The default value is: YES.
  108 +
  109 +BRIEF_MEMBER_DESC = YES
  110 +
  111 +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
  112 +# description of a member or function before the detailed description
  113 +#
  114 +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
  115 +# brief descriptions will be completely suppressed.
  116 +# The default value is: YES.
  117 +
  118 +REPEAT_BRIEF = YES
  119 +
  120 +# This tag implements a quasi-intelligent brief description abbreviator that is
  121 +# used to form the text in various listings. Each string in this list, if found
  122 +# as the leading text of the brief description, will be stripped from the text
  123 +# and the result, after processing the whole list, is used as the annotated
  124 +# text. Otherwise, the brief description is used as-is. If left blank, the
  125 +# following values are used ($name is automatically replaced with the name of
  126 +# the entity):The $name class, The $name widget, The $name file, is, provides,
  127 +# specifies, contains, represents, a, an and the.
  128 +
  129 +ABBREVIATE_BRIEF = "The $name class" \
  130 + "The $name widget" \
  131 + "The $name file" \
  132 + is \
  133 + provides \
  134 + specifies \
  135 + contains \
  136 + represents \
  137 + a \
  138 + an \
  139 + the
  140 +
  141 +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
  142 +# doxygen will generate a detailed section even if there is only a brief
  143 +# description.
  144 +# The default value is: NO.
  145 +
  146 +ALWAYS_DETAILED_SEC = NO
  147 +
  148 +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
  149 +# inherited members of a class in the documentation of that class as if those
  150 +# members were ordinary class members. Constructors, destructors and assignment
  151 +# operators of the base classes will not be shown.
  152 +# The default value is: NO.
  153 +
  154 +INLINE_INHERITED_MEMB = NO
  155 +
  156 +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
  157 +# before files name in the file list and in the header files. If set to NO the
  158 +# shortest path that makes the file name unique will be used
  159 +# The default value is: YES.
  160 +
  161 +FULL_PATH_NAMES = YES
  162 +
  163 +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
  164 +# Stripping is only done if one of the specified strings matches the left-hand
  165 +# part of the path. The tag can be used to show relative paths in the file list.
  166 +# If left blank the directory from which doxygen is run is used as the path to
  167 +# strip.
  168 +#
  169 +# Note that you can specify absolute paths here, but also relative paths, which
  170 +# will be relative from the directory where doxygen is started.
  171 +# This tag requires that the tag FULL_PATH_NAMES is set to YES.
  172 +
  173 +STRIP_FROM_PATH =
  174 +
  175 +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
  176 +# path mentioned in the documentation of a class, which tells the reader which
  177 +# header file to include in order to use a class. If left blank only the name of
  178 +# the header file containing the class definition is used. Otherwise one should
  179 +# specify the list of include paths that are normally passed to the compiler
  180 +# using the -I flag.
  181 +
  182 +STRIP_FROM_INC_PATH =
  183 +
  184 +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
  185 +# less readable) file names. This can be useful is your file systems doesn't
  186 +# support long names like on DOS, Mac, or CD-ROM.
  187 +# The default value is: NO.
  188 +
  189 +SHORT_NAMES = NO
  190 +
  191 +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
  192 +# first line (until the first dot) of a Javadoc-style comment as the brief
  193 +# description. If set to NO, the Javadoc-style will behave just like regular Qt-
  194 +# style comments (thus requiring an explicit @brief command for a brief
  195 +# description.)
  196 +# The default value is: NO.
  197 +
  198 +JAVADOC_AUTOBRIEF = NO
  199 +
  200 +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
  201 +# line (until the first dot) of a Qt-style comment as the brief description. If
  202 +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
  203 +# requiring an explicit \brief command for a brief description.)
  204 +# The default value is: NO.
  205 +
  206 +QT_AUTOBRIEF = NO
  207 +
  208 +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
  209 +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
  210 +# a brief description. This used to be the default behavior. The new default is
  211 +# to treat a multi-line C++ comment block as a detailed description. Set this
  212 +# tag to YES if you prefer the old behavior instead.
  213 +#
  214 +# Note that setting this tag to YES also means that rational rose comments are
  215 +# not recognized any more.
  216 +# The default value is: NO.
  217 +
  218 +MULTILINE_CPP_IS_BRIEF = NO
  219 +
  220 +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
  221 +# documentation from any documented member that it re-implements.
  222 +# The default value is: YES.
  223 +
  224 +INHERIT_DOCS = YES
  225 +
  226 +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
  227 +# page for each member. If set to NO, the documentation of a member will be part
  228 +# of the file/class/namespace that contains it.
  229 +# The default value is: NO.
  230 +
  231 +SEPARATE_MEMBER_PAGES = NO
  232 +
  233 +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
  234 +# uses this value to replace tabs by spaces in code fragments.
  235 +# Minimum value: 1, maximum value: 16, default value: 4.
  236 +
  237 +TAB_SIZE = 4
  238 +
  239 +# This tag can be used to specify a number of aliases that act as commands in
  240 +# the documentation. An alias has the form:
  241 +# name=value
  242 +# For example adding
  243 +# "sideeffect=@par Side Effects:\n"
  244 +# will allow you to put the command \sideeffect (or @sideeffect) in the
  245 +# documentation, which will result in a user-defined paragraph with heading
  246 +# "Side Effects:". You can put \n's in the value part of an alias to insert
  247 +# newlines (in the resulting output). You can put ^^ in the value part of an
  248 +# alias to insert a newline as if a physical newline was in the original file.
  249 +# When you need a literal { or } or , in the value part of an alias you have to
  250 +# escape them by means of a backslash (\), this can lead to conflicts with the
  251 +# commands \{ and \} for these it is advised to use the version @{ and @} or use
  252 +# a double escape (\\{ and \\})
  253 +
  254 +ALIASES =
  255 +
  256 +# This tag can be used to specify a number of word-keyword mappings (TCL only).
  257 +# A mapping has the form "name=value". For example adding "class=itcl::class"
  258 +# will allow you to use the command class in the itcl::class meaning.
  259 +
  260 +TCL_SUBST =
  261 +
  262 +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
  263 +# only. Doxygen will then generate output that is more tailored for C. For
  264 +# instance, some of the names that are used will be different. The list of all
  265 +# members will be omitted, etc.
  266 +# The default value is: NO.
  267 +
  268 +OPTIMIZE_OUTPUT_FOR_C = NO
  269 +
  270 +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
  271 +# Python sources only. Doxygen will then generate output that is more tailored
  272 +# for that language. For instance, namespaces will be presented as packages,
  273 +# qualified scopes will look different, etc.
  274 +# The default value is: NO.
  275 +
  276 +OPTIMIZE_OUTPUT_JAVA = NO
  277 +
  278 +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
  279 +# sources. Doxygen will then generate output that is tailored for Fortran.
  280 +# The default value is: NO.
  281 +
  282 +OPTIMIZE_FOR_FORTRAN = NO
  283 +
  284 +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
  285 +# sources. Doxygen will then generate output that is tailored for VHDL.
  286 +# The default value is: NO.
  287 +
  288 +OPTIMIZE_OUTPUT_VHDL = NO
  289 +
  290 +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
  291 +# sources only. Doxygen will then generate output that is more tailored for that
  292 +# language. For instance, namespaces will be presented as modules, types will be
  293 +# separated into more groups, etc.
  294 +# The default value is: NO.
  295 +
  296 +OPTIMIZE_OUTPUT_SLICE = NO
  297 +
  298 +# Doxygen selects the parser to use depending on the extension of the files it
  299 +# parses. With this tag you can assign which parser to use for a given
  300 +# extension. Doxygen has a built-in mapping, but you can override or extend it
  301 +# using this tag. The format is ext=language, where ext is a file extension, and
  302 +# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
  303 +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
  304 +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
  305 +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
  306 +# tries to guess whether the code is fixed or free formatted code, this is the
  307 +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
  308 +# .inc files as Fortran files (default is PHP), and .f files as C (default is
  309 +# Fortran), use: inc=Fortran f=C.
  310 +#
  311 +# Note: For files without extension you can use no_extension as a placeholder.
  312 +#
  313 +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
  314 +# the files are not read by doxygen.
  315 +
  316 +EXTENSION_MAPPING =
  317 +
  318 +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
  319 +# according to the Markdown format, which allows for more readable
  320 +# documentation. See https://daringfireball.net/projects/markdown/ for details.
  321 +# The output of markdown processing is further processed by doxygen, so you can
  322 +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
  323 +# case of backward compatibilities issues.
  324 +# The default value is: YES.
  325 +
  326 +MARKDOWN_SUPPORT = YES
  327 +
  328 +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
  329 +# to that level are automatically included in the table of contents, even if
  330 +# they do not have an id attribute.
  331 +# Note: This feature currently applies only to Markdown headings.
  332 +# Minimum value: 0, maximum value: 99, default value: 0.
  333 +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
  334 +
  335 +TOC_INCLUDE_HEADINGS = 0
  336 +
  337 +# When enabled doxygen tries to link words that correspond to documented
  338 +# classes, or namespaces to their corresponding documentation. Such a link can
  339 +# be prevented in individual cases by putting a % sign in front of the word or
  340 +# globally by setting AUTOLINK_SUPPORT to NO.
  341 +# The default value is: YES.
  342 +
  343 +AUTOLINK_SUPPORT = YES
  344 +
  345 +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
  346 +# to include (a tag file for) the STL sources as input, then you should set this
  347 +# tag to YES in order to let doxygen match functions declarations and
  348 +# definitions whose arguments contain STL classes (e.g. func(std::string);
  349 +# versus func(std::string) {}). This also make the inheritance and collaboration
  350 +# diagrams that involve STL classes more complete and accurate.
  351 +# The default value is: NO.
  352 +
  353 +BUILTIN_STL_SUPPORT = NO
  354 +
  355 +# If you use Microsoft's C++/CLI language, you should set this option to YES to
  356 +# enable parsing support.
  357 +# The default value is: NO.
  358 +
  359 +CPP_CLI_SUPPORT = NO
  360 +
  361 +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
  362 +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
  363 +# will parse them like normal C++ but will assume all classes use public instead
  364 +# of private inheritance when no explicit protection keyword is present.
  365 +# The default value is: NO.
  366 +
  367 +SIP_SUPPORT = NO
  368 +
  369 +# For Microsoft's IDL there are propget and propput attributes to indicate
  370 +# getter and setter methods for a property. Setting this option to YES will make
  371 +# doxygen to replace the get and set methods by a property in the documentation.
  372 +# This will only work if the methods are indeed getting or setting a simple
  373 +# type. If this is not the case, or you want to show the methods anyway, you
  374 +# should set this option to NO.
  375 +# The default value is: YES.
  376 +
  377 +IDL_PROPERTY_SUPPORT = YES
  378 +
  379 +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
  380 +# tag is set to YES then doxygen will reuse the documentation of the first
  381 +# member in the group (if any) for the other members of the group. By default
  382 +# all members of a group must be documented explicitly.
  383 +# The default value is: NO.
  384 +
  385 +DISTRIBUTE_GROUP_DOC = NO
  386 +
  387 +# If one adds a struct or class to a group and this option is enabled, then also
  388 +# any nested class or struct is added to the same group. By default this option
  389 +# is disabled and one has to add nested compounds explicitly via \ingroup.
  390 +# The default value is: NO.
  391 +
  392 +GROUP_NESTED_COMPOUNDS = NO
  393 +
  394 +# Set the SUBGROUPING tag to YES to allow class member groups of the same type
  395 +# (for instance a group of public functions) to be put as a subgroup of that
  396 +# type (e.g. under the Public Functions section). Set it to NO to prevent
  397 +# subgrouping. Alternatively, this can be done per class using the
  398 +# \nosubgrouping command.
  399 +# The default value is: YES.
  400 +
  401 +SUBGROUPING = YES
  402 +
  403 +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
  404 +# are shown inside the group in which they are included (e.g. using \ingroup)
  405 +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
  406 +# and RTF).
  407 +#
  408 +# Note that this feature does not work in combination with
  409 +# SEPARATE_MEMBER_PAGES.
  410 +# The default value is: NO.
  411 +
  412 +INLINE_GROUPED_CLASSES = NO
  413 +
  414 +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
  415 +# with only public data fields or simple typedef fields will be shown inline in
  416 +# the documentation of the scope in which they are defined (i.e. file,
  417 +# namespace, or group documentation), provided this scope is documented. If set
  418 +# to NO, structs, classes, and unions are shown on a separate page (for HTML and
  419 +# Man pages) or section (for LaTeX and RTF).
  420 +# The default value is: NO.
  421 +
  422 +INLINE_SIMPLE_STRUCTS = NO
  423 +
  424 +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
  425 +# enum is documented as struct, union, or enum with the name of the typedef. So
  426 +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
  427 +# with name TypeT. When disabled the typedef will appear as a member of a file,
  428 +# namespace, or class. And the struct will be named TypeS. This can typically be
  429 +# useful for C code in case the coding convention dictates that all compound
  430 +# types are typedef'ed and only the typedef is referenced, never the tag name.
  431 +# The default value is: NO.
  432 +
  433 +TYPEDEF_HIDES_STRUCT = NO
  434 +
  435 +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
  436 +# cache is used to resolve symbols given their name and scope. Since this can be
  437 +# an expensive process and often the same symbol appears multiple times in the
  438 +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
  439 +# doxygen will become slower. If the cache is too large, memory is wasted. The
  440 +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
  441 +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
  442 +# symbols. At the end of a run doxygen will report the cache usage and suggest
  443 +# the optimal cache size from a speed point of view.
  444 +# Minimum value: 0, maximum value: 9, default value: 0.
  445 +
  446 +LOOKUP_CACHE_SIZE = 0
  447 +
  448 +#---------------------------------------------------------------------------
  449 +# Build related configuration options
  450 +#---------------------------------------------------------------------------
  451 +
  452 +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
  453 +# documentation are documented, even if no documentation was available. Private
  454 +# class members and static file members will be hidden unless the
  455 +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
  456 +# Note: This will also disable the warnings about undocumented members that are
  457 +# normally produced when WARNINGS is set to YES.
  458 +# The default value is: NO.
  459 +
  460 +EXTRACT_ALL = YES
  461 +
  462 +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
  463 +# be included in the documentation.
  464 +# The default value is: NO.
  465 +
  466 +EXTRACT_PRIVATE = NO
  467 +
  468 +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
  469 +# scope will be included in the documentation.
  470 +# The default value is: NO.
  471 +
  472 +EXTRACT_PACKAGE = NO
  473 +
  474 +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
  475 +# included in the documentation.
  476 +# The default value is: NO.
  477 +
  478 +EXTRACT_STATIC = NO
  479 +
  480 +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
  481 +# locally in source files will be included in the documentation. If set to NO,
  482 +# only classes defined in header files are included. Does not have any effect
  483 +# for Java sources.
  484 +# The default value is: YES.
  485 +
  486 +EXTRACT_LOCAL_CLASSES = YES
  487 +
  488 +# This flag is only useful for Objective-C code. If set to YES, local methods,
  489 +# which are defined in the implementation section but not in the interface are
  490 +# included in the documentation. If set to NO, only methods in the interface are
  491 +# included.
  492 +# The default value is: NO.
  493 +
  494 +EXTRACT_LOCAL_METHODS = NO
  495 +
  496 +# If this flag is set to YES, the members of anonymous namespaces will be
  497 +# extracted and appear in the documentation as a namespace called
  498 +# 'anonymous_namespace{file}', where file will be replaced with the base name of
  499 +# the file that contains the anonymous namespace. By default anonymous namespace
  500 +# are hidden.
  501 +# The default value is: NO.
  502 +
  503 +EXTRACT_ANON_NSPACES = NO
  504 +
  505 +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
  506 +# undocumented members inside documented classes or files. If set to NO these
  507 +# members will be included in the various overviews, but no documentation
  508 +# section is generated. This option has no effect if EXTRACT_ALL is enabled.
  509 +# The default value is: NO.
  510 +
  511 +HIDE_UNDOC_MEMBERS = NO
  512 +
  513 +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
  514 +# undocumented classes that are normally visible in the class hierarchy. If set
  515 +# to NO, these classes will be included in the various overviews. This option
  516 +# has no effect if EXTRACT_ALL is enabled.
  517 +# The default value is: NO.
  518 +
  519 +HIDE_UNDOC_CLASSES = NO
  520 +
  521 +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
  522 +# (class|struct|union) declarations. If set to NO, these declarations will be
  523 +# included in the documentation.
  524 +# The default value is: NO.
  525 +
  526 +HIDE_FRIEND_COMPOUNDS = NO
  527 +
  528 +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
  529 +# documentation blocks found inside the body of a function. If set to NO, these
  530 +# blocks will be appended to the function's detailed documentation block.
  531 +# The default value is: NO.
  532 +
  533 +HIDE_IN_BODY_DOCS = NO
  534 +
  535 +# The INTERNAL_DOCS tag determines if documentation that is typed after a
  536 +# \internal command is included. If the tag is set to NO then the documentation
  537 +# will be excluded. Set it to YES to include the internal documentation.
  538 +# The default value is: NO.
  539 +
  540 +INTERNAL_DOCS = NO
  541 +
  542 +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
  543 +# names in lower-case letters. If set to YES, upper-case letters are also
  544 +# allowed. This is useful if you have classes or files whose names only differ
  545 +# in case and if your file system supports case sensitive file names. Windows
  546 +# and Mac users are advised to set this option to NO.
  547 +# The default value is: system dependent.
  548 +
  549 +CASE_SENSE_NAMES = NO
  550 +
  551 +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
  552 +# their full class and namespace scopes in the documentation. If set to YES, the
  553 +# scope will be hidden.
  554 +# The default value is: NO.
  555 +
  556 +HIDE_SCOPE_NAMES = NO
  557 +
  558 +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
  559 +# append additional text to a page's title, such as Class Reference. If set to
  560 +# YES the compound reference will be hidden.
  561 +# The default value is: NO.
  562 +
  563 +HIDE_COMPOUND_REFERENCE= NO
  564 +
  565 +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
  566 +# the files that are included by a file in the documentation of that file.
  567 +# The default value is: YES.
  568 +
  569 +SHOW_INCLUDE_FILES = YES
  570 +
  571 +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
  572 +# grouped member an include statement to the documentation, telling the reader
  573 +# which file to include in order to use the member.
  574 +# The default value is: NO.
  575 +
  576 +SHOW_GROUPED_MEMB_INC = NO
  577 +
  578 +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
  579 +# files with double quotes in the documentation rather than with sharp brackets.
  580 +# The default value is: NO.
  581 +
  582 +FORCE_LOCAL_INCLUDES = NO
  583 +
  584 +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
  585 +# documentation for inline members.
  586 +# The default value is: YES.
  587 +
  588 +INLINE_INFO = YES
  589 +
  590 +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
  591 +# (detailed) documentation of file and class members alphabetically by member
  592 +# name. If set to NO, the members will appear in declaration order.
  593 +# The default value is: YES.
  594 +
  595 +SORT_MEMBER_DOCS = YES
  596 +
  597 +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
  598 +# descriptions of file, namespace and class members alphabetically by member
  599 +# name. If set to NO, the members will appear in declaration order. Note that
  600 +# this will also influence the order of the classes in the class list.
  601 +# The default value is: NO.
  602 +
  603 +SORT_BRIEF_DOCS = NO
  604 +
  605 +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
  606 +# (brief and detailed) documentation of class members so that constructors and
  607 +# destructors are listed first. If set to NO the constructors will appear in the
  608 +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
  609 +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
  610 +# member documentation.
  611 +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
  612 +# detailed member documentation.
  613 +# The default value is: NO.
  614 +
  615 +SORT_MEMBERS_CTORS_1ST = NO
  616 +
  617 +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
  618 +# of group names into alphabetical order. If set to NO the group names will
  619 +# appear in their defined order.
  620 +# The default value is: NO.
  621 +
  622 +SORT_GROUP_NAMES = NO
  623 +
  624 +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
  625 +# fully-qualified names, including namespaces. If set to NO, the class list will
  626 +# be sorted only by class name, not including the namespace part.
  627 +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
  628 +# Note: This option applies only to the class list, not to the alphabetical
  629 +# list.
  630 +# The default value is: NO.
  631 +
  632 +SORT_BY_SCOPE_NAME = NO
  633 +
  634 +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
  635 +# type resolution of all parameters of a function it will reject a match between
  636 +# the prototype and the implementation of a member function even if there is
  637 +# only one candidate or it is obvious which candidate to choose by doing a
  638 +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
  639 +# accept a match between prototype and implementation in such cases.
  640 +# The default value is: NO.
  641 +
  642 +STRICT_PROTO_MATCHING = NO
  643 +
  644 +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
  645 +# list. This list is created by putting \todo commands in the documentation.
  646 +# The default value is: YES.
  647 +
  648 +GENERATE_TODOLIST = YES
  649 +
  650 +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
  651 +# list. This list is created by putting \test commands in the documentation.
  652 +# The default value is: YES.
  653 +
  654 +GENERATE_TESTLIST = YES
  655 +
  656 +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
  657 +# list. This list is created by putting \bug commands in the documentation.
  658 +# The default value is: YES.
  659 +
  660 +GENERATE_BUGLIST = YES
  661 +
  662 +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
  663 +# the deprecated list. This list is created by putting \deprecated commands in
  664 +# the documentation.
  665 +# The default value is: YES.
  666 +
  667 +GENERATE_DEPRECATEDLIST= YES
  668 +
  669 +# The ENABLED_SECTIONS tag can be used to enable conditional documentation
  670 +# sections, marked by \if <section_label> ... \endif and \cond <section_label>
  671 +# ... \endcond blocks.
  672 +
  673 +ENABLED_SECTIONS =
  674 +
  675 +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
  676 +# initial value of a variable or macro / define can have for it to appear in the
  677 +# documentation. If the initializer consists of more lines than specified here
  678 +# it will be hidden. Use a value of 0 to hide initializers completely. The
  679 +# appearance of the value of individual variables and macros / defines can be
  680 +# controlled using \showinitializer or \hideinitializer command in the
  681 +# documentation regardless of this setting.
  682 +# Minimum value: 0, maximum value: 10000, default value: 30.
  683 +
  684 +MAX_INITIALIZER_LINES = 30
  685 +
  686 +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
  687 +# the bottom of the documentation of classes and structs. If set to YES, the
  688 +# list will mention the files that were used to generate the documentation.
  689 +# The default value is: YES.
  690 +
  691 +SHOW_USED_FILES = YES
  692 +
  693 +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
  694 +# will remove the Files entry from the Quick Index and from the Folder Tree View
  695 +# (if specified).
  696 +# The default value is: YES.
  697 +
  698 +SHOW_FILES = YES
  699 +
  700 +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
  701 +# page. This will remove the Namespaces entry from the Quick Index and from the
  702 +# Folder Tree View (if specified).
  703 +# The default value is: YES.
  704 +
  705 +SHOW_NAMESPACES = YES
  706 +
  707 +# The FILE_VERSION_FILTER tag can be used to specify a program or script that
  708 +# doxygen should invoke to get the current version for each file (typically from
  709 +# the version control system). Doxygen will invoke the program by executing (via
  710 +# popen()) the command command input-file, where command is the value of the
  711 +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
  712 +# by doxygen. Whatever the program writes to standard output is used as the file
  713 +# version. For an example see the documentation.
  714 +
  715 +FILE_VERSION_FILTER =
  716 +
  717 +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
  718 +# by doxygen. The layout file controls the global structure of the generated
  719 +# output files in an output format independent way. To create the layout file
  720 +# that represents doxygen's defaults, run doxygen with the -l option. You can
  721 +# optionally specify a file name after the option, if omitted DoxygenLayout.xml
  722 +# will be used as the name of the layout file.
  723 +#
  724 +# Note that if you run doxygen from a directory containing a file called
  725 +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
  726 +# tag is left empty.
  727 +
  728 +LAYOUT_FILE =
  729 +
  730 +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
  731 +# the reference definitions. This must be a list of .bib files. The .bib
  732 +# extension is automatically appended if omitted. This requires the bibtex tool
  733 +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
  734 +# For LaTeX the style of the bibliography can be controlled using
  735 +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
  736 +# search path. See also \cite for info how to create references.
  737 +
  738 +CITE_BIB_FILES =
  739 +
  740 +#---------------------------------------------------------------------------
  741 +# Configuration options related to warning and progress messages
  742 +#---------------------------------------------------------------------------
  743 +
  744 +# The QUIET tag can be used to turn on/off the messages that are generated to
  745 +# standard output by doxygen. If QUIET is set to YES this implies that the
  746 +# messages are off.
  747 +# The default value is: NO.
  748 +
  749 +QUIET = NO
  750 +
  751 +# The WARNINGS tag can be used to turn on/off the warning messages that are
  752 +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
  753 +# this implies that the warnings are on.
  754 +#
  755 +# Tip: Turn warnings on while writing the documentation.
  756 +# The default value is: YES.
  757 +
  758 +WARNINGS = YES
  759 +
  760 +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
  761 +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
  762 +# will automatically be disabled.
  763 +# The default value is: YES.
  764 +
  765 +WARN_IF_UNDOCUMENTED = YES
  766 +
  767 +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
  768 +# potential errors in the documentation, such as not documenting some parameters
  769 +# in a documented function, or documenting parameters that don't exist or using
  770 +# markup commands wrongly.
  771 +# The default value is: YES.
  772 +
  773 +WARN_IF_DOC_ERROR = YES
  774 +
  775 +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
  776 +# are documented, but have no documentation for their parameters or return
  777 +# value. If set to NO, doxygen will only warn about wrong or incomplete
  778 +# parameter documentation, but not about the absence of documentation. If
  779 +# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
  780 +# The default value is: NO.
  781 +
  782 +WARN_NO_PARAMDOC = NO
  783 +
  784 +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
  785 +# a warning is encountered.
  786 +# The default value is: NO.
  787 +
  788 +WARN_AS_ERROR = NO
  789 +
  790 +# The WARN_FORMAT tag determines the format of the warning messages that doxygen
  791 +# can produce. The string should contain the $file, $line, and $text tags, which
  792 +# will be replaced by the file and line number from which the warning originated
  793 +# and the warning text. Optionally the format may contain $version, which will
  794 +# be replaced by the version of the file (if it could be obtained via
  795 +# FILE_VERSION_FILTER)
  796 +# The default value is: $file:$line: $text.
  797 +
  798 +WARN_FORMAT = "$file:$line: $text"
  799 +
  800 +# The WARN_LOGFILE tag can be used to specify a file to which warning and error
  801 +# messages should be written. If left blank the output is written to standard
  802 +# error (stderr).
  803 +
  804 +WARN_LOGFILE =
  805 +
  806 +#---------------------------------------------------------------------------
  807 +# Configuration options related to the input files
  808 +#---------------------------------------------------------------------------
  809 +
  810 +# The INPUT tag is used to specify the files and/or directories that contain
  811 +# documented source files. You may enter file names like myfile.cpp or
  812 +# directories like /usr/src/myproject. Separate the files or directories with
  813 +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
  814 +# Note: If this tag is empty the current directory is searched.
  815 +
  816 +INPUT = /home/pgroen/projects/osdev_components/mqtt
  817 +
  818 +# This tag can be used to specify the character encoding of the source files
  819 +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
  820 +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
  821 +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
  822 +# possible encodings.
  823 +# The default value is: UTF-8.
  824 +
  825 +INPUT_ENCODING = UTF-8
  826 +
  827 +# If the value of the INPUT tag contains directories, you can use the
  828 +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
  829 +# *.h) to filter out the source-files in the directories.
  830 +#
  831 +# Note that for custom extensions or not directly supported extensions you also
  832 +# need to set EXTENSION_MAPPING for the extension otherwise the files are not
  833 +# read by doxygen.
  834 +#
  835 +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
  836 +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
  837 +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
  838 +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
  839 +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
  840 +
  841 +FILE_PATTERNS = *.c \
  842 + *.cc \
  843 + *.cxx \
  844 + *.cpp \
  845 + *.c++ \
  846 + *.java \
  847 + *.ii \
  848 + *.ixx \
  849 + *.ipp \
  850 + *.i++ \
  851 + *.inl \
  852 + *.idl \
  853 + *.ddl \
  854 + *.odl \
  855 + *.h \
  856 + *.hh \
  857 + *.hxx \
  858 + *.hpp \
  859 + *.h++ \
  860 + *.cs \
  861 + *.d \
  862 + *.php \
  863 + *.php4 \
  864 + *.php5 \
  865 + *.phtml \
  866 + *.inc \
  867 + *.m \
  868 + *.markdown \
  869 + *.md \
  870 + *.mm \
  871 + *.dox \
  872 + *.py \
  873 + *.pyw \
  874 + *.f90 \
  875 + *.f95 \
  876 + *.f03 \
  877 + *.f08 \
  878 + *.f \
  879 + *.for \
  880 + *.tcl \
  881 + *.vhd \
  882 + *.vhdl \
  883 + *.ucf \
  884 + *.qsf \
  885 + *.ice
  886 +
  887 +# The RECURSIVE tag can be used to specify whether or not subdirectories should
  888 +# be searched for input files as well.
  889 +# The default value is: NO.
  890 +
  891 +RECURSIVE = NO
  892 +
  893 +# The EXCLUDE tag can be used to specify files and/or directories that should be
  894 +# excluded from the INPUT source files. This way you can easily exclude a
  895 +# subdirectory from a directory tree whose root is specified with the INPUT tag.
  896 +#
  897 +# Note that relative paths are relative to the directory from which doxygen is
  898 +# run.
  899 +
  900 +EXCLUDE =
  901 +
  902 +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
  903 +# directories that are symbolic links (a Unix file system feature) are excluded
  904 +# from the input.
  905 +# The default value is: NO.
  906 +
  907 +EXCLUDE_SYMLINKS = NO
  908 +
  909 +# If the value of the INPUT tag contains directories, you can use the
  910 +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
  911 +# certain files from those directories.
  912 +#
  913 +# Note that the wildcards are matched against the file with absolute path, so to
  914 +# exclude all test directories for example use the pattern */test/*
  915 +
  916 +EXCLUDE_PATTERNS =
  917 +
  918 +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
  919 +# (namespaces, classes, functions, etc.) that should be excluded from the
  920 +# output. The symbol name can be a fully qualified name, a word, or if the
  921 +# wildcard * is used, a substring. Examples: ANamespace, AClass,
  922 +# AClass::ANamespace, ANamespace::*Test
  923 +#
  924 +# Note that the wildcards are matched against the file with absolute path, so to
  925 +# exclude all test directories use the pattern */test/*
  926 +
  927 +EXCLUDE_SYMBOLS =
  928 +
  929 +# The EXAMPLE_PATH tag can be used to specify one or more files or directories
  930 +# that contain example code fragments that are included (see the \include
  931 +# command).
  932 +
  933 +EXAMPLE_PATH =
  934 +
  935 +# If the value of the EXAMPLE_PATH tag contains directories, you can use the
  936 +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
  937 +# *.h) to filter out the source-files in the directories. If left blank all
  938 +# files are included.
  939 +
  940 +EXAMPLE_PATTERNS = *
  941 +
  942 +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
  943 +# searched for input files to be used with the \include or \dontinclude commands
  944 +# irrespective of the value of the RECURSIVE tag.
  945 +# The default value is: NO.
  946 +
  947 +EXAMPLE_RECURSIVE = NO
  948 +
  949 +# The IMAGE_PATH tag can be used to specify one or more files or directories
  950 +# that contain images that are to be included in the documentation (see the
  951 +# \image command).
  952 +
  953 +IMAGE_PATH =
  954 +
  955 +# The INPUT_FILTER tag can be used to specify a program that doxygen should
  956 +# invoke to filter for each input file. Doxygen will invoke the filter program
  957 +# by executing (via popen()) the command:
  958 +#
  959 +# <filter> <input-file>
  960 +#
  961 +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
  962 +# name of an input file. Doxygen will then use the output that the filter
  963 +# program writes to standard output. If FILTER_PATTERNS is specified, this tag
  964 +# will be ignored.
  965 +#
  966 +# Note that the filter must not add or remove lines; it is applied before the
  967 +# code is scanned, but not when the output code is generated. If lines are added
  968 +# or removed, the anchors will not be placed correctly.
  969 +#
  970 +# Note that for custom extensions or not directly supported extensions you also
  971 +# need to set EXTENSION_MAPPING for the extension otherwise the files are not
  972 +# properly processed by doxygen.
  973 +
  974 +INPUT_FILTER =
  975 +
  976 +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
  977 +# basis. Doxygen will compare the file name with each pattern and apply the
  978 +# filter if there is a match. The filters are a list of the form: pattern=filter
  979 +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
  980 +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
  981 +# patterns match the file name, INPUT_FILTER is applied.
  982 +#
  983 +# Note that for custom extensions or not directly supported extensions you also
  984 +# need to set EXTENSION_MAPPING for the extension otherwise the files are not
  985 +# properly processed by doxygen.
  986 +
  987 +FILTER_PATTERNS =
  988 +
  989 +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
  990 +# INPUT_FILTER) will also be used to filter the input files that are used for
  991 +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
  992 +# The default value is: NO.
  993 +
  994 +FILTER_SOURCE_FILES = NO
  995 +
  996 +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
  997 +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
  998 +# it is also possible to disable source filtering for a specific pattern using
  999 +# *.ext= (so without naming a filter).
  1000 +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
  1001 +
  1002 +FILTER_SOURCE_PATTERNS =
  1003 +
  1004 +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
  1005 +# is part of the input, its contents will be placed on the main page
  1006 +# (index.html). This can be useful if you have a project on for instance GitHub
  1007 +# and want to reuse the introduction page also for the doxygen output.
  1008 +
  1009 +USE_MDFILE_AS_MAINPAGE =
  1010 +
  1011 +#---------------------------------------------------------------------------
  1012 +# Configuration options related to source browsing
  1013 +#---------------------------------------------------------------------------
  1014 +
  1015 +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
  1016 +# generated. Documented entities will be cross-referenced with these sources.
  1017 +#
  1018 +# Note: To get rid of all source code in the generated output, make sure that
  1019 +# also VERBATIM_HEADERS is set to NO.
  1020 +# The default value is: NO.
  1021 +
  1022 +SOURCE_BROWSER = NO
  1023 +
  1024 +# Setting the INLINE_SOURCES tag to YES will include the body of functions,
  1025 +# classes and enums directly into the documentation.
  1026 +# The default value is: NO.
  1027 +
  1028 +INLINE_SOURCES = NO
  1029 +
  1030 +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
  1031 +# special comment blocks from generated source code fragments. Normal C, C++ and
  1032 +# Fortran comments will always remain visible.
  1033 +# The default value is: YES.
  1034 +
  1035 +STRIP_CODE_COMMENTS = YES
  1036 +
  1037 +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
  1038 +# entity all documented functions referencing it will be listed.
  1039 +# The default value is: NO.
  1040 +
  1041 +REFERENCED_BY_RELATION = NO
  1042 +
  1043 +# If the REFERENCES_RELATION tag is set to YES then for each documented function
  1044 +# all documented entities called/used by that function will be listed.
  1045 +# The default value is: NO.
  1046 +
  1047 +REFERENCES_RELATION = NO
  1048 +
  1049 +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
  1050 +# to YES then the hyperlinks from functions in REFERENCES_RELATION and
  1051 +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
  1052 +# link to the documentation.
  1053 +# The default value is: YES.
  1054 +
  1055 +REFERENCES_LINK_SOURCE = YES
  1056 +
  1057 +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
  1058 +# source code will show a tooltip with additional information such as prototype,
  1059 +# brief description and links to the definition and documentation. Since this
  1060 +# will make the HTML file larger and loading of large files a bit slower, you
  1061 +# can opt to disable this feature.
  1062 +# The default value is: YES.
  1063 +# This tag requires that the tag SOURCE_BROWSER is set to YES.
  1064 +
  1065 +SOURCE_TOOLTIPS = YES
  1066 +
  1067 +# If the USE_HTAGS tag is set to YES then the references to source code will
  1068 +# point to the HTML generated by the htags(1) tool instead of doxygen built-in
  1069 +# source browser. The htags tool is part of GNU's global source tagging system
  1070 +# (see https://www.gnu.org/software/global/global.html). You will need version
  1071 +# 4.8.6 or higher.
  1072 +#
  1073 +# To use it do the following:
  1074 +# - Install the latest version of global
  1075 +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
  1076 +# - Make sure the INPUT points to the root of the source tree
  1077 +# - Run doxygen as normal
  1078 +#
  1079 +# Doxygen will invoke htags (and that will in turn invoke gtags), so these
  1080 +# tools must be available from the command line (i.e. in the search path).
  1081 +#
  1082 +# The result: instead of the source browser generated by doxygen, the links to
  1083 +# source code will now point to the output of htags.
  1084 +# The default value is: NO.
  1085 +# This tag requires that the tag SOURCE_BROWSER is set to YES.
  1086 +
  1087 +USE_HTAGS = NO
  1088 +
  1089 +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
  1090 +# verbatim copy of the header file for each class for which an include is
  1091 +# specified. Set to NO to disable this.
  1092 +# See also: Section \class.
  1093 +# The default value is: YES.
  1094 +
  1095 +VERBATIM_HEADERS = YES
  1096 +
  1097 +#---------------------------------------------------------------------------
  1098 +# Configuration options related to the alphabetical class index
  1099 +#---------------------------------------------------------------------------
  1100 +
  1101 +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
  1102 +# compounds will be generated. Enable this if the project contains a lot of
  1103 +# classes, structs, unions or interfaces.
  1104 +# The default value is: YES.
  1105 +
  1106 +ALPHABETICAL_INDEX = YES
  1107 +
  1108 +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
  1109 +# which the alphabetical index list will be split.
  1110 +# Minimum value: 1, maximum value: 20, default value: 5.
  1111 +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
  1112 +
  1113 +COLS_IN_ALPHA_INDEX = 5
  1114 +
  1115 +# In case all classes in a project start with a common prefix, all classes will
  1116 +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
  1117 +# can be used to specify a prefix (or a list of prefixes) that should be ignored
  1118 +# while generating the index headers.
  1119 +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
  1120 +
  1121 +IGNORE_PREFIX =
  1122 +
  1123 +#---------------------------------------------------------------------------
  1124 +# Configuration options related to the HTML output
  1125 +#---------------------------------------------------------------------------
  1126 +
  1127 +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
  1128 +# The default value is: YES.
  1129 +
  1130 +GENERATE_HTML = YES
  1131 +
  1132 +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
  1133 +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
  1134 +# it.
  1135 +# The default directory is: html.
  1136 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1137 +
  1138 +HTML_OUTPUT = html
  1139 +
  1140 +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
  1141 +# generated HTML page (for example: .htm, .php, .asp).
  1142 +# The default value is: .html.
  1143 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1144 +
  1145 +HTML_FILE_EXTENSION = .html
  1146 +
  1147 +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
  1148 +# each generated HTML page. If the tag is left blank doxygen will generate a
  1149 +# standard header.
  1150 +#
  1151 +# To get valid HTML the header file that includes any scripts and style sheets
  1152 +# that doxygen needs, which is dependent on the configuration options used (e.g.
  1153 +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
  1154 +# default header using
  1155 +# doxygen -w html new_header.html new_footer.html new_stylesheet.css
  1156 +# YourConfigFile
  1157 +# and then modify the file new_header.html. See also section "Doxygen usage"
  1158 +# for information on how to generate the default header that doxygen normally
  1159 +# uses.
  1160 +# Note: The header is subject to change so you typically have to regenerate the
  1161 +# default header when upgrading to a newer version of doxygen. For a description
  1162 +# of the possible markers and block names see the documentation.
  1163 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1164 +
  1165 +HTML_HEADER =
  1166 +
  1167 +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
  1168 +# generated HTML page. If the tag is left blank doxygen will generate a standard
  1169 +# footer. See HTML_HEADER for more information on how to generate a default
  1170 +# footer and what special commands can be used inside the footer. See also
  1171 +# section "Doxygen usage" for information on how to generate the default footer
  1172 +# that doxygen normally uses.
  1173 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1174 +
  1175 +HTML_FOOTER =
  1176 +
  1177 +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
  1178 +# sheet that is used by each HTML page. It can be used to fine-tune the look of
  1179 +# the HTML output. If left blank doxygen will generate a default style sheet.
  1180 +# See also section "Doxygen usage" for information on how to generate the style
  1181 +# sheet that doxygen normally uses.
  1182 +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
  1183 +# it is more robust and this tag (HTML_STYLESHEET) will in the future become
  1184 +# obsolete.
  1185 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1186 +
  1187 +HTML_STYLESHEET =
  1188 +
  1189 +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
  1190 +# cascading style sheets that are included after the standard style sheets
  1191 +# created by doxygen. Using this option one can overrule certain style aspects.
  1192 +# This is preferred over using HTML_STYLESHEET since it does not replace the
  1193 +# standard style sheet and is therefore more robust against future updates.
  1194 +# Doxygen will copy the style sheet files to the output directory.
  1195 +# Note: The order of the extra style sheet files is of importance (e.g. the last
  1196 +# style sheet in the list overrules the setting of the previous ones in the
  1197 +# list). For an example see the documentation.
  1198 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1199 +
  1200 +HTML_EXTRA_STYLESHEET =
  1201 +
  1202 +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
  1203 +# other source files which should be copied to the HTML output directory. Note
  1204 +# that these files will be copied to the base HTML output directory. Use the
  1205 +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
  1206 +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
  1207 +# files will be copied as-is; there are no commands or markers available.
  1208 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1209 +
  1210 +HTML_EXTRA_FILES =
  1211 +
  1212 +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
  1213 +# will adjust the colors in the style sheet and background images according to
  1214 +# this color. Hue is specified as an angle on a colorwheel, see
  1215 +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
  1216 +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
  1217 +# purple, and 360 is red again.
  1218 +# Minimum value: 0, maximum value: 359, default value: 220.
  1219 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1220 +
  1221 +HTML_COLORSTYLE_HUE = 220
  1222 +
  1223 +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
  1224 +# in the HTML output. For a value of 0 the output will use grayscales only. A
  1225 +# value of 255 will produce the most vivid colors.
  1226 +# Minimum value: 0, maximum value: 255, default value: 100.
  1227 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1228 +
  1229 +HTML_COLORSTYLE_SAT = 100
  1230 +
  1231 +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
  1232 +# luminance component of the colors in the HTML output. Values below 100
  1233 +# gradually make the output lighter, whereas values above 100 make the output
  1234 +# darker. The value divided by 100 is the actual gamma applied, so 80 represents
  1235 +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
  1236 +# change the gamma.
  1237 +# Minimum value: 40, maximum value: 240, default value: 80.
  1238 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1239 +
  1240 +HTML_COLORSTYLE_GAMMA = 80
  1241 +
  1242 +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
  1243 +# page will contain the date and time when the page was generated. Setting this
  1244 +# to YES can help to show when doxygen was last run and thus if the
  1245 +# documentation is up to date.
  1246 +# The default value is: NO.
  1247 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1248 +
  1249 +HTML_TIMESTAMP = NO
  1250 +
  1251 +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
  1252 +# documentation will contain a main index with vertical navigation menus that
  1253 +# are dynamically created via Javascript. If disabled, the navigation index will
  1254 +# consists of multiple levels of tabs that are statically embedded in every HTML
  1255 +# page. Disable this option to support browsers that do not have Javascript,
  1256 +# like the Qt help browser.
  1257 +# The default value is: YES.
  1258 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1259 +
  1260 +HTML_DYNAMIC_MENUS = YES
  1261 +
  1262 +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
  1263 +# documentation will contain sections that can be hidden and shown after the
  1264 +# page has loaded.
  1265 +# The default value is: NO.
  1266 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1267 +
  1268 +HTML_DYNAMIC_SECTIONS = NO
  1269 +
  1270 +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
  1271 +# shown in the various tree structured indices initially; the user can expand
  1272 +# and collapse entries dynamically later on. Doxygen will expand the tree to
  1273 +# such a level that at most the specified number of entries are visible (unless
  1274 +# a fully collapsed tree already exceeds this amount). So setting the number of
  1275 +# entries 1 will produce a full collapsed tree by default. 0 is a special value
  1276 +# representing an infinite number of entries and will result in a full expanded
  1277 +# tree by default.
  1278 +# Minimum value: 0, maximum value: 9999, default value: 100.
  1279 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1280 +
  1281 +HTML_INDEX_NUM_ENTRIES = 100
  1282 +
  1283 +# If the GENERATE_DOCSET tag is set to YES, additional index files will be
  1284 +# generated that can be used as input for Apple's Xcode 3 integrated development
  1285 +# environment (see: https://developer.apple.com/xcode/), introduced with OSX
  1286 +# 10.5 (Leopard). To create a documentation set, doxygen will generate a
  1287 +# Makefile in the HTML output directory. Running make will produce the docset in
  1288 +# that directory and running make install will install the docset in
  1289 +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
  1290 +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
  1291 +# genXcode/_index.html for more information.
  1292 +# The default value is: NO.
  1293 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1294 +
  1295 +GENERATE_DOCSET = NO
  1296 +
  1297 +# This tag determines the name of the docset feed. A documentation feed provides
  1298 +# an umbrella under which multiple documentation sets from a single provider
  1299 +# (such as a company or product suite) can be grouped.
  1300 +# The default value is: Doxygen generated docs.
  1301 +# This tag requires that the tag GENERATE_DOCSET is set to YES.
  1302 +
  1303 +DOCSET_FEEDNAME = "Doxygen generated docs"
  1304 +
  1305 +# This tag specifies a string that should uniquely identify the documentation
  1306 +# set bundle. This should be a reverse domain-name style string, e.g.
  1307 +# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
  1308 +# The default value is: org.doxygen.Project.
  1309 +# This tag requires that the tag GENERATE_DOCSET is set to YES.
  1310 +
  1311 +DOCSET_BUNDLE_ID = org.doxygen.Project
  1312 +
  1313 +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
  1314 +# the documentation publisher. This should be a reverse domain-name style
  1315 +# string, e.g. com.mycompany.MyDocSet.documentation.
  1316 +# The default value is: org.doxygen.Publisher.
  1317 +# This tag requires that the tag GENERATE_DOCSET is set to YES.
  1318 +
  1319 +DOCSET_PUBLISHER_ID = org.doxygen.Publisher
  1320 +
  1321 +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
  1322 +# The default value is: Publisher.
  1323 +# This tag requires that the tag GENERATE_DOCSET is set to YES.
  1324 +
  1325 +DOCSET_PUBLISHER_NAME = Publisher
  1326 +
  1327 +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
  1328 +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
  1329 +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
  1330 +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
  1331 +# Windows.
  1332 +#
  1333 +# The HTML Help Workshop contains a compiler that can convert all HTML output
  1334 +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
  1335 +# files are now used as the Windows 98 help format, and will replace the old
  1336 +# Windows help format (.hlp) on all Windows platforms in the future. Compressed
  1337 +# HTML files also contain an index, a table of contents, and you can search for
  1338 +# words in the documentation. The HTML workshop also contains a viewer for
  1339 +# compressed HTML files.
  1340 +# The default value is: NO.
  1341 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1342 +
  1343 +GENERATE_HTMLHELP = NO
  1344 +
  1345 +# The CHM_FILE tag can be used to specify the file name of the resulting .chm
  1346 +# file. You can add a path in front of the file if the result should not be
  1347 +# written to the html output directory.
  1348 +# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
  1349 +
  1350 +CHM_FILE =
  1351 +
  1352 +# The HHC_LOCATION tag can be used to specify the location (absolute path
  1353 +# including file name) of the HTML help compiler (hhc.exe). If non-empty,
  1354 +# doxygen will try to run the HTML help compiler on the generated index.hhp.
  1355 +# The file has to be specified with full path.
  1356 +# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
  1357 +
  1358 +HHC_LOCATION =
  1359 +
  1360 +# The GENERATE_CHI flag controls if a separate .chi index file is generated
  1361 +# (YES) or that it should be included in the master .chm file (NO).
  1362 +# The default value is: NO.
  1363 +# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
  1364 +
  1365 +GENERATE_CHI = NO
  1366 +
  1367 +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
  1368 +# and project file content.
  1369 +# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
  1370 +
  1371 +CHM_INDEX_ENCODING =
  1372 +
  1373 +# The BINARY_TOC flag controls whether a binary table of contents is generated
  1374 +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
  1375 +# enables the Previous and Next buttons.
  1376 +# The default value is: NO.
  1377 +# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
  1378 +
  1379 +BINARY_TOC = NO
  1380 +
  1381 +# The TOC_EXPAND flag can be set to YES to add extra items for group members to
  1382 +# the table of contents of the HTML help documentation and to the tree view.
  1383 +# The default value is: NO.
  1384 +# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
  1385 +
  1386 +TOC_EXPAND = NO
  1387 +
  1388 +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
  1389 +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
  1390 +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
  1391 +# (.qch) of the generated HTML documentation.
  1392 +# The default value is: NO.
  1393 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1394 +
  1395 +GENERATE_QHP = NO
  1396 +
  1397 +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
  1398 +# the file name of the resulting .qch file. The path specified is relative to
  1399 +# the HTML output folder.
  1400 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1401 +
  1402 +QCH_FILE =
  1403 +
  1404 +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
  1405 +# Project output. For more information please see Qt Help Project / Namespace
  1406 +# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
  1407 +# The default value is: org.doxygen.Project.
  1408 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1409 +
  1410 +QHP_NAMESPACE = org.doxygen.Project
  1411 +
  1412 +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
  1413 +# Help Project output. For more information please see Qt Help Project / Virtual
  1414 +# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
  1415 +# folders).
  1416 +# The default value is: doc.
  1417 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1418 +
  1419 +QHP_VIRTUAL_FOLDER = doc
  1420 +
  1421 +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
  1422 +# filter to add. For more information please see Qt Help Project / Custom
  1423 +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
  1424 +# filters).
  1425 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1426 +
  1427 +QHP_CUST_FILTER_NAME =
  1428 +
  1429 +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
  1430 +# custom filter to add. For more information please see Qt Help Project / Custom
  1431 +# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
  1432 +# filters).
  1433 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1434 +
  1435 +QHP_CUST_FILTER_ATTRS =
  1436 +
  1437 +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
  1438 +# project's filter section matches. Qt Help Project / Filter Attributes (see:
  1439 +# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
  1440 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1441 +
  1442 +QHP_SECT_FILTER_ATTRS =
  1443 +
  1444 +# The QHG_LOCATION tag can be used to specify the location of Qt's
  1445 +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
  1446 +# generated .qhp file.
  1447 +# This tag requires that the tag GENERATE_QHP is set to YES.
  1448 +
  1449 +QHG_LOCATION =
  1450 +
  1451 +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
  1452 +# generated, together with the HTML files, they form an Eclipse help plugin. To
  1453 +# install this plugin and make it available under the help contents menu in
  1454 +# Eclipse, the contents of the directory containing the HTML and XML files needs
  1455 +# to be copied into the plugins directory of eclipse. The name of the directory
  1456 +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
  1457 +# After copying Eclipse needs to be restarted before the help appears.
  1458 +# The default value is: NO.
  1459 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1460 +
  1461 +GENERATE_ECLIPSEHELP = NO
  1462 +
  1463 +# A unique identifier for the Eclipse help plugin. When installing the plugin
  1464 +# the directory name containing the HTML and XML files should also have this
  1465 +# name. Each documentation set should have its own identifier.
  1466 +# The default value is: org.doxygen.Project.
  1467 +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
  1468 +
  1469 +ECLIPSE_DOC_ID = org.doxygen.Project
  1470 +
  1471 +# If you want full control over the layout of the generated HTML pages it might
  1472 +# be necessary to disable the index and replace it with your own. The
  1473 +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
  1474 +# of each HTML page. A value of NO enables the index and the value YES disables
  1475 +# it. Since the tabs in the index contain the same information as the navigation
  1476 +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
  1477 +# The default value is: NO.
  1478 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1479 +
  1480 +DISABLE_INDEX = NO
  1481 +
  1482 +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
  1483 +# structure should be generated to display hierarchical information. If the tag
  1484 +# value is set to YES, a side panel will be generated containing a tree-like
  1485 +# index structure (just like the one that is generated for HTML Help). For this
  1486 +# to work a browser that supports JavaScript, DHTML, CSS and frames is required
  1487 +# (i.e. any modern browser). Windows users are probably better off using the
  1488 +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
  1489 +# further fine-tune the look of the index. As an example, the default style
  1490 +# sheet generated by doxygen has an example that shows how to put an image at
  1491 +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
  1492 +# the same information as the tab index, you could consider setting
  1493 +# DISABLE_INDEX to YES when enabling this option.
  1494 +# The default value is: NO.
  1495 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1496 +
  1497 +GENERATE_TREEVIEW = YES
  1498 +
  1499 +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
  1500 +# doxygen will group on one line in the generated HTML documentation.
  1501 +#
  1502 +# Note that a value of 0 will completely suppress the enum values from appearing
  1503 +# in the overview section.
  1504 +# Minimum value: 0, maximum value: 20, default value: 4.
  1505 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1506 +
  1507 +ENUM_VALUES_PER_LINE = 4
  1508 +
  1509 +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
  1510 +# to set the initial width (in pixels) of the frame in which the tree is shown.
  1511 +# Minimum value: 0, maximum value: 1500, default value: 250.
  1512 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1513 +
  1514 +TREEVIEW_WIDTH = 250
  1515 +
  1516 +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
  1517 +# external symbols imported via tag files in a separate window.
  1518 +# The default value is: NO.
  1519 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1520 +
  1521 +EXT_LINKS_IN_WINDOW = NO
  1522 +
  1523 +# Use this tag to change the font size of LaTeX formulas included as images in
  1524 +# the HTML documentation. When you change the font size after a successful
  1525 +# doxygen run you need to manually remove any form_*.png images from the HTML
  1526 +# output directory to force them to be regenerated.
  1527 +# Minimum value: 8, maximum value: 50, default value: 10.
  1528 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1529 +
  1530 +FORMULA_FONTSIZE = 10
  1531 +
  1532 +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
  1533 +# generated for formulas are transparent PNGs. Transparent PNGs are not
  1534 +# supported properly for IE 6.0, but are supported on all modern browsers.
  1535 +#
  1536 +# Note that when changing this option you need to delete any form_*.png files in
  1537 +# the HTML output directory before the changes have effect.
  1538 +# The default value is: YES.
  1539 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1540 +
  1541 +FORMULA_TRANSPARENT = YES
  1542 +
  1543 +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
  1544 +# https://www.mathjax.org) which uses client side Javascript for the rendering
  1545 +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
  1546 +# installed or if you want to formulas look prettier in the HTML output. When
  1547 +# enabled you may also need to install MathJax separately and configure the path
  1548 +# to it using the MATHJAX_RELPATH option.
  1549 +# The default value is: NO.
  1550 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1551 +
  1552 +USE_MATHJAX = NO
  1553 +
  1554 +# When MathJax is enabled you can set the default output format to be used for
  1555 +# the MathJax output. See the MathJax site (see:
  1556 +# http://docs.mathjax.org/en/latest/output.html) for more details.
  1557 +# Possible values are: HTML-CSS (which is slower, but has the best
  1558 +# compatibility), NativeMML (i.e. MathML) and SVG.
  1559 +# The default value is: HTML-CSS.
  1560 +# This tag requires that the tag USE_MATHJAX is set to YES.
  1561 +
  1562 +MATHJAX_FORMAT = HTML-CSS
  1563 +
  1564 +# When MathJax is enabled you need to specify the location relative to the HTML
  1565 +# output directory using the MATHJAX_RELPATH option. The destination directory
  1566 +# should contain the MathJax.js script. For instance, if the mathjax directory
  1567 +# is located at the same level as the HTML output directory, then
  1568 +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
  1569 +# Content Delivery Network so you can quickly see the result without installing
  1570 +# MathJax. However, it is strongly recommended to install a local copy of
  1571 +# MathJax from https://www.mathjax.org before deployment.
  1572 +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
  1573 +# This tag requires that the tag USE_MATHJAX is set to YES.
  1574 +
  1575 +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
  1576 +
  1577 +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
  1578 +# extension names that should be enabled during MathJax rendering. For example
  1579 +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
  1580 +# This tag requires that the tag USE_MATHJAX is set to YES.
  1581 +
  1582 +MATHJAX_EXTENSIONS =
  1583 +
  1584 +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
  1585 +# of code that will be used on startup of the MathJax code. See the MathJax site
  1586 +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
  1587 +# example see the documentation.
  1588 +# This tag requires that the tag USE_MATHJAX is set to YES.
  1589 +
  1590 +MATHJAX_CODEFILE =
  1591 +
  1592 +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
  1593 +# the HTML output. The underlying search engine uses javascript and DHTML and
  1594 +# should work on any modern browser. Note that when using HTML help
  1595 +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
  1596 +# there is already a search function so this one should typically be disabled.
  1597 +# For large projects the javascript based search engine can be slow, then
  1598 +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
  1599 +# search using the keyboard; to jump to the search box use <access key> + S
  1600 +# (what the <access key> is depends on the OS and browser, but it is typically
  1601 +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
  1602 +# key> to jump into the search results window, the results can be navigated
  1603 +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
  1604 +# the search. The filter options can be selected when the cursor is inside the
  1605 +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
  1606 +# to select a filter and <Enter> or <escape> to activate or cancel the filter
  1607 +# option.
  1608 +# The default value is: YES.
  1609 +# This tag requires that the tag GENERATE_HTML is set to YES.
  1610 +
  1611 +SEARCHENGINE = YES
  1612 +
  1613 +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
  1614 +# implemented using a web server instead of a web client using Javascript. There
  1615 +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
  1616 +# setting. When disabled, doxygen will generate a PHP script for searching and
  1617 +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
  1618 +# and searching needs to be provided by external tools. See the section
  1619 +# "External Indexing and Searching" for details.
  1620 +# The default value is: NO.
  1621 +# This tag requires that the tag SEARCHENGINE is set to YES.
  1622 +
  1623 +SERVER_BASED_SEARCH = NO
  1624 +
  1625 +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
  1626 +# script for searching. Instead the search results are written to an XML file
  1627 +# which needs to be processed by an external indexer. Doxygen will invoke an
  1628 +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
  1629 +# search results.
  1630 +#
  1631 +# Doxygen ships with an example indexer (doxyindexer) and search engine
  1632 +# (doxysearch.cgi) which are based on the open source search engine library
  1633 +# Xapian (see: https://xapian.org/).
  1634 +#
  1635 +# See the section "External Indexing and Searching" for details.
  1636 +# The default value is: NO.
  1637 +# This tag requires that the tag SEARCHENGINE is set to YES.
  1638 +
  1639 +EXTERNAL_SEARCH = NO
  1640 +
  1641 +# The SEARCHENGINE_URL should point to a search engine hosted by a web server
  1642 +# which will return the search results when EXTERNAL_SEARCH is enabled.
  1643 +#
  1644 +# Doxygen ships with an example indexer (doxyindexer) and search engine
  1645 +# (doxysearch.cgi) which are based on the open source search engine library
  1646 +# Xapian (see: https://xapian.org/). See the section "External Indexing and
  1647 +# Searching" for details.
  1648 +# This tag requires that the tag SEARCHENGINE is set to YES.
  1649 +
  1650 +SEARCHENGINE_URL =
  1651 +
  1652 +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
  1653 +# search data is written to a file for indexing by an external tool. With the
  1654 +# SEARCHDATA_FILE tag the name of this file can be specified.
  1655 +# The default file is: searchdata.xml.
  1656 +# This tag requires that the tag SEARCHENGINE is set to YES.
  1657 +
  1658 +SEARCHDATA_FILE = searchdata.xml
  1659 +
  1660 +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
  1661 +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
  1662 +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
  1663 +# projects and redirect the results back to the right project.
  1664 +# This tag requires that the tag SEARCHENGINE is set to YES.
  1665 +
  1666 +EXTERNAL_SEARCH_ID =
  1667 +
  1668 +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
  1669 +# projects other than the one defined by this configuration file, but that are
  1670 +# all added to the same external search index. Each project needs to have a
  1671 +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
  1672 +# to a relative location where the documentation can be found. The format is:
  1673 +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
  1674 +# This tag requires that the tag SEARCHENGINE is set to YES.
  1675 +
  1676 +EXTRA_SEARCH_MAPPINGS =
  1677 +
  1678 +#---------------------------------------------------------------------------
  1679 +# Configuration options related to the LaTeX output
  1680 +#---------------------------------------------------------------------------
  1681 +
  1682 +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
  1683 +# The default value is: YES.
  1684 +
  1685 +GENERATE_LATEX = YES
  1686 +
  1687 +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
  1688 +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
  1689 +# it.
  1690 +# The default directory is: latex.
  1691 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1692 +
  1693 +LATEX_OUTPUT = latex
  1694 +
  1695 +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
  1696 +# invoked.
  1697 +#
  1698 +# Note that when not enabling USE_PDFLATEX the default is latex when enabling
  1699 +# USE_PDFLATEX the default is pdflatex and when in the later case latex is
  1700 +# chosen this is overwritten by pdflatex. For specific output languages the
  1701 +# default can have been set differently, this depends on the implementation of
  1702 +# the output language.
  1703 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1704 +
  1705 +LATEX_CMD_NAME =
  1706 +
  1707 +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
  1708 +# index for LaTeX.
  1709 +# Note: This tag is used in the Makefile / make.bat.
  1710 +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
  1711 +# (.tex).
  1712 +# The default file is: makeindex.
  1713 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1714 +
  1715 +MAKEINDEX_CMD_NAME = makeindex
  1716 +
  1717 +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
  1718 +# generate index for LaTeX.
  1719 +# Note: This tag is used in the generated output file (.tex).
  1720 +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
  1721 +# The default value is: \makeindex.
  1722 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1723 +
  1724 +LATEX_MAKEINDEX_CMD = \makeindex
  1725 +
  1726 +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
  1727 +# documents. This may be useful for small projects and may help to save some
  1728 +# trees in general.
  1729 +# The default value is: NO.
  1730 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1731 +
  1732 +COMPACT_LATEX = NO
  1733 +
  1734 +# The PAPER_TYPE tag can be used to set the paper type that is used by the
  1735 +# printer.
  1736 +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
  1737 +# 14 inches) and executive (7.25 x 10.5 inches).
  1738 +# The default value is: a4.
  1739 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1740 +
  1741 +PAPER_TYPE = a4
  1742 +
  1743 +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
  1744 +# that should be included in the LaTeX output. The package can be specified just
  1745 +# by its name or with the correct syntax as to be used with the LaTeX
  1746 +# \usepackage command. To get the times font for instance you can specify :
  1747 +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
  1748 +# To use the option intlimits with the amsmath package you can specify:
  1749 +# EXTRA_PACKAGES=[intlimits]{amsmath}
  1750 +# If left blank no extra packages will be included.
  1751 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1752 +
  1753 +EXTRA_PACKAGES =
  1754 +
  1755 +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
  1756 +# generated LaTeX document. The header should contain everything until the first
  1757 +# chapter. If it is left blank doxygen will generate a standard header. See
  1758 +# section "Doxygen usage" for information on how to let doxygen write the
  1759 +# default header to a separate file.
  1760 +#
  1761 +# Note: Only use a user-defined header if you know what you are doing! The
  1762 +# following commands have a special meaning inside the header: $title,
  1763 +# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
  1764 +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
  1765 +# string, for the replacement values of the other commands the user is referred
  1766 +# to HTML_HEADER.
  1767 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1768 +
  1769 +LATEX_HEADER =
  1770 +
  1771 +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
  1772 +# generated LaTeX document. The footer should contain everything after the last
  1773 +# chapter. If it is left blank doxygen will generate a standard footer. See
  1774 +# LATEX_HEADER for more information on how to generate a default footer and what
  1775 +# special commands can be used inside the footer.
  1776 +#
  1777 +# Note: Only use a user-defined footer if you know what you are doing!
  1778 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1779 +
  1780 +LATEX_FOOTER =
  1781 +
  1782 +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
  1783 +# LaTeX style sheets that are included after the standard style sheets created
  1784 +# by doxygen. Using this option one can overrule certain style aspects. Doxygen
  1785 +# will copy the style sheet files to the output directory.
  1786 +# Note: The order of the extra style sheet files is of importance (e.g. the last
  1787 +# style sheet in the list overrules the setting of the previous ones in the
  1788 +# list).
  1789 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1790 +
  1791 +LATEX_EXTRA_STYLESHEET =
  1792 +
  1793 +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
  1794 +# other source files which should be copied to the LATEX_OUTPUT output
  1795 +# directory. Note that the files will be copied as-is; there are no commands or
  1796 +# markers available.
  1797 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1798 +
  1799 +LATEX_EXTRA_FILES =
  1800 +
  1801 +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
  1802 +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
  1803 +# contain links (just like the HTML output) instead of page references. This
  1804 +# makes the output suitable for online browsing using a PDF viewer.
  1805 +# The default value is: YES.
  1806 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1807 +
  1808 +PDF_HYPERLINKS = NO
  1809 +
  1810 +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
  1811 +# the PDF file directly from the LaTeX files. Set this option to YES, to get a
  1812 +# higher quality PDF documentation.
  1813 +# The default value is: YES.
  1814 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1815 +
  1816 +USE_PDFLATEX = YES
  1817 +
  1818 +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
  1819 +# command to the generated LaTeX files. This will instruct LaTeX to keep running
  1820 +# if errors occur, instead of asking the user for help. This option is also used
  1821 +# when generating formulas in HTML.
  1822 +# The default value is: NO.
  1823 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1824 +
  1825 +LATEX_BATCHMODE = NO
  1826 +
  1827 +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
  1828 +# index chapters (such as File Index, Compound Index, etc.) in the output.
  1829 +# The default value is: NO.
  1830 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1831 +
  1832 +LATEX_HIDE_INDICES = NO
  1833 +
  1834 +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
  1835 +# code with syntax highlighting in the LaTeX output.
  1836 +#
  1837 +# Note that which sources are shown also depends on other settings such as
  1838 +# SOURCE_BROWSER.
  1839 +# The default value is: NO.
  1840 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1841 +
  1842 +LATEX_SOURCE_CODE = NO
  1843 +
  1844 +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
  1845 +# bibliography, e.g. plainnat, or ieeetr. See
  1846 +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
  1847 +# The default value is: plain.
  1848 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1849 +
  1850 +LATEX_BIB_STYLE = plain
  1851 +
  1852 +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
  1853 +# page will contain the date and time when the page was generated. Setting this
  1854 +# to NO can help when comparing the output of multiple runs.
  1855 +# The default value is: NO.
  1856 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1857 +
  1858 +LATEX_TIMESTAMP = NO
  1859 +
  1860 +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
  1861 +# path from which the emoji images will be read. If a relative path is entered,
  1862 +# it will be relative to the LATEX_OUTPUT directory. If left blank the
  1863 +# LATEX_OUTPUT directory will be used.
  1864 +# This tag requires that the tag GENERATE_LATEX is set to YES.
  1865 +
  1866 +LATEX_EMOJI_DIRECTORY =
  1867 +
  1868 +#---------------------------------------------------------------------------
  1869 +# Configuration options related to the RTF output
  1870 +#---------------------------------------------------------------------------
  1871 +
  1872 +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
  1873 +# RTF output is optimized for Word 97 and may not look too pretty with other RTF
  1874 +# readers/editors.
  1875 +# The default value is: NO.
  1876 +
  1877 +GENERATE_RTF = NO
  1878 +
  1879 +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
  1880 +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
  1881 +# it.
  1882 +# The default directory is: rtf.
  1883 +# This tag requires that the tag GENERATE_RTF is set to YES.
  1884 +
  1885 +RTF_OUTPUT = rtf
  1886 +
  1887 +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
  1888 +# documents. This may be useful for small projects and may help to save some
  1889 +# trees in general.
  1890 +# The default value is: NO.
  1891 +# This tag requires that the tag GENERATE_RTF is set to YES.
  1892 +
  1893 +COMPACT_RTF = NO
  1894 +
  1895 +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
  1896 +# contain hyperlink fields. The RTF file will contain links (just like the HTML
  1897 +# output) instead of page references. This makes the output suitable for online
  1898 +# browsing using Word or some other Word compatible readers that support those
  1899 +# fields.
  1900 +#
  1901 +# Note: WordPad (write) and others do not support links.
  1902 +# The default value is: NO.
  1903 +# This tag requires that the tag GENERATE_RTF is set to YES.
  1904 +
  1905 +RTF_HYPERLINKS = NO
  1906 +
  1907 +# Load stylesheet definitions from file. Syntax is similar to doxygen's
  1908 +# configuration file, i.e. a series of assignments. You only have to provide
  1909 +# replacements, missing definitions are set to their default value.
  1910 +#
  1911 +# See also section "Doxygen usage" for information on how to generate the
  1912 +# default style sheet that doxygen normally uses.
  1913 +# This tag requires that the tag GENERATE_RTF is set to YES.
  1914 +
  1915 +RTF_STYLESHEET_FILE =
  1916 +
  1917 +# Set optional variables used in the generation of an RTF document. Syntax is
  1918 +# similar to doxygen's configuration file. A template extensions file can be
  1919 +# generated using doxygen -e rtf extensionFile.
  1920 +# This tag requires that the tag GENERATE_RTF is set to YES.
  1921 +
  1922 +RTF_EXTENSIONS_FILE =
  1923 +
  1924 +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
  1925 +# with syntax highlighting in the RTF output.
  1926 +#
  1927 +# Note that which sources are shown also depends on other settings such as
  1928 +# SOURCE_BROWSER.
  1929 +# The default value is: NO.
  1930 +# This tag requires that the tag GENERATE_RTF is set to YES.
  1931 +
  1932 +RTF_SOURCE_CODE = NO
  1933 +
  1934 +#---------------------------------------------------------------------------
  1935 +# Configuration options related to the man page output
  1936 +#---------------------------------------------------------------------------
  1937 +
  1938 +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
  1939 +# classes and files.
  1940 +# The default value is: NO.
  1941 +
  1942 +GENERATE_MAN = NO
  1943 +
  1944 +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
  1945 +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
  1946 +# it. A directory man3 will be created inside the directory specified by
  1947 +# MAN_OUTPUT.
  1948 +# The default directory is: man.
  1949 +# This tag requires that the tag GENERATE_MAN is set to YES.
  1950 +
  1951 +MAN_OUTPUT = man
  1952 +
  1953 +# The MAN_EXTENSION tag determines the extension that is added to the generated
  1954 +# man pages. In case the manual section does not start with a number, the number
  1955 +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
  1956 +# optional.
  1957 +# The default value is: .3.
  1958 +# This tag requires that the tag GENERATE_MAN is set to YES.
  1959 +
  1960 +MAN_EXTENSION = .3
  1961 +
  1962 +# The MAN_SUBDIR tag determines the name of the directory created within
  1963 +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
  1964 +# MAN_EXTENSION with the initial . removed.
  1965 +# This tag requires that the tag GENERATE_MAN is set to YES.
  1966 +
  1967 +MAN_SUBDIR =
  1968 +
  1969 +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
  1970 +# will generate one additional man file for each entity documented in the real
  1971 +# man page(s). These additional files only source the real man page, but without
  1972 +# them the man command would be unable to find the correct page.
  1973 +# The default value is: NO.
  1974 +# This tag requires that the tag GENERATE_MAN is set to YES.
  1975 +
  1976 +MAN_LINKS = NO
  1977 +
  1978 +#---------------------------------------------------------------------------
  1979 +# Configuration options related to the XML output
  1980 +#---------------------------------------------------------------------------
  1981 +
  1982 +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
  1983 +# captures the structure of the code including all documentation.
  1984 +# The default value is: NO.
  1985 +
  1986 +GENERATE_XML = NO
  1987 +
  1988 +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
  1989 +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
  1990 +# it.
  1991 +# The default directory is: xml.
  1992 +# This tag requires that the tag GENERATE_XML is set to YES.
  1993 +
  1994 +XML_OUTPUT = xml
  1995 +
  1996 +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
  1997 +# listings (including syntax highlighting and cross-referencing information) to
  1998 +# the XML output. Note that enabling this will significantly increase the size
  1999 +# of the XML output.
  2000 +# The default value is: YES.
  2001 +# This tag requires that the tag GENERATE_XML is set to YES.
  2002 +
  2003 +XML_PROGRAMLISTING = YES
  2004 +
  2005 +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
  2006 +# namespace members in file scope as well, matching the HTML output.
  2007 +# The default value is: NO.
  2008 +# This tag requires that the tag GENERATE_XML is set to YES.
  2009 +
  2010 +XML_NS_MEMB_FILE_SCOPE = NO
  2011 +
  2012 +#---------------------------------------------------------------------------
  2013 +# Configuration options related to the DOCBOOK output
  2014 +#---------------------------------------------------------------------------
  2015 +
  2016 +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
  2017 +# that can be used to generate PDF.
  2018 +# The default value is: NO.
  2019 +
  2020 +GENERATE_DOCBOOK = NO
  2021 +
  2022 +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
  2023 +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
  2024 +# front of it.
  2025 +# The default directory is: docbook.
  2026 +# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
  2027 +
  2028 +DOCBOOK_OUTPUT = docbook
  2029 +
  2030 +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
  2031 +# program listings (including syntax highlighting and cross-referencing
  2032 +# information) to the DOCBOOK output. Note that enabling this will significantly
  2033 +# increase the size of the DOCBOOK output.
  2034 +# The default value is: NO.
  2035 +# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
  2036 +
  2037 +DOCBOOK_PROGRAMLISTING = NO
  2038 +
  2039 +#---------------------------------------------------------------------------
  2040 +# Configuration options for the AutoGen Definitions output
  2041 +#---------------------------------------------------------------------------
  2042 +
  2043 +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
  2044 +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
  2045 +# the structure of the code including all documentation. Note that this feature
  2046 +# is still experimental and incomplete at the moment.
  2047 +# The default value is: NO.
  2048 +
  2049 +GENERATE_AUTOGEN_DEF = NO
  2050 +
  2051 +#---------------------------------------------------------------------------
  2052 +# Configuration options related to the Perl module output
  2053 +#---------------------------------------------------------------------------
  2054 +
  2055 +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
  2056 +# file that captures the structure of the code including all documentation.
  2057 +#
  2058 +# Note that this feature is still experimental and incomplete at the moment.
  2059 +# The default value is: NO.
  2060 +
  2061 +GENERATE_PERLMOD = NO
  2062 +
  2063 +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
  2064 +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
  2065 +# output from the Perl module output.
  2066 +# The default value is: NO.
  2067 +# This tag requires that the tag GENERATE_PERLMOD is set to YES.
  2068 +
  2069 +PERLMOD_LATEX = NO
  2070 +
  2071 +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
  2072 +# formatted so it can be parsed by a human reader. This is useful if you want to
  2073 +# understand what is going on. On the other hand, if this tag is set to NO, the
  2074 +# size of the Perl module output will be much smaller and Perl will parse it
  2075 +# just the same.
  2076 +# The default value is: YES.
  2077 +# This tag requires that the tag GENERATE_PERLMOD is set to YES.
  2078 +
  2079 +PERLMOD_PRETTY = YES
  2080 +
  2081 +# The names of the make variables in the generated doxyrules.make file are
  2082 +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
  2083 +# so different doxyrules.make files included by the same Makefile don't
  2084 +# overwrite each other's variables.
  2085 +# This tag requires that the tag GENERATE_PERLMOD is set to YES.
  2086 +
  2087 +PERLMOD_MAKEVAR_PREFIX =
  2088 +
  2089 +#---------------------------------------------------------------------------
  2090 +# Configuration options related to the preprocessor
  2091 +#---------------------------------------------------------------------------
  2092 +
  2093 +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
  2094 +# C-preprocessor directives found in the sources and include files.
  2095 +# The default value is: YES.
  2096 +
  2097 +ENABLE_PREPROCESSING = YES
  2098 +
  2099 +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
  2100 +# in the source code. If set to NO, only conditional compilation will be
  2101 +# performed. Macro expansion can be done in a controlled way by setting
  2102 +# EXPAND_ONLY_PREDEF to YES.
  2103 +# The default value is: NO.
  2104 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2105 +
  2106 +MACRO_EXPANSION = NO
  2107 +
  2108 +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
  2109 +# the macro expansion is limited to the macros specified with the PREDEFINED and
  2110 +# EXPAND_AS_DEFINED tags.
  2111 +# The default value is: NO.
  2112 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2113 +
  2114 +EXPAND_ONLY_PREDEF = NO
  2115 +
  2116 +# If the SEARCH_INCLUDES tag is set to YES, the include files in the
  2117 +# INCLUDE_PATH will be searched if a #include is found.
  2118 +# The default value is: YES.
  2119 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2120 +
  2121 +SEARCH_INCLUDES = YES
  2122 +
  2123 +# The INCLUDE_PATH tag can be used to specify one or more directories that
  2124 +# contain include files that are not input files but should be processed by the
  2125 +# preprocessor.
  2126 +# This tag requires that the tag SEARCH_INCLUDES is set to YES.
  2127 +
  2128 +INCLUDE_PATH =
  2129 +
  2130 +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
  2131 +# patterns (like *.h and *.hpp) to filter out the header-files in the
  2132 +# directories. If left blank, the patterns specified with FILE_PATTERNS will be
  2133 +# used.
  2134 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2135 +
  2136 +INCLUDE_FILE_PATTERNS =
  2137 +
  2138 +# The PREDEFINED tag can be used to specify one or more macro names that are
  2139 +# defined before the preprocessor is started (similar to the -D option of e.g.
  2140 +# gcc). The argument of the tag is a list of macros of the form: name or
  2141 +# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
  2142 +# is assumed. To prevent a macro definition from being undefined via #undef or
  2143 +# recursively expanded use the := operator instead of the = operator.
  2144 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2145 +
  2146 +PREDEFINED =
  2147 +
  2148 +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
  2149 +# tag can be used to specify a list of macro names that should be expanded. The
  2150 +# macro definition that is found in the sources will be used. Use the PREDEFINED
  2151 +# tag if you want to use a different macro definition that overrules the
  2152 +# definition found in the source code.
  2153 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2154 +
  2155 +EXPAND_AS_DEFINED =
  2156 +
  2157 +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
  2158 +# remove all references to function-like macros that are alone on a line, have
  2159 +# an all uppercase name, and do not end with a semicolon. Such function macros
  2160 +# are typically used for boiler-plate code, and will confuse the parser if not
  2161 +# removed.
  2162 +# The default value is: YES.
  2163 +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
  2164 +
  2165 +SKIP_FUNCTION_MACROS = YES
  2166 +
  2167 +#---------------------------------------------------------------------------
  2168 +# Configuration options related to external references
  2169 +#---------------------------------------------------------------------------
  2170 +
  2171 +# The TAGFILES tag can be used to specify one or more tag files. For each tag
  2172 +# file the location of the external documentation should be added. The format of
  2173 +# a tag file without this location is as follows:
  2174 +# TAGFILES = file1 file2 ...
  2175 +# Adding location for the tag files is done as follows:
  2176 +# TAGFILES = file1=loc1 "file2 = loc2" ...
  2177 +# where loc1 and loc2 can be relative or absolute paths or URLs. See the
  2178 +# section "Linking to external documentation" for more information about the use
  2179 +# of tag files.
  2180 +# Note: Each tag file must have a unique name (where the name does NOT include
  2181 +# the path). If a tag file is not located in the directory in which doxygen is
  2182 +# run, you must also specify the path to the tagfile here.
  2183 +
  2184 +TAGFILES =
  2185 +
  2186 +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
  2187 +# tag file that is based on the input files it reads. See section "Linking to
  2188 +# external documentation" for more information about the usage of tag files.
  2189 +
  2190 +GENERATE_TAGFILE =
  2191 +
  2192 +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
  2193 +# the class index. If set to NO, only the inherited external classes will be
  2194 +# listed.
  2195 +# The default value is: NO.
  2196 +
  2197 +ALLEXTERNALS = NO
  2198 +
  2199 +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
  2200 +# in the modules index. If set to NO, only the current project's groups will be
  2201 +# listed.
  2202 +# The default value is: YES.
  2203 +
  2204 +EXTERNAL_GROUPS = YES
  2205 +
  2206 +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
  2207 +# the related pages index. If set to NO, only the current project's pages will
  2208 +# be listed.
  2209 +# The default value is: YES.
  2210 +
  2211 +EXTERNAL_PAGES = YES
  2212 +
  2213 +# The PERL_PATH should be the absolute path and name of the perl script
  2214 +# interpreter (i.e. the result of 'which perl').
  2215 +# The default file (with absolute path) is: /usr/bin/perl.
  2216 +
  2217 +PERL_PATH = /usr/bin/perl
  2218 +
  2219 +#---------------------------------------------------------------------------
  2220 +# Configuration options related to the dot tool
  2221 +#---------------------------------------------------------------------------
  2222 +
  2223 +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
  2224 +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
  2225 +# NO turns the diagrams off. Note that this option also works with HAVE_DOT
  2226 +# disabled, but it is recommended to install and use dot, since it yields more
  2227 +# powerful graphs.
  2228 +# The default value is: YES.
  2229 +
  2230 +CLASS_DIAGRAMS = NO
  2231 +
  2232 +# You can define message sequence charts within doxygen comments using the \msc
  2233 +# command. Doxygen will then run the mscgen tool (see:
  2234 +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
  2235 +# documentation. The MSCGEN_PATH tag allows you to specify the directory where
  2236 +# the mscgen tool resides. If left empty the tool is assumed to be found in the
  2237 +# default search path.
  2238 +
  2239 +MSCGEN_PATH =
  2240 +
  2241 +# You can include diagrams made with dia in doxygen documentation. Doxygen will
  2242 +# then run dia to produce the diagram and insert it in the documentation. The
  2243 +# DIA_PATH tag allows you to specify the directory where the dia binary resides.
  2244 +# If left empty dia is assumed to be found in the default search path.
  2245 +
  2246 +DIA_PATH =
  2247 +
  2248 +# If set to YES the inheritance and collaboration graphs will hide inheritance
  2249 +# and usage relations if the target is undocumented or is not a class.
  2250 +# The default value is: YES.
  2251 +
  2252 +HIDE_UNDOC_RELATIONS = YES
  2253 +
  2254 +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
  2255 +# available from the path. This tool is part of Graphviz (see:
  2256 +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
  2257 +# Bell Labs. The other options in this section have no effect if this option is
  2258 +# set to NO
  2259 +# The default value is: NO.
  2260 +
  2261 +HAVE_DOT = YES
  2262 +
  2263 +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
  2264 +# to run in parallel. When set to 0 doxygen will base this on the number of
  2265 +# processors available in the system. You can set it explicitly to a value
  2266 +# larger than 0 to get control over the balance between CPU load and processing
  2267 +# speed.
  2268 +# Minimum value: 0, maximum value: 32, default value: 0.
  2269 +# This tag requires that the tag HAVE_DOT is set to YES.
  2270 +
  2271 +DOT_NUM_THREADS = 0
  2272 +
  2273 +# When you want a differently looking font in the dot files that doxygen
  2274 +# generates you can specify the font name using DOT_FONTNAME. You need to make
  2275 +# sure dot is able to find the font, which can be done by putting it in a
  2276 +# standard location or by setting the DOTFONTPATH environment variable or by
  2277 +# setting DOT_FONTPATH to the directory containing the font.
  2278 +# The default value is: Helvetica.
  2279 +# This tag requires that the tag HAVE_DOT is set to YES.
  2280 +
  2281 +DOT_FONTNAME = Helvetica
  2282 +
  2283 +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
  2284 +# dot graphs.
  2285 +# Minimum value: 4, maximum value: 24, default value: 10.
  2286 +# This tag requires that the tag HAVE_DOT is set to YES.
  2287 +
  2288 +DOT_FONTSIZE = 10
  2289 +
  2290 +# By default doxygen will tell dot to use the default font as specified with
  2291 +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
  2292 +# the path where dot can find it using this tag.
  2293 +# This tag requires that the tag HAVE_DOT is set to YES.
  2294 +
  2295 +DOT_FONTPATH =
  2296 +
  2297 +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
  2298 +# each documented class showing the direct and indirect inheritance relations.
  2299 +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
  2300 +# The default value is: YES.
  2301 +# This tag requires that the tag HAVE_DOT is set to YES.
  2302 +
  2303 +CLASS_GRAPH = YES
  2304 +
  2305 +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
  2306 +# graph for each documented class showing the direct and indirect implementation
  2307 +# dependencies (inheritance, containment, and class references variables) of the
  2308 +# class with other documented classes.
  2309 +# The default value is: YES.
  2310 +# This tag requires that the tag HAVE_DOT is set to YES.
  2311 +
  2312 +COLLABORATION_GRAPH = YES
  2313 +
  2314 +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
  2315 +# groups, showing the direct groups dependencies.
  2316 +# The default value is: YES.
  2317 +# This tag requires that the tag HAVE_DOT is set to YES.
  2318 +
  2319 +GROUP_GRAPHS = YES
  2320 +
  2321 +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
  2322 +# collaboration diagrams in a style similar to the OMG's Unified Modeling
  2323 +# Language.
  2324 +# The default value is: NO.
  2325 +# This tag requires that the tag HAVE_DOT is set to YES.
  2326 +
  2327 +UML_LOOK = NO
  2328 +
  2329 +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
  2330 +# class node. If there are many fields or methods and many nodes the graph may
  2331 +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
  2332 +# number of items for each type to make the size more manageable. Set this to 0
  2333 +# for no limit. Note that the threshold may be exceeded by 50% before the limit
  2334 +# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
  2335 +# but if the number exceeds 15, the total amount of fields shown is limited to
  2336 +# 10.
  2337 +# Minimum value: 0, maximum value: 100, default value: 10.
  2338 +# This tag requires that the tag HAVE_DOT is set to YES.
  2339 +
  2340 +UML_LIMIT_NUM_FIELDS = 10
  2341 +
  2342 +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
  2343 +# collaboration graphs will show the relations between templates and their
  2344 +# instances.
  2345 +# The default value is: NO.
  2346 +# This tag requires that the tag HAVE_DOT is set to YES.
  2347 +
  2348 +TEMPLATE_RELATIONS = NO
  2349 +
  2350 +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
  2351 +# YES then doxygen will generate a graph for each documented file showing the
  2352 +# direct and indirect include dependencies of the file with other documented
  2353 +# files.
  2354 +# The default value is: YES.
  2355 +# This tag requires that the tag HAVE_DOT is set to YES.
  2356 +
  2357 +INCLUDE_GRAPH = YES
  2358 +
  2359 +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
  2360 +# set to YES then doxygen will generate a graph for each documented file showing
  2361 +# the direct and indirect include dependencies of the file with other documented
  2362 +# files.
  2363 +# The default value is: YES.
  2364 +# This tag requires that the tag HAVE_DOT is set to YES.
  2365 +
  2366 +INCLUDED_BY_GRAPH = YES
  2367 +
  2368 +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
  2369 +# dependency graph for every global function or class method.
  2370 +#
  2371 +# Note that enabling this option will significantly increase the time of a run.
  2372 +# So in most cases it will be better to enable call graphs for selected
  2373 +# functions only using the \callgraph command. Disabling a call graph can be
  2374 +# accomplished by means of the command \hidecallgraph.
  2375 +# The default value is: NO.
  2376 +# This tag requires that the tag HAVE_DOT is set to YES.
  2377 +
  2378 +CALL_GRAPH = YES
  2379 +
  2380 +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
  2381 +# dependency graph for every global function or class method.
  2382 +#
  2383 +# Note that enabling this option will significantly increase the time of a run.
  2384 +# So in most cases it will be better to enable caller graphs for selected
  2385 +# functions only using the \callergraph command. Disabling a caller graph can be
  2386 +# accomplished by means of the command \hidecallergraph.
  2387 +# The default value is: NO.
  2388 +# This tag requires that the tag HAVE_DOT is set to YES.
  2389 +
  2390 +CALLER_GRAPH = YES
  2391 +
  2392 +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
  2393 +# hierarchy of all classes instead of a textual one.
  2394 +# The default value is: YES.
  2395 +# This tag requires that the tag HAVE_DOT is set to YES.
  2396 +
  2397 +GRAPHICAL_HIERARCHY = YES
  2398 +
  2399 +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
  2400 +# dependencies a directory has on other directories in a graphical way. The
  2401 +# dependency relations are determined by the #include relations between the
  2402 +# files in the directories.
  2403 +# The default value is: YES.
  2404 +# This tag requires that the tag HAVE_DOT is set to YES.
  2405 +
  2406 +DIRECTORY_GRAPH = YES
  2407 +
  2408 +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
  2409 +# generated by dot. For an explanation of the image formats see the section
  2410 +# output formats in the documentation of the dot tool (Graphviz (see:
  2411 +# http://www.graphviz.org/)).
  2412 +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
  2413 +# to make the SVG files visible in IE 9+ (other browsers do not have this
  2414 +# requirement).
  2415 +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
  2416 +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
  2417 +# png:gdiplus:gdiplus.
  2418 +# The default value is: png.
  2419 +# This tag requires that the tag HAVE_DOT is set to YES.
  2420 +
  2421 +DOT_IMAGE_FORMAT = png
  2422 +
  2423 +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
  2424 +# enable generation of interactive SVG images that allow zooming and panning.
  2425 +#
  2426 +# Note that this requires a modern browser other than Internet Explorer. Tested
  2427 +# and working are Firefox, Chrome, Safari, and Opera.
  2428 +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
  2429 +# the SVG files visible. Older versions of IE do not have SVG support.
  2430 +# The default value is: NO.
  2431 +# This tag requires that the tag HAVE_DOT is set to YES.
  2432 +
  2433 +INTERACTIVE_SVG = NO
  2434 +
  2435 +# The DOT_PATH tag can be used to specify the path where the dot tool can be
  2436 +# found. If left blank, it is assumed the dot tool can be found in the path.
  2437 +# This tag requires that the tag HAVE_DOT is set to YES.
  2438 +
  2439 +DOT_PATH =
  2440 +
  2441 +# The DOTFILE_DIRS tag can be used to specify one or more directories that
  2442 +# contain dot files that are included in the documentation (see the \dotfile
  2443 +# command).
  2444 +# This tag requires that the tag HAVE_DOT is set to YES.
  2445 +
  2446 +DOTFILE_DIRS =
  2447 +
  2448 +# The MSCFILE_DIRS tag can be used to specify one or more directories that
  2449 +# contain msc files that are included in the documentation (see the \mscfile
  2450 +# command).
  2451 +
  2452 +MSCFILE_DIRS =
  2453 +
  2454 +# The DIAFILE_DIRS tag can be used to specify one or more directories that
  2455 +# contain dia files that are included in the documentation (see the \diafile
  2456 +# command).
  2457 +
  2458 +DIAFILE_DIRS =
  2459 +
  2460 +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
  2461 +# path where java can find the plantuml.jar file. If left blank, it is assumed
  2462 +# PlantUML is not used or called during a preprocessing step. Doxygen will
  2463 +# generate a warning when it encounters a \startuml command in this case and
  2464 +# will not generate output for the diagram.
  2465 +
  2466 +PLANTUML_JAR_PATH =
  2467 +
  2468 +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
  2469 +# configuration file for plantuml.
  2470 +
  2471 +PLANTUML_CFG_FILE =
  2472 +
  2473 +# When using plantuml, the specified paths are searched for files specified by
  2474 +# the !include statement in a plantuml block.
  2475 +
  2476 +PLANTUML_INCLUDE_PATH =
  2477 +
  2478 +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
  2479 +# that will be shown in the graph. If the number of nodes in a graph becomes
  2480 +# larger than this value, doxygen will truncate the graph, which is visualized
  2481 +# by representing a node as a red box. Note that doxygen if the number of direct
  2482 +# children of the root node in a graph is already larger than
  2483 +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
  2484 +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
  2485 +# Minimum value: 0, maximum value: 10000, default value: 50.
  2486 +# This tag requires that the tag HAVE_DOT is set to YES.
  2487 +
  2488 +DOT_GRAPH_MAX_NODES = 50
  2489 +
  2490 +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
  2491 +# generated by dot. A depth value of 3 means that only nodes reachable from the
  2492 +# root by following a path via at most 3 edges will be shown. Nodes that lay
  2493 +# further from the root node will be omitted. Note that setting this option to 1
  2494 +# or 2 may greatly reduce the computation time needed for large code bases. Also
  2495 +# note that the size of a graph can be further restricted by
  2496 +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
  2497 +# Minimum value: 0, maximum value: 1000, default value: 0.
  2498 +# This tag requires that the tag HAVE_DOT is set to YES.
  2499 +
  2500 +MAX_DOT_GRAPH_DEPTH = 0
  2501 +
  2502 +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
  2503 +# background. This is disabled by default, because dot on Windows does not seem
  2504 +# to support this out of the box.
  2505 +#
  2506 +# Warning: Depending on the platform used, enabling this option may lead to
  2507 +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
  2508 +# read).
  2509 +# The default value is: NO.
  2510 +# This tag requires that the tag HAVE_DOT is set to YES.
  2511 +
  2512 +DOT_TRANSPARENT = NO
  2513 +
  2514 +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
  2515 +# files in one run (i.e. multiple -o and -T options on the command line). This
  2516 +# makes dot run faster, but since only newer versions of dot (>1.8.10) support
  2517 +# this, this feature is disabled by default.
  2518 +# The default value is: NO.
  2519 +# This tag requires that the tag HAVE_DOT is set to YES.
  2520 +
  2521 +DOT_MULTI_TARGETS = NO
  2522 +
  2523 +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
  2524 +# explaining the meaning of the various boxes and arrows in the dot generated
  2525 +# graphs.
  2526 +# The default value is: YES.
  2527 +# This tag requires that the tag HAVE_DOT is set to YES.
  2528 +
  2529 +GENERATE_LEGEND = YES
  2530 +
  2531 +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
  2532 +# files that are used to generate the various graphs.
  2533 +# The default value is: YES.
  2534 +# This tag requires that the tag HAVE_DOT is set to YES.
  2535 +
  2536 +DOT_CLEANUP = YES
src/qmqtt.cpp 0 → 100644
  1 +++ a/src/qmqtt.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt.h"
  23 +#include "log.h"
  24 +
  25 +using namespace osdev::components;
  26 +
  27 +QMQTTClient::QMQTTClient( const QMqttConfigSettings& connectionSettings, QObject *parent )
  28 + : QObject(parent)
  29 + , m_qhConnections()
  30 + , m_connConfig( connectionSettings )
  31 +{
  32 +
  33 +}
  34 +
  35 +QMQTTClient::~QMQTTClient()
  36 +{
  37 + // Clean up any connections we have.
  38 + for( auto key : m_qhConnections.keys())
  39 + {
  40 + QPointer<QMqttPubSubClient> pTemp = m_qhConnections.take( key );
  41 + if(pTemp)
  42 + {
  43 + delete pTemp.data();
  44 + }
  45 + }
  46 +}
  47 +
  48 +void QMQTTClient::subscribe( const QString& mqtt_topic )
  49 +{
  50 + if(!topicExists( mqtt_topic ) )
  51 + {
  52 + if( !createNewThread( mqtt_topic ) )
  53 + {
  54 + LogError("[QMQTTClient::subscribe]", QString("There was an error creating a subscription to : %1").arg(mqtt_topic));
  55 + }
  56 + }
  57 +
  58 + if( topicExists( mqtt_topic ) )
  59 + {
  60 + m_qhConnections.value( mqtt_topic )->subscribe( mqtt_topic );
  61 + }
  62 +}
  63 +
  64 +void QMQTTClient::unsubscribe(const QString& mqtt_topic)
  65 +{
  66 + if( topicExists( mqtt_topic ) )
  67 + {
  68 + m_qhConnections.value( mqtt_topic )->unsubscribe( mqtt_topic );
  69 + }
  70 +}
  71 +
  72 +void QMQTTClient::publish(const QString& mqtt_topic, const QString& mqtt_message)
  73 +{
  74 + if( !topicExists( mqtt_topic ) )
  75 + {
  76 + if( !createNewThread( mqtt_topic ) )
  77 + {
  78 + LogError("[QMQTTClient::publish]", QString("There was an error creating publishing to : %1").arg( mqtt_topic ) );
  79 + }
  80 + }
  81 +
  82 + if(topicExists(mqtt_topic))
  83 + {
  84 + m_qhConnections.value(mqtt_topic)->publish(mqtt_topic, mqtt_message);
  85 + }
  86 +}
  87 +
  88 +bool QMQTTClient::createNewThread(const QString& topic)
  89 +{
  90 + QPointer<QMqttPubSubClient> pThread = new QMqttPubSubClient(m_connConfig.getHostAddress(), m_connConfig.getPortNumber() );
  91 + if(pThread)
  92 + {
  93 + connect( pThread.data(), &QMqttPubSubClient::signalMessageReceived, this, &QMQTTClient::signalNewMessageReceived );
  94 + connect( pThread.data(), &QMqttPubSubClient::signalReInitialise, this, &QMQTTClient::signalReInitialize );
  95 + m_qhConnections.insert( topic, pThread );
  96 + }
  97 + return m_qhConnections.contains( topic );
  98 +}
  99 +
  100 +bool QMQTTClient::topicExists( const QString& topic )
  101 +{
  102 + if( m_qhConnections.contains( topic ) )
  103 + return true;
  104 + else
  105 + return false;
  106 +}
src/qmqtt.h 0 → 100644
  1 +++ a/src/qmqtt.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef OSDEV_COMPONENTS_QMQTT_H
  23 +#define OSDEV_COMPONENTS_QMQTT_H
  24 +
  25 +#include <QObject>
  26 +#include <QString>
  27 +#include <QHash>
  28 +#include <QPointer>
  29 +
  30 +#include "qmqtt_pubsubclient.h"
  31 +#include "qmqtt_configsettings.h"
  32 +
  33 +namespace osdev {
  34 +namespace components {
  35 +
  36 +class QMQTTClient : public QObject
  37 +{
  38 + Q_OBJECT
  39 +
  40 +public:
  41 + QMQTTClient( const QMqttConfigSettings& connectionSettings = QMqttConfigSettings(), QObject *parent = nullptr );
  42 + virtual ~QMQTTClient();
  43 +
  44 + void subscribe( const QString& mqtt_topic );
  45 + void unsubscribe( const QString& mqtt_topic );
  46 + void publish( const QString& mqtt_topic, const QString& mqtt_message );
  47 +
  48 + int getNumberOfConnections(){ return m_qhConnections.count(); }
  49 +
  50 +signals:
  51 + void signalNewMessageReceived( const QString& mqtt_topic, const QString& mqtt_message );
  52 + void signalReInitialize();
  53 +
  54 +private:
  55 + bool topicExists( const QString& topic );
  56 + bool createNewThread( const QString& topic );
  57 +
  58 +private: // Members (Giggity!)
  59 + QHash<QString, QPointer<QMqttPubSubClient>> m_qhConnections; ///< The container that keeps track of all connections by their topics.
  60 + QMqttConfigSettings m_connConfig; ///< All kinds of connection parameters in a convenient object.
  61 +
  62 +};
  63 +
  64 +} /* End namespace components */
  65 +} /* End namespace osdev */
  66 +
  67 +#endif /* OSDEV_COMPONENTS_QMQTT_H */
src/qmqtt_client.cpp 0 → 100644
  1 +++ a/src/qmqtt_client.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_client.h"
  23 +#include "qmqtt_client_p.h"
  24 +
  25 +QMQTT::Client::Client(const QHostAddress& host,
  26 + const quint16 port,
  27 + QObject* parent)
  28 + : QObject(parent)
  29 + , d_ptr(new ClientPrivate(this))
  30 +{
  31 + Q_D(Client);
  32 + d->init(host, port);
  33 +}
  34 +
  35 +#ifndef QT_NO_SSL
  36 +QMQTT::Client::Client(const QString &hostName,
  37 + const quint16 port,
  38 + const QSslConfiguration &config,
  39 + const bool ignoreSelfSigned, QObject *parent)
  40 + : QObject(parent)
  41 + , d_ptr(new ClientPrivate(this))
  42 +{
  43 + Q_D(Client);
  44 + d->init(hostName, port, config, ignoreSelfSigned);
  45 +}
  46 +#endif // QT_NO_SSL
  47 +
  48 +QMQTT::Client::Client(const QString &hostName,
  49 + const quint16 port,
  50 + const bool ssl,
  51 + const bool ignoreSelfSigned,
  52 + QObject* parent)
  53 + : QObject(parent)
  54 + , d_ptr(new ClientPrivate(this))
  55 +{
  56 + Q_D(Client);
  57 + d->init(hostName, port, ssl, ignoreSelfSigned);
  58 +}
  59 +
  60 +#ifdef QT_WEBSOCKETS_LIB
  61 +QMQTT::Client::Client(const QString& url,
  62 + const QString& origin,
  63 + QWebSocketProtocol::Version version,
  64 + bool ignoreSelfSigned,
  65 + QObject* parent)
  66 + : QObject(parent)
  67 + , d_ptr(new ClientPrivate(this))
  68 +{
  69 + Q_D(Client);
  70 +#ifndef QT_NO_SSL
  71 + d->init(url, origin, version, NULL, ignoreSelfSigned);
  72 +#else
  73 + Q_UNUSED(ignoreSelfSigned)
  74 + d->init(url, origin, version);
  75 +#endif // QT_NO_SSL
  76 +}
  77 +
  78 +#ifndef QT_NO_SSL
  79 +QMQTT::Client::Client(const QString& url,
  80 + const QString& origin,
  81 + QWebSocketProtocol::Version version,
  82 + const QSslConfiguration& sslConfig,
  83 + const bool ignoreSelfSigned,
  84 + QObject* parent)
  85 + : QObject(parent)
  86 + , d_ptr(new ClientPrivate(this))
  87 +{
  88 + Q_D(Client);
  89 + d->init(url, origin, version, &sslConfig, ignoreSelfSigned);
  90 +}
  91 +#endif // QT_NO_SSL
  92 +#endif // QT_WEBSOCKETS_LIB
  93 +
  94 +QMQTT::Client::Client(NetworkInterface* network,
  95 + const QHostAddress& host,
  96 + const quint16 port,
  97 + QObject* parent)
  98 + : QObject(parent)
  99 + , d_ptr(new ClientPrivate(this))
  100 +{
  101 + Q_D(Client);
  102 + d->init(host, port, network);
  103 +}
  104 +
  105 +QMQTT::Client::~Client()
  106 +{
  107 +}
  108 +
  109 +QHostAddress QMQTT::Client::host() const
  110 +{
  111 + Q_D(const Client);
  112 + return d->host();
  113 +}
  114 +
  115 +void QMQTT::Client::setHost(const QHostAddress& host)
  116 +{
  117 + Q_D(Client);
  118 + d->setHost(host);
  119 +}
  120 +
  121 +QString QMQTT::Client::hostName() const
  122 +{
  123 + Q_D(const Client);
  124 + return d->hostName();
  125 +}
  126 +
  127 +void QMQTT::Client::setHostName(const QString &hostName)
  128 +{
  129 + Q_D(Client);
  130 + d->setHostName(hostName);
  131 +}
  132 +
  133 +quint16 QMQTT::Client::port() const
  134 +{
  135 + Q_D(const Client);
  136 + return d->port();
  137 +}
  138 +
  139 +void QMQTT::Client::setPort(const quint16 port)
  140 +{
  141 + Q_D(Client);
  142 + d->setPort(port);
  143 +}
  144 +
  145 +QString QMQTT::Client::clientId() const
  146 +{
  147 + Q_D(const Client);
  148 + return d->clientId();
  149 +}
  150 +
  151 +void QMQTT::Client::setClientId(const QString& clientId)
  152 +{
  153 + Q_D(Client);
  154 + d->setClientId(clientId);
  155 +}
  156 +
  157 +QString QMQTT::Client::username() const
  158 +{
  159 + Q_D(const Client);
  160 + return d->username();
  161 +}
  162 +
  163 +void QMQTT::Client::setUsername(const QString& username)
  164 +{
  165 + Q_D(Client);
  166 + d->setUsername(username);
  167 +}
  168 +
  169 +QMQTT::MQTTVersion QMQTT::Client::version() const
  170 +{
  171 + Q_D(const Client);
  172 + return d->version();
  173 +}
  174 +
  175 +void QMQTT::Client::setVersion(const QMQTT::MQTTVersion version)
  176 +{
  177 + Q_D(Client);
  178 + d->setVersion(version);
  179 +}
  180 +
  181 +QByteArray QMQTT::Client::password() const
  182 +{
  183 + Q_D(const Client);
  184 + return d->password();
  185 +}
  186 +
  187 +void QMQTT::Client::setPassword(const QByteArray &password)
  188 +{
  189 + Q_D(Client);
  190 + d->setPassword(password);
  191 +}
  192 +
  193 +quint16 QMQTT::Client::keepAlive() const
  194 +{
  195 + Q_D(const Client);
  196 + return d->keepAlive();
  197 +}
  198 +
  199 +void QMQTT::Client::setKeepAlive(const quint16 keepAlive)
  200 +{
  201 + Q_D(Client);
  202 + d->setKeepAlive(keepAlive);
  203 +}
  204 +
  205 +bool QMQTT::Client::cleanSession() const
  206 +{
  207 + Q_D(const Client);
  208 + return d->cleanSession();
  209 +}
  210 +
  211 +void QMQTT::Client::setCleanSession(const bool cleanSession)
  212 +{
  213 + Q_D(Client);
  214 + d->setCleanSession(cleanSession);
  215 +}
  216 +
  217 +bool QMQTT::Client::autoReconnect() const
  218 +{
  219 + Q_D(const Client);
  220 + return d->autoReconnect();
  221 +}
  222 +
  223 +void QMQTT::Client::setAutoReconnect(const bool value)
  224 +{
  225 + Q_D(Client);
  226 + d->setAutoReconnect(value);
  227 +}
  228 +
  229 +int QMQTT::Client::autoReconnectInterval() const
  230 +{
  231 + Q_D(const Client);
  232 + return d->autoReconnectInterval();
  233 +}
  234 +
  235 +void QMQTT::Client::setAutoReconnectInterval(const int autoReconnectInterval)
  236 +{
  237 + Q_D(Client);
  238 + d->setAutoReconnectInterval(autoReconnectInterval);
  239 +}
  240 +
  241 +QString QMQTT::Client::willTopic() const
  242 +{
  243 + Q_D(const Client);
  244 + return d->willTopic();
  245 +}
  246 +
  247 +void QMQTT::Client::setWillTopic(const QString& willTopic)
  248 +{
  249 + Q_D(Client);
  250 + d->setWillTopic(willTopic);
  251 +}
  252 +
  253 +quint8 QMQTT::Client::willQos() const
  254 +{
  255 + Q_D(const Client);
  256 + return d->willQos();
  257 +}
  258 +
  259 +void QMQTT::Client::setWillQos(const quint8 willQos)
  260 +{
  261 + Q_D(Client);
  262 + d->setWillQos(willQos);
  263 +}
  264 +
  265 +bool QMQTT::Client::willRetain() const
  266 +{
  267 + Q_D(const Client);
  268 + return d->willRetain();
  269 +}
  270 +
  271 +void QMQTT::Client::setWillRetain(const bool willRetain)
  272 +{
  273 + Q_D(Client);
  274 + d->setWillRetain(willRetain);
  275 +}
  276 +
  277 +QByteArray QMQTT::Client::willMessage() const
  278 +{
  279 + Q_D(const Client);
  280 + return d->willMessage();
  281 +}
  282 +
  283 +void QMQTT::Client::setWillMessage(const QByteArray &willMessage)
  284 +{
  285 + Q_D(Client);
  286 + d->setWillMessage(willMessage);
  287 +}
  288 +
  289 +QMQTT::ConnectionState QMQTT::Client::connectionState() const
  290 +{
  291 + Q_D(const Client);
  292 + return d->connectionState();
  293 +}
  294 +
  295 +bool QMQTT::Client::isConnectedToHost() const
  296 +{
  297 + Q_D(const Client);
  298 + return d->isConnectedToHost();
  299 +}
  300 +
  301 +#ifndef QT_NO_SSL
  302 +QSslConfiguration QMQTT::Client::sslConfiguration() const
  303 +{
  304 + Q_D(const Client);
  305 + return d->sslConfiguration();
  306 +}
  307 +
  308 +void QMQTT::Client::setSslConfiguration(const QSslConfiguration& config)
  309 +{
  310 + Q_D(Client);
  311 + d->setSslConfiguration(config);
  312 +}
  313 +#endif // QT_NO_SSL
  314 +
  315 +void QMQTT::Client::connectToHost()
  316 +{
  317 + Q_D(Client);
  318 + d->connectToHost();
  319 +}
  320 +
  321 +void QMQTT::Client::onNetworkConnected()
  322 +{
  323 + Q_D(Client);
  324 + d->onNetworkConnected();
  325 +}
  326 +
  327 +quint16 QMQTT::Client::publish(const Message& message)
  328 +{
  329 + Q_D(Client);
  330 + return d->publish(message);
  331 +}
  332 +
  333 +void QMQTT::Client::subscribe(const QString& topic, const quint8 qos)
  334 +{
  335 + Q_D(Client);
  336 + d->subscribe(topic, qos);
  337 +}
  338 +
  339 +void QMQTT::Client::unsubscribe(const QString& topic)
  340 +{
  341 + Q_D(Client);
  342 + d->unsubscribe(topic);
  343 +}
  344 +
  345 +void QMQTT::Client::onTimerPingReq()
  346 +{
  347 + Q_D(Client);
  348 + d->onTimerPingReq();
  349 +}
  350 +
  351 +void QMQTT::Client::onPingTimeout()
  352 +{
  353 + Q_D(Client);
  354 + d->onPingTimeout();
  355 +}
  356 +
  357 +void QMQTT::Client::disconnectFromHost()
  358 +{
  359 + Q_D(Client);
  360 + d->disconnectFromHost();
  361 +}
  362 +
  363 +void QMQTT::Client::onNetworkReceived(const QMQTT::Frame& frame)
  364 +{
  365 + Q_D(Client);
  366 + d->onNetworkReceived(frame);
  367 +}
  368 +
  369 +void QMQTT::Client::onNetworkDisconnected()
  370 +{
  371 + Q_D(Client);
  372 + d->onNetworkDisconnected();
  373 +}
  374 +
  375 +void QMQTT::Client::onNetworkError(QAbstractSocket::SocketError error)
  376 +{
  377 + Q_D(Client);
  378 + d->onNetworkError(error);
  379 +}
  380 +
  381 +#ifndef QT_NO_SSL
  382 +void QMQTT::Client::onSslErrors(const QList<QSslError>& errors)
  383 +{
  384 + Q_D(Client);
  385 + d->onSslErrors(errors);
  386 +}
  387 +#endif // QT_NO_SSL
  388 +
  389 +#ifndef QT_NO_SSL
  390 +void QMQTT::Client::ignoreSslErrors()
  391 +{
  392 + Q_D(Client);
  393 + d->ignoreSslErrors();
  394 +}
  395 +
  396 +void QMQTT::Client::ignoreSslErrors(const QList<QSslError>& errors)
  397 +{
  398 + Q_D(Client);
  399 + d->ignoreSslErrors(errors);
  400 +}
  401 +#endif // QT_NO_SSL
src/qmqtt_client.h 0 → 100644
  1 +++ a/src/qmqtt_client.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_CLIENT_H
  23 +#define QMQTT_CLIENT_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QObject>
  28 +#include <QString>
  29 +#include <QHostAddress>
  30 +#include <QByteArray>
  31 +#include <QAbstractSocket>
  32 +#include <QScopedPointer>
  33 +#include <QList>
  34 +
  35 +#ifdef QT_WEBSOCKETS_LIB
  36 +#include <QWebSocket>
  37 +#endif // QT_WEBSOCKETS_LIB
  38 +
  39 +#ifndef QT_NO_SSL
  40 +#include <QSslConfiguration>
  41 +QT_FORWARD_DECLARE_CLASS(QSslError)
  42 +#endif // QT_NO_SSL
  43 +
  44 +#ifndef Q_ENUM_NS
  45 +#define Q_ENUM_NS(x)
  46 +#endif // Q_ENUM_NS
  47 +
  48 +namespace QMQTT {
  49 +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
  50 +Q_MQTT_EXPORT Q_NAMESPACE
  51 +#endif
  52 +
  53 +static const quint8 LIBRARY_VERSION_MAJOR = 0;
  54 +static const quint8 LIBRARY_VERSION_MINOR = 3;
  55 +static const quint8 LIBRARY_VERSION_REVISION = 1;
  56 +//static const char* LIBRARY_VERSION = "0.3.1";
  57 +
  58 +enum MQTTVersion
  59 +{
  60 + V3_1_0 = 3,
  61 + V3_1_1 = 4
  62 +};
  63 +Q_ENUM_NS(MQTTVersion)
  64 +
  65 +enum ConnectionState
  66 +{
  67 + STATE_INIT = 0,
  68 + STATE_CONNECTING,
  69 + STATE_CONNECTED,
  70 + STATE_DISCONNECTED
  71 +};
  72 +Q_ENUM_NS(ConnectionState)
  73 +
  74 +enum ClientError
  75 +{
  76 + UnknownError = 0,
  77 + SocketConnectionRefusedError,
  78 + SocketRemoteHostClosedError,
  79 + SocketHostNotFoundError,
  80 + SocketAccessError,
  81 + SocketResourceError,
  82 + SocketTimeoutError,
  83 + SocketDatagramTooLargeError,
  84 + SocketNetworkError,
  85 + SocketAddressInUseError,
  86 + SocketAddressNotAvailableError,
  87 + SocketUnsupportedSocketOperationError,
  88 + SocketUnfinishedSocketOperationError,
  89 + SocketProxyAuthenticationRequiredError,
  90 + SocketSslHandshakeFailedError,
  91 + SocketProxyConnectionRefusedError,
  92 + SocketProxyConnectionClosedError,
  93 + SocketProxyConnectionTimeoutError,
  94 + SocketProxyNotFoundError,
  95 + SocketProxyProtocolError,
  96 + SocketOperationError,
  97 + SocketSslInternalError,
  98 + SocketSslInvalidUserDataError,
  99 + SocketTemporaryError,
  100 + MqttUnacceptableProtocolVersionError=1<<16,
  101 + MqttIdentifierRejectedError,
  102 + MqttServerUnavailableError,
  103 + MqttBadUserNameOrPasswordError,
  104 + MqttNotAuthorizedError,
  105 + MqttNoPingResponse
  106 +};
  107 +Q_ENUM_NS(ClientError)
  108 +
  109 +class ClientPrivate;
  110 +class Message;
  111 +class Frame;
  112 +class NetworkInterface;
  113 +
  114 +class Q_MQTT_EXPORT Client : public QObject
  115 +{
  116 + Q_OBJECT
  117 + Q_PROPERTY(quint16 _port READ port WRITE setPort)
  118 + Q_PROPERTY(QHostAddress _host READ host WRITE setHost)
  119 + Q_PROPERTY(QString _hostName READ hostName WRITE setHostName)
  120 + Q_PROPERTY(QString _clientId READ clientId WRITE setClientId)
  121 + Q_PROPERTY(QString _username READ username WRITE setUsername)
  122 + Q_PROPERTY(QByteArray _password READ password WRITE setPassword)
  123 + Q_PROPERTY(quint16 _keepAlive READ keepAlive WRITE setKeepAlive)
  124 + Q_PROPERTY(MQTTVersion _version READ version WRITE setVersion)
  125 + Q_PROPERTY(bool _autoReconnect READ autoReconnect WRITE setAutoReconnect)
  126 + Q_PROPERTY(int _autoReconnectInterval READ autoReconnectInterval WRITE setAutoReconnectInterval)
  127 + Q_PROPERTY(bool _cleanSession READ cleanSession WRITE setCleanSession)
  128 + Q_PROPERTY(QString _willTopic READ willTopic WRITE setWillTopic)
  129 + Q_PROPERTY(quint8 _willQos READ willQos WRITE setWillQos)
  130 + Q_PROPERTY(bool _willRetain READ willRetain WRITE setWillRetain)
  131 + Q_PROPERTY(QByteArray _willMessage READ willMessage WRITE setWillMessage)
  132 + Q_PROPERTY(QString _connectionState READ connectionState)
  133 +#ifndef QT_NO_SSL
  134 + Q_PROPERTY(QSslConfiguration _sslConfiguration READ sslConfiguration WRITE setSslConfiguration)
  135 +#endif // QT_NO_SSL
  136 +
  137 +public:
  138 + Client(const QHostAddress& host = QHostAddress::LocalHost,
  139 + const quint16 port = 1883,
  140 + QObject* parent = NULL);
  141 +
  142 +#ifndef QT_NO_SSL
  143 + Client(const QString& hostName,
  144 + const quint16 port,
  145 + const QSslConfiguration& config,
  146 + const bool ignoreSelfSigned=false,
  147 + QObject* parent = NULL);
  148 +#endif // QT_NO_SSL
  149 +
  150 + // This function is provided for backward compatibility with older versions of QMQTT.
  151 + // If the ssl parameter is true, this function will load a private key ('cert.key') and a local
  152 + // certificate ('cert.crt') from the current working directory. It will also set PeerVerifyMode
  153 + // to None. This may not be the safest way to set up an SSL connection.
  154 + Client(const QString& hostName,
  155 + const quint16 port,
  156 + const bool ssl,
  157 + const bool ignoreSelfSigned,
  158 + QObject* parent = NULL);
  159 +
  160 +#ifdef QT_WEBSOCKETS_LIB
  161 + // Create a connection over websockets
  162 + Client(const QString& url,
  163 + const QString& origin,
  164 + QWebSocketProtocol::Version version,
  165 + bool ignoreSelfSigned = false,
  166 + QObject* parent = NULL);
  167 +
  168 +#ifndef QT_NO_SSL
  169 + Client(const QString& url,
  170 + const QString& origin,
  171 + QWebSocketProtocol::Version version,
  172 + const QSslConfiguration& config,
  173 + const bool ignoreSelfSigned = false,
  174 + QObject* parent = NULL);
  175 +#endif // QT_NO_SSL
  176 +#endif // QT_WEBSOCKETS_LIB
  177 +
  178 + // for testing purposes only
  179 + Client(NetworkInterface* network,
  180 + const QHostAddress& host = QHostAddress::LocalHost,
  181 + const quint16 port = 1883,
  182 + QObject* parent = NULL);
  183 +
  184 + virtual ~Client();
  185 +
  186 + QHostAddress host() const;
  187 + QString hostName() const;
  188 + quint16 port() const;
  189 + QString clientId() const;
  190 + QString username() const;
  191 + QByteArray password() const;
  192 + QMQTT::MQTTVersion version() const;
  193 + quint16 keepAlive() const;
  194 + bool cleanSession() const;
  195 + bool autoReconnect() const;
  196 + int autoReconnectInterval() const;
  197 + ConnectionState connectionState() const;
  198 + QString willTopic() const;
  199 + quint8 willQos() const;
  200 + bool willRetain() const;
  201 + QByteArray willMessage() const;
  202 +
  203 + bool isConnectedToHost() const;
  204 +#ifndef QT_NO_SSL
  205 + QSslConfiguration sslConfiguration() const;
  206 + void setSslConfiguration(const QSslConfiguration& config);
  207 +#endif // QT_NO_SSL
  208 +
  209 +public slots:
  210 + void setHost(const QHostAddress& host);
  211 + void setHostName(const QString& hostName);
  212 + void setPort(const quint16 port);
  213 + void setClientId(const QString& clientId);
  214 + void setUsername(const QString& username);
  215 + void setPassword(const QByteArray& password);
  216 + void setVersion(const MQTTVersion version);
  217 + void setKeepAlive(const quint16 keepAlive);
  218 + void setCleanSession(const bool cleanSession);
  219 + void setAutoReconnect(const bool value);
  220 + void setAutoReconnectInterval(const int autoReconnectInterval);
  221 + void setWillTopic(const QString& willTopic);
  222 + void setWillQos(const quint8 willQos);
  223 + void setWillRetain(const bool willRetain);
  224 + void setWillMessage(const QByteArray& willMessage);
  225 +
  226 + void connectToHost();
  227 + void disconnectFromHost();
  228 +
  229 + void subscribe(const QString& topic, const quint8 qos = 0);
  230 + void unsubscribe(const QString& topic);
  231 +
  232 + quint16 publish(const QMQTT::Message& message);
  233 +
  234 +#ifndef QT_NO_SSL
  235 + void ignoreSslErrors();
  236 + void ignoreSslErrors(const QList<QSslError>& errors);
  237 +#endif // QT_NO_SSL
  238 +
  239 +signals:
  240 + void connected();
  241 + void disconnected();
  242 + void error(const QMQTT::ClientError error);
  243 +
  244 + void subscribed(const QString& topic, const quint8 qos = 0);
  245 + void unsubscribed(const QString& topic);
  246 + void published(const QMQTT::Message& message, quint16 msgid = 0);
  247 + void received(const QMQTT::Message& message);
  248 + void pingresp();
  249 +#ifndef QT_NO_SSL
  250 + void sslErrors(const QList<QSslError>& errors);
  251 +#endif // QT_NO_SSL
  252 +
  253 +protected slots:
  254 + void onNetworkConnected();
  255 + void onNetworkDisconnected();
  256 + void onNetworkReceived(const QMQTT::Frame& frame);
  257 + void onTimerPingReq();
  258 + void onPingTimeout();
  259 + void onNetworkError(QAbstractSocket::SocketError error);
  260 +#ifndef QT_NO_SSL
  261 + void onSslErrors(const QList<QSslError>& errors);
  262 +#endif // QT_NO_SSL
  263 +
  264 +protected:
  265 + QScopedPointer<ClientPrivate> d_ptr;
  266 +
  267 +private:
  268 + Q_DISABLE_COPY(Client)
  269 + Q_DECLARE_PRIVATE(Client)
  270 +};
  271 +
  272 +} // namespace QMQTT
  273 +
  274 +Q_DECLARE_METATYPE(QMQTT::ClientError)
  275 +
  276 +#endif // QMQTT_CLIENT_H
src/qmqtt_client_p.cpp 0 → 100644
  1 +++ a/src/qmqtt_client_p.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_client_p.h"
  23 +#include "qmqtt_network_p.h"
  24 +#include "qmqtt_frame.h"
  25 +#include "qmqtt_message.h"
  26 +
  27 +#include <QLoggingCategory>
  28 +#include <QUuid>
  29 +#ifndef QT_NO_SSL
  30 +#include <QFile>
  31 +#include <QSslConfiguration>
  32 +#include <QSslKey>
  33 +#endif // QT_NO_SSL
  34 +
  35 +Q_LOGGING_CATEGORY(client, "qmqtt.client")
  36 +
  37 +static const quint8 QOS0 = 0x00;
  38 +static const quint8 QOS1 = 0x01;
  39 +static const quint8 QOS2 = 0x02;
  40 +
  41 +QMQTT::ClientPrivate::ClientPrivate(Client* qq_ptr)
  42 + : _host(QHostAddress::LocalHost)
  43 + , _port(1883)
  44 + , _gmid(1)
  45 + , _version(MQTTVersion::V3_1_0)
  46 + , _clientId(QUuid::createUuid().toString())
  47 + , _cleanSession(false)
  48 + , _connectionState(STATE_INIT)
  49 + , _willQos(0)
  50 + , _willRetain(false)
  51 + , q_ptr(qq_ptr)
  52 +{
  53 + setKeepAlive(300);
  54 +}
  55 +
  56 +QMQTT::ClientPrivate::~ClientPrivate()
  57 +{
  58 +}
  59 +
  60 +void QMQTT::ClientPrivate::init(const QHostAddress& host, const quint16 port, NetworkInterface* network)
  61 +{
  62 + Q_Q(Client);
  63 + _host = host;
  64 + _port = port;
  65 + if(network == NULL)
  66 + {
  67 + init(new Network(q));
  68 + }
  69 + else
  70 + {
  71 + init(network);
  72 + }
  73 +}
  74 +
  75 +#ifndef QT_NO_SSL
  76 +void QMQTT::ClientPrivate::init(const QString& hostName, const quint16 port,
  77 + const QSslConfiguration &config, const bool ignoreSelfSigned)
  78 +{
  79 + Q_Q(Client);
  80 + _hostName = hostName;
  81 + _port = port;
  82 + _ignoreSelfSigned = ignoreSelfSigned;
  83 + init(new Network(config, q));
  84 + QObject::connect(_network.data(), &QMQTT::Network::sslErrors, q, &QMQTT::Client::onSslErrors);
  85 +}
  86 +#endif // QT_NO_SSL
  87 +
  88 +void QMQTT::ClientPrivate::init(const QString& hostName, const quint16 port, const bool ssl,
  89 + const bool ignoreSelfSigned)
  90 +{
  91 + Q_Q(Client);
  92 + _hostName = hostName;
  93 + _port = port;
  94 + if (ssl)
  95 + {
  96 +#ifndef QT_NO_SSL
  97 + QSslConfiguration sslConf = QSslConfiguration::defaultConfiguration();
  98 + QList<QSslCertificate> certs = QSslCertificate::fromPath(QStringLiteral("./cert.crt"));
  99 + if (!certs.isEmpty())
  100 + sslConf.setLocalCertificate(certs.first());
  101 + QFile file(QStringLiteral("./cert.key"));
  102 + if (file.open(QIODevice::ReadOnly)) {
  103 + sslConf.setPrivateKey(QSslKey(file.readAll(), QSsl::Rsa));
  104 + }
  105 + sslConf.setPeerVerifyMode(QSslSocket::VerifyNone);
  106 + init(hostName, port, sslConf, ignoreSelfSigned);
  107 +#else
  108 + Q_UNUSED(ignoreSelfSigned)
  109 + qCritical() << "SSL not supported in this QT build";
  110 +#endif // QT_NO_SSL
  111 + }
  112 + else
  113 + {
  114 + init(new Network(q));
  115 + }
  116 +}
  117 +
  118 +#ifdef QT_WEBSOCKETS_LIB
  119 +#ifndef QT_NO_SSL
  120 +void QMQTT::ClientPrivate::init(const QString& url,
  121 + const QString& origin,
  122 + QWebSocketProtocol::Version version,
  123 + const QSslConfiguration* sslConfig,
  124 + bool ignoreSelfSigned)
  125 +{
  126 + Q_Q(Client);
  127 + _hostName = url;
  128 + _ignoreSelfSigned = ignoreSelfSigned;
  129 + init(new Network(origin, version, sslConfig, q));
  130 +}
  131 +#endif // QT_NO_SSL
  132 +
  133 +void QMQTT::ClientPrivate::init(const QString& url,
  134 + const QString& origin,
  135 + QWebSocketProtocol::Version version)
  136 +{
  137 + Q_Q(Client);
  138 + _hostName = url;
  139 + init(new Network(origin, version, q));
  140 +}
  141 +#endif // QT_WEBSOCKETS_LIB
  142 +
  143 +void QMQTT::ClientPrivate::init(NetworkInterface* network)
  144 +{
  145 + Q_Q(Client);
  146 +
  147 + _network.reset(network);
  148 + _timer.setSingleShot(true);
  149 + _pingResponseTimer.setSingleShot(true);
  150 +
  151 + QObject::connect(&_timer, &QTimer::timeout, q, &Client::onTimerPingReq);
  152 + QObject::connect(&_pingResponseTimer, &QTimer::timeout, q, &Client::onPingTimeout);
  153 + QObject::connect(_network.data(), &Network::connected,
  154 + q, &Client::onNetworkConnected);
  155 + QObject::connect(_network.data(), &Network::disconnected,
  156 + q, &Client::onNetworkDisconnected);
  157 + QObject::connect(_network.data(), &Network::received,
  158 + q, &Client::onNetworkReceived);
  159 + QObject::connect(_network.data(), &Network::error,
  160 + q, &Client::onNetworkError);
  161 +}
  162 +
  163 +void QMQTT::ClientPrivate::connectToHost()
  164 +{
  165 + _connectionState = ConnectionState::STATE_CONNECTING;
  166 + if (_hostName.isEmpty())
  167 + {
  168 + _network->connectToHost(_host, _port);
  169 + }
  170 + else
  171 + {
  172 + _network->connectToHost(_hostName, _port);
  173 + }
  174 +}
  175 +
  176 +void QMQTT::ClientPrivate::onNetworkConnected()
  177 +{
  178 + sendConnect();
  179 +}
  180 +
  181 +void QMQTT::ClientPrivate::sendConnect()
  182 +{
  183 + quint8 header = CONNECT;
  184 + quint8 flags = 0;
  185 +
  186 + //header
  187 + Frame frame(header);
  188 +
  189 + //flags
  190 + flags = FLAG_CLEANSESS(flags, _cleanSession ? 1 : 0 );
  191 + flags = FLAG_WILL(flags, willTopic().isEmpty() ? 0 : 1);
  192 + if (!willTopic().isEmpty())
  193 + {
  194 + flags = FLAG_WILLQOS(flags, willQos());
  195 + flags = FLAG_WILLRETAIN(flags, willRetain() ? 1 : 0);
  196 + }
  197 + if (!username().isEmpty())
  198 + {
  199 + flags = FLAG_USERNAME(flags, 1);
  200 + flags = FLAG_PASSWD(flags, !password().isEmpty() ? 1 : 0);
  201 + }
  202 +
  203 + //payload
  204 + if(_version == V3_1_1)
  205 + {
  206 + frame.writeString(QStringLiteral(PROTOCOL_MAGIC_3_1_1));
  207 + }
  208 + else
  209 + {
  210 + frame.writeString(QStringLiteral(PROTOCOL_MAGIC_3_1_0));
  211 + }
  212 + frame.writeChar(_version);
  213 + frame.writeChar(flags);
  214 + frame.writeInt(keepAlive());
  215 + frame.writeString(_clientId);
  216 + if(!willTopic().isEmpty())
  217 + {
  218 + frame.writeString(willTopic());
  219 + // According to the specs (http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718031)
  220 + // the will message gets always sent together with the topic, also when it is empty which is perfectly valid.
  221 + frame.writeByteArray(_willMessage);
  222 + }
  223 + if (!_username.isEmpty())
  224 + {
  225 + frame.writeString(_username);
  226 + if (!_password.isEmpty())
  227 + {
  228 + frame.writeByteArray(_password);
  229 + }
  230 + }
  231 + sendFrame(frame);
  232 +}
  233 +
  234 +quint16 QMQTT::ClientPrivate::sendPublish(const Message &message)
  235 +{
  236 + quint16 msgid = message.id();
  237 +
  238 + quint8 header = PUBLISH;
  239 + header = SETRETAIN(header, message.retain() ? 1 : 0);
  240 + header = SETQOS(header, message.qos());
  241 + header = SETDUP(header, message.dup() ? 1 : 0);
  242 + Frame frame(header);
  243 + frame.writeString(message.topic());
  244 + if(message.qos() > QOS0) {
  245 + if (msgid == 0)
  246 + msgid = nextmid();
  247 + frame.writeInt(msgid);
  248 + }
  249 + if(!message.payload().isEmpty()) {
  250 + frame.writeRawData(message.payload());
  251 + }
  252 + sendFrame(frame);
  253 + return msgid;
  254 +}
  255 +
  256 +void QMQTT::ClientPrivate::sendPuback(const quint8 type, const quint16 mid)
  257 +{
  258 + Frame frame(type);
  259 + frame.writeInt(mid);
  260 + sendFrame(frame);
  261 +}
  262 +
  263 +quint16 QMQTT::ClientPrivate::sendSubscribe(const QString & topic, const quint8 qos)
  264 +{
  265 + quint16 mid = nextmid();
  266 + Frame frame(SETQOS(SUBSCRIBE, QOS1));
  267 + frame.writeInt(mid);
  268 + frame.writeString(topic);
  269 + frame.writeChar(qos);
  270 + sendFrame(frame);
  271 + return mid;
  272 +}
  273 +
  274 +quint16 QMQTT::ClientPrivate::sendUnsubscribe(const QString &topic)
  275 +{
  276 + quint16 mid = nextmid();
  277 + Frame frame(SETQOS(UNSUBSCRIBE, QOS1));
  278 + frame.writeInt(mid);
  279 + frame.writeString(topic);
  280 + sendFrame(frame);
  281 + return mid;
  282 +}
  283 +
  284 +void QMQTT::ClientPrivate::onTimerPingReq()
  285 +{
  286 + if (!isConnectedToHost())
  287 + return;
  288 + Frame frame(PINGREQ);
  289 + sendFrame(frame);
  290 + _pingResponseTimer.start();
  291 +}
  292 +
  293 +void QMQTT::ClientPrivate::onPingTimeout()
  294 +{
  295 + Q_Q(Client);
  296 + emit q->error(MqttNoPingResponse);
  297 + disconnectFromHost();
  298 +}
  299 +
  300 +void QMQTT::ClientPrivate::disconnectFromHost()
  301 +{
  302 + _connectionState = ConnectionState::STATE_DISCONNECTED;
  303 + sendDisconnect();
  304 + _network->disconnectFromHost();
  305 +}
  306 +
  307 +void QMQTT::ClientPrivate::sendDisconnect()
  308 +{
  309 + Frame frame(DISCONNECT);
  310 + sendFrame(frame);
  311 +}
  312 +
  313 +void QMQTT::ClientPrivate::sendFrame(const Frame &frame)
  314 +{
  315 + _network->sendFrame(frame);
  316 + _timer.start();
  317 +}
  318 +
  319 +void QMQTT::ClientPrivate::stopKeepAlive()
  320 +{
  321 + _timer.stop();
  322 + _pingResponseTimer.stop();
  323 +}
  324 +
  325 +quint16 QMQTT::ClientPrivate::nextmid()
  326 +{
  327 + return _gmid++;
  328 +}
  329 +
  330 +quint16 QMQTT::ClientPrivate::publish(const Message& message)
  331 +{
  332 + Q_Q(Client);
  333 + quint16 msgid = sendPublish(message);
  334 +
  335 + // Emit published only at QOS0
  336 + if (message.qos() == QOS0)
  337 + emit q->published(message, msgid);
  338 + else
  339 + _midToMessage[msgid] = message;
  340 +
  341 + return msgid;
  342 +}
  343 +
  344 +void QMQTT::ClientPrivate::puback(const quint8 type, const quint16 msgid)
  345 +{
  346 + sendPuback(type, msgid);
  347 +}
  348 +
  349 +void QMQTT::ClientPrivate::subscribe(const QString& topic, const quint8 qos)
  350 +{
  351 + quint16 msgid = sendSubscribe(topic, qos);
  352 + _midToTopic[msgid] = topic;
  353 +}
  354 +
  355 +void QMQTT::ClientPrivate::unsubscribe(const QString& topic)
  356 +{
  357 + quint16 msgid = sendUnsubscribe(topic);
  358 + _midToTopic[msgid] = topic;
  359 +}
  360 +
  361 +void QMQTT::ClientPrivate::onNetworkDisconnected()
  362 +{
  363 + Q_Q(Client);
  364 +
  365 + stopKeepAlive();
  366 + _midToTopic.clear();
  367 + _midToMessage.clear();
  368 + emit q->disconnected();
  369 +}
  370 +
  371 +void QMQTT::ClientPrivate::onNetworkReceived(const QMQTT::Frame& frm)
  372 +{
  373 + QMQTT::Frame frame(frm);
  374 + quint8 qos = 0;
  375 + bool retain, dup;
  376 + QString topic;
  377 + quint16 mid = 0;
  378 + quint8 header = frame.header();
  379 + quint8 type = GETTYPE(header);
  380 +
  381 + switch(type)
  382 + {
  383 + case CONNACK:
  384 + frame.readChar();
  385 + handleConnack(frame.readChar());
  386 + break;
  387 + case PUBLISH:
  388 + qos = GETQOS(header);
  389 + retain = GETRETAIN(header);
  390 + dup = GETDUP(header);
  391 + topic = frame.readString();
  392 + if( qos > QOS0) {
  393 + mid = frame.readInt();
  394 + }
  395 + handlePublish(Message(mid, topic, frame.data(), qos, retain, dup));
  396 + break;
  397 + case PUBACK:
  398 + case PUBREC:
  399 + case PUBREL:
  400 + case PUBCOMP:
  401 + mid = frame.readInt();
  402 + handlePuback(type, mid);
  403 + break;
  404 + case SUBACK:
  405 + mid = frame.readInt();
  406 + topic = _midToTopic.take(mid);
  407 + qos = frame.readChar();
  408 + handleSuback(topic, qos);
  409 + break;
  410 + case UNSUBACK:
  411 + mid = frame.readInt();
  412 + topic = _midToTopic.take(mid);
  413 + handleUnsuback(topic);
  414 + break;
  415 + case PINGRESP:
  416 + handlePingresp();
  417 + break;
  418 + default:
  419 + break;
  420 + }
  421 +}
  422 +
  423 +void QMQTT::ClientPrivate::handleConnack(const quint8 ack)
  424 +{
  425 + Q_Q(Client);
  426 +
  427 + switch (ack)
  428 + {
  429 + case 0:
  430 + _connectionState = ConnectionState::STATE_CONNECTED;
  431 + emit q->connected();
  432 + break;
  433 + case 1:
  434 + emit q->error(MqttUnacceptableProtocolVersionError);
  435 + break;
  436 + case 2:
  437 + emit q->error(MqttIdentifierRejectedError);
  438 + break;
  439 + case 3:
  440 + emit q->error(MqttServerUnavailableError);
  441 + break;
  442 + case 4:
  443 + emit q->error(MqttBadUserNameOrPasswordError);
  444 + break;
  445 + case 5:
  446 + emit q->error(MqttNotAuthorizedError);
  447 + break;
  448 + default:
  449 + emit q->error(UnknownError);
  450 + break;
  451 + }
  452 +}
  453 +
  454 +void QMQTT::ClientPrivate::handlePublish(const Message& message)
  455 +{
  456 + Q_Q(Client);
  457 +
  458 + if(message.qos() == QOS1)
  459 + {
  460 + sendPuback(PUBACK, message.id());
  461 + }
  462 + else if(message.qos() == QOS2)
  463 + {
  464 + sendPuback(PUBREC, message.id());
  465 + }
  466 + emit q->received(message);
  467 +}
  468 +
  469 +void QMQTT::ClientPrivate::handlePuback(const quint8 type, const quint16 msgid)
  470 +{
  471 + Q_Q(Client);
  472 +
  473 + switch (type)
  474 + {
  475 + case PUBREC:
  476 + sendPuback(SETQOS(PUBREL, QOS1), msgid);
  477 + break;
  478 + case PUBREL:
  479 + sendPuback(PUBCOMP, msgid);
  480 + break;
  481 + case PUBACK:
  482 + case PUBCOMP:
  483 + // Emit published on PUBACK at QOS1 and on PUBCOMP at QOS2
  484 + emit q->published(_midToMessage.take(msgid), msgid);
  485 + break;
  486 + }
  487 +}
  488 +
  489 +void QMQTT::ClientPrivate::handlePingresp()
  490 +{
  491 + // Stop the ping response timer to prevent disconnection. It will be restarted when the next
  492 + // ping request has been sent.
  493 + _pingResponseTimer.stop();
  494 + Q_Q(Client);
  495 + emit q->pingresp();
  496 +}
  497 +
  498 +void QMQTT::ClientPrivate::handleSuback(const QString &topic, const quint8 qos)
  499 +{
  500 + Q_Q(Client);
  501 + emit q->subscribed(topic, qos);
  502 +}
  503 +
  504 +void QMQTT::ClientPrivate::handleUnsuback(const QString &topic) {
  505 + Q_Q(Client);
  506 + emit q->unsubscribed(topic);
  507 +}
  508 +
  509 +bool QMQTT::ClientPrivate::autoReconnect() const
  510 +{
  511 + return _network->autoReconnect();
  512 +}
  513 +
  514 +void QMQTT::ClientPrivate::setAutoReconnect(const bool autoReconnect)
  515 +{
  516 + _network->setAutoReconnect(autoReconnect);
  517 +}
  518 +
  519 +int QMQTT::ClientPrivate::autoReconnectInterval() const
  520 +{
  521 + return _network->autoReconnectInterval();
  522 +}
  523 +
  524 +void QMQTT::ClientPrivate::setAutoReconnectInterval(const int autoReconnectInterval)
  525 +{
  526 + _network->setAutoReconnectInterval(autoReconnectInterval);
  527 +}
  528 +
  529 +bool QMQTT::ClientPrivate::isConnectedToHost() const
  530 +{
  531 + return _network->isConnectedToHost();
  532 +}
  533 +
  534 +QMQTT::ConnectionState QMQTT::ClientPrivate::connectionState() const
  535 +{
  536 + return _connectionState;
  537 +}
  538 +
  539 +void QMQTT::ClientPrivate::setCleanSession(const bool cleanSession)
  540 +{
  541 + _cleanSession = cleanSession;
  542 +}
  543 +
  544 +bool QMQTT::ClientPrivate::cleanSession() const
  545 +{
  546 + return _cleanSession;
  547 +}
  548 +
  549 +void QMQTT::ClientPrivate::setKeepAlive(const quint16 keepAlive)
  550 +{
  551 + // _timer will be started when a message is sent.
  552 + _timer.setInterval(keepAlive*1000);
  553 + // The MQTT specification does not mention a timeout value in this case, so we use 10% of the
  554 + // keep alive interval.
  555 + _pingResponseTimer.setInterval(qBound(keepAlive * 100, 10000, keepAlive * 1000));
  556 +}
  557 +
  558 +quint16 QMQTT::ClientPrivate::keepAlive() const
  559 +{
  560 + return _timer.interval() / 1000;
  561 +}
  562 +
  563 +void QMQTT::ClientPrivate::setPassword(const QByteArray& password)
  564 +{
  565 + _password = password;
  566 +}
  567 +
  568 +QByteArray QMQTT::ClientPrivate::password() const
  569 +{
  570 + return _password;
  571 +}
  572 +
  573 +void QMQTT::ClientPrivate::setUsername(const QString& username)
  574 +{
  575 + _username = username;
  576 +}
  577 +
  578 +QString QMQTT::ClientPrivate::username() const
  579 +{
  580 + return _username;
  581 +}
  582 +
  583 +void QMQTT::ClientPrivate::setVersion(const MQTTVersion version)
  584 +{
  585 + _version = version;
  586 +}
  587 +
  588 +QMQTT::MQTTVersion QMQTT::ClientPrivate::version() const
  589 +{
  590 + return _version;
  591 +}
  592 +
  593 +void QMQTT::ClientPrivate::setClientId(const QString& clientId)
  594 +{
  595 + if(clientId.isEmpty())
  596 + {
  597 + _clientId = QUuid::createUuid().toString();
  598 + }
  599 + else
  600 + {
  601 + _clientId = clientId;
  602 + }
  603 +}
  604 +
  605 +QString QMQTT::ClientPrivate::clientId() const
  606 +{
  607 + return _clientId;
  608 +}
  609 +
  610 +void QMQTT::ClientPrivate::setPort(const quint16 port)
  611 +{
  612 + _port = port;
  613 +}
  614 +
  615 +quint16 QMQTT::ClientPrivate::port() const
  616 +{
  617 + return _port;
  618 +}
  619 +
  620 +void QMQTT::ClientPrivate::setHost(const QHostAddress& host)
  621 +{
  622 + _host = host;
  623 +}
  624 +
  625 +QHostAddress QMQTT::ClientPrivate::host() const
  626 +{
  627 + return _host;
  628 +}
  629 +
  630 +void QMQTT::ClientPrivate::setHostName(const QString& hostName)
  631 +{
  632 + _hostName = hostName;
  633 +}
  634 +
  635 +QString QMQTT::ClientPrivate::hostName() const
  636 +{
  637 + return _hostName;
  638 +}
  639 +
  640 +QString QMQTT::ClientPrivate::willTopic() const
  641 +{
  642 + return _willTopic;
  643 +}
  644 +
  645 +void QMQTT::ClientPrivate::setWillTopic(const QString& willTopic)
  646 +{
  647 + _willTopic = willTopic;
  648 +}
  649 +
  650 +quint8 QMQTT::ClientPrivate::willQos() const
  651 +{
  652 + return _willQos;
  653 +}
  654 +
  655 +void QMQTT::ClientPrivate::setWillQos(const quint8 willQos)
  656 +{
  657 + _willQos = willQos;
  658 +}
  659 +
  660 +bool QMQTT::ClientPrivate::willRetain() const
  661 +{
  662 + return _willRetain;
  663 +}
  664 +
  665 +void QMQTT::ClientPrivate::setWillRetain(const bool willRetain)
  666 +{
  667 + _willRetain = willRetain;
  668 +}
  669 +
  670 +QByteArray QMQTT::ClientPrivate::willMessage() const
  671 +{
  672 + return _willMessage;
  673 +}
  674 +
  675 +void QMQTT::ClientPrivate::setWillMessage(const QByteArray& willMessage)
  676 +{
  677 + _willMessage = willMessage;
  678 +}
  679 +
  680 +void QMQTT::ClientPrivate::onNetworkError(QAbstractSocket::SocketError socketError)
  681 +{
  682 + Q_Q(Client);
  683 +
  684 + switch (socketError)
  685 + {
  686 + case QAbstractSocket::ConnectionRefusedError:
  687 + emit q->error(SocketConnectionRefusedError);
  688 + break;
  689 + case QAbstractSocket::RemoteHostClosedError:
  690 + emit q->error(SocketRemoteHostClosedError);
  691 + break;
  692 + case QAbstractSocket::HostNotFoundError:
  693 + emit q->error(SocketHostNotFoundError);
  694 + break;
  695 + case QAbstractSocket::SocketAccessError:
  696 + emit q->error(SocketAccessError);
  697 + break;
  698 + case QAbstractSocket::SocketResourceError:
  699 + emit q->error(SocketResourceError);
  700 + break;
  701 + case QAbstractSocket::SocketTimeoutError:
  702 + emit q->error(SocketTimeoutError);
  703 + break;
  704 + case QAbstractSocket::DatagramTooLargeError:
  705 + emit q->error(SocketDatagramTooLargeError);
  706 + break;
  707 + case QAbstractSocket::NetworkError:
  708 + emit q->error(SocketNetworkError);
  709 + break;
  710 + case QAbstractSocket::AddressInUseError:
  711 + emit q->error(SocketAddressInUseError);
  712 + break;
  713 + case QAbstractSocket::SocketAddressNotAvailableError:
  714 + emit q->error(SocketAddressNotAvailableError);
  715 + break;
  716 + case QAbstractSocket::UnsupportedSocketOperationError:
  717 + emit q->error(SocketUnsupportedSocketOperationError);
  718 + break;
  719 + case QAbstractSocket::UnfinishedSocketOperationError:
  720 + emit q->error(SocketUnfinishedSocketOperationError);
  721 + break;
  722 + case QAbstractSocket::ProxyAuthenticationRequiredError:
  723 + emit q->error(SocketProxyAuthenticationRequiredError);
  724 + break;
  725 + case QAbstractSocket::SslHandshakeFailedError:
  726 + emit q->error(SocketSslHandshakeFailedError);
  727 + break;
  728 + case QAbstractSocket::ProxyConnectionRefusedError:
  729 + emit q->error(SocketProxyConnectionRefusedError);
  730 + break;
  731 + case QAbstractSocket::ProxyConnectionClosedError:
  732 + emit q->error(SocketProxyConnectionClosedError);
  733 + break;
  734 + case QAbstractSocket::ProxyConnectionTimeoutError:
  735 + emit q->error(SocketProxyConnectionTimeoutError);
  736 + break;
  737 + case QAbstractSocket::ProxyNotFoundError:
  738 + emit q->error(SocketProxyNotFoundError);
  739 + break;
  740 + case QAbstractSocket::ProxyProtocolError:
  741 + emit q->error(SocketProxyProtocolError);
  742 + break;
  743 + case QAbstractSocket::OperationError:
  744 + emit q->error(SocketOperationError);
  745 + break;
  746 + case QAbstractSocket::SslInternalError:
  747 + emit q->error(SocketSslInternalError);
  748 + break;
  749 + case QAbstractSocket::SslInvalidUserDataError:
  750 + emit q->error(SocketSslInvalidUserDataError);
  751 + break;
  752 + case QAbstractSocket::TemporaryError:
  753 + emit q->error(SocketTemporaryError);
  754 + break;
  755 + default:
  756 + emit q->error(UnknownError);
  757 + break;
  758 + }
  759 +}
  760 +
  761 +#ifndef QT_NO_SSL
  762 +void QMQTT::ClientPrivate::ignoreSslErrors()
  763 +{
  764 + _network->ignoreSslErrors();
  765 +}
  766 +
  767 +void QMQTT::ClientPrivate::ignoreSslErrors(const QList<QSslError>& errors)
  768 +{
  769 + _network->ignoreSslErrors(errors);
  770 +}
  771 +
  772 +QSslConfiguration QMQTT::ClientPrivate::sslConfiguration() const
  773 +{
  774 + return _network->sslConfiguration();
  775 +}
  776 +
  777 +void QMQTT::ClientPrivate::setSslConfiguration(const QSslConfiguration& config)
  778 +{
  779 + _network->setSslConfiguration(config);
  780 +}
  781 +
  782 +void QMQTT::ClientPrivate::onSslErrors(const QList<QSslError>& errors)
  783 +{
  784 + Q_Q(Client);
  785 +
  786 + emit q->sslErrors(errors);
  787 +
  788 + if (!_ignoreSelfSigned)
  789 + return;
  790 + foreach (QSslError error, errors)
  791 + {
  792 + if (error.error() != QSslError::SelfSignedCertificate &&
  793 + error.error() != QSslError::SelfSignedCertificateInChain)
  794 + {
  795 + return;
  796 + }
  797 + }
  798 + ignoreSslErrors();
  799 +}
  800 +#endif // QT_NO_SSL
src/qmqtt_client_p.h 0 → 100644
  1 +++ a/src/qmqtt_client_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_CLIENT_P_H
  23 +#define QMQTT_CLIENT_P_H
  24 +
  25 +#include "qmqtt_client.h"
  26 +
  27 +#include <QHostAddress>
  28 +#include <QString>
  29 +#include <QByteArray>
  30 +#include <QHash>
  31 +#include <QTimer>
  32 +#include <QAbstractSocket>
  33 +
  34 +#ifdef QT_WEBSOCKETS_LIB
  35 +#include <QWebSocket>
  36 +#endif // QT_WEBSOCKETS_LIB
  37 +
  38 +#ifndef QT_NO_SSL
  39 +#include <QSslConfiguration>
  40 +QT_FORWARD_DECLARE_CLASS(QSslError)
  41 +#endif // QT_NO_SSL
  42 +
  43 +namespace QMQTT {
  44 +
  45 +class NetworkInterface;
  46 +
  47 +class ClientPrivate
  48 +{
  49 +public:
  50 + ClientPrivate(Client* qq_ptr);
  51 + ~ClientPrivate();
  52 +
  53 + /// Deleted copy-constructor
  54 + ClientPrivate(const ClientPrivate&) = delete;
  55 + /// Deleted assignment operator
  56 + ClientPrivate& operator=(const ClientPrivate&) = delete;
  57 + /// Deleted move-constructor
  58 + ClientPrivate(const ClientPrivate&&) = delete;
  59 + /// Deleted move-operator
  60 + ClientPrivate& operator=(const ClientPrivate&&) = delete;
  61 +
  62 + void init(const QHostAddress& host, const quint16 port, NetworkInterface* network = NULL);
  63 +#ifndef QT_NO_SSL
  64 + void init(const QString& hostName, const quint16 port, const QSslConfiguration& config,
  65 + const bool ignoreSelfSigned=false);
  66 +#endif // QT_NO_SSL
  67 + void init(const QString& hostName, const quint16 port, const bool ssl, const bool ignoreSelfSigned);
  68 +#ifdef QT_WEBSOCKETS_LIB
  69 +#ifndef QT_NO_SSL
  70 + void init(const QString& url,
  71 + const QString& origin,
  72 + QWebSocketProtocol::Version version,
  73 + const QSslConfiguration* sslConfig,
  74 + bool ignoreSelfSigned);
  75 +#endif // QT_NO_SSL
  76 + void init(const QString& url,
  77 + const QString& origin,
  78 + QWebSocketProtocol::Version version);
  79 +#endif // QT_WEBSOCKETS_LIB
  80 + void init(NetworkInterface* network);
  81 +
  82 + QHostAddress _host;
  83 + QString _hostName;
  84 + quint16 _port;
  85 +#ifdef QT_WEBSOCKETS_LIB
  86 + QWebSocketProtocol::Version _webSocketVersion;
  87 +#endif // QT_WEBSOCKETS_LIB
  88 +#ifndef QT_NO_SSL
  89 + bool _ignoreSelfSigned;
  90 +#endif // QT_NO_SSL
  91 + quint16 _gmid;
  92 + MQTTVersion _version;
  93 + QString _clientId;
  94 + QString _username;
  95 + QByteArray _password;
  96 + bool _cleanSession;
  97 + ConnectionState _connectionState;
  98 + QScopedPointer<NetworkInterface> _network;
  99 + QTimer _timer;
  100 + QTimer _pingResponseTimer;
  101 + QString _willTopic;
  102 + quint8 _willQos;
  103 + bool _willRetain;
  104 + QByteArray _willMessage;
  105 + QHash<quint16, QString> _midToTopic;
  106 + QHash<quint16, Message> _midToMessage;
  107 +
  108 + Client* const q_ptr;
  109 +
  110 + quint16 nextmid();
  111 + void connectToHost();
  112 + void sendConnect();
  113 + void onTimerPingReq();
  114 + void onPingTimeout();
  115 + quint16 sendUnsubscribe(const QString &topic);
  116 + quint16 sendSubscribe(const QString &topic, const quint8 qos);
  117 + quint16 sendPublish(const Message &message);
  118 + void sendPuback(const quint8 type, const quint16 mid);
  119 + void sendDisconnect();
  120 + void sendFrame(const Frame &frame);
  121 + void disconnectFromHost();
  122 + void stopKeepAlive();
  123 + void onNetworkConnected();
  124 + void onNetworkDisconnected();
  125 + quint16 publish(const Message& message);
  126 + void puback(const quint8 type, const quint16 msgid);
  127 + void subscribe(const QString& topic, const quint8 qos);
  128 + void unsubscribe(const QString& topic);
  129 + void onNetworkReceived(const QMQTT::Frame& frame);
  130 + void handleConnack(const quint8 ack);
  131 + void handlePublish(const Message& message);
  132 + void handlePuback(const quint8 type, const quint16 msgid);
  133 + void handleSuback(const QString& topic, const quint8 qos);
  134 + void handleUnsuback(const QString& topic);
  135 + void handlePingresp();
  136 + bool autoReconnect() const;
  137 + void setAutoReconnect(const bool autoReconnect);
  138 + int autoReconnectInterval() const;
  139 + void setAutoReconnectInterval(const int autoReconnectInterval);
  140 + bool isConnectedToHost() const;
  141 + QMQTT::ConnectionState connectionState() const;
  142 + void setCleanSession(const bool cleanSession);
  143 + bool cleanSession() const;
  144 + void setKeepAlive(const quint16 keepAlive);
  145 + quint16 keepAlive() const;
  146 + void setPassword(const QByteArray& password);
  147 + QByteArray password() const;
  148 + void setUsername(const QString& username);
  149 + QString username() const;
  150 + void setVersion(const MQTTVersion);
  151 + MQTTVersion version() const;
  152 + void setClientId(const QString& clientId);
  153 + QString clientId() const;
  154 + void setPort(const quint16 port);
  155 + quint16 port() const;
  156 + void setHost(const QHostAddress& host);
  157 + QHostAddress host() const;
  158 + void setHostName(const QString& hostName);
  159 + QString hostName() const;
  160 + void setWillTopic(const QString& willTopic);
  161 + void setWillQos(const quint8 willQos);
  162 + void setWillRetain(const bool willRetain);
  163 + void setWillMessage(const QByteArray& willMessage);
  164 + QString willTopic() const;
  165 + quint8 willQos() const;
  166 + bool willRetain() const;
  167 + QByteArray willMessage() const;
  168 + void onNetworkError(QAbstractSocket::SocketError error);
  169 +#ifndef QT_NO_SSL
  170 + void ignoreSslErrors();
  171 + void ignoreSslErrors(const QList<QSslError>& errors);
  172 + QSslConfiguration sslConfiguration() const;
  173 + void setSslConfiguration(const QSslConfiguration& config);
  174 + void onSslErrors(const QList<QSslError>& errors);
  175 +#endif // QT_NO_SSL
  176 +
  177 + Q_DECLARE_PUBLIC(Client)
  178 +};
  179 +
  180 +} // namespace QMQTT
  181 +
  182 +#endif // QMQTT_CLIENT_P_H
src/qmqtt_configsettings.cpp 0 → 100644
  1 +++ a/src/qmqtt_configsettings.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_configsettings.h"
  23 +#include "log.h"
  24 +
  25 +using namespace osdev::components;
  26 +
  27 +void QMqttConfigSettings::setHostAddress( const QHostAddress &host )
  28 +{
  29 + m_host_address = host;
  30 +}
  31 +
  32 +QHostAddress QMqttConfigSettings::getHostAddress() const
  33 +{
  34 + return m_host_address;
  35 +}
  36 +
  37 +void QMqttConfigSettings::setHostName( const QString& host_name )
  38 +{
  39 + m_host_name = host_name;
  40 + QHostInfo host_info = QHostInfo::fromName( host_name );
  41 + if( !host_info.addresses().isEmpty() )
  42 + {
  43 + m_host_address = host_info.addresses().first();
  44 + }
  45 + else
  46 + {
  47 + LogError( "[QMqttConfigSettings::setHostName]", QString( "Hostname : %1 failed to resolve to an ip-address." ).arg( host_name ) );
  48 + }
  49 +}
  50 +
  51 +QString QMqttConfigSettings::getHostName() const
  52 +{
  53 + return m_host_name;
  54 +}
  55 +
  56 +void QMqttConfigSettings::setPortNumber( const quint16 port )
  57 +{
  58 + m_host_port = port;
  59 +}
  60 +
  61 +quint16 QMqttConfigSettings::getPortNumber() const
  62 +{
  63 + return m_host_port;
  64 +}
  65 +
  66 +void QMqttConfigSettings::setClientId( const QString& clientId )
  67 +{
  68 + m_client_id = clientId;
  69 +}
  70 +
  71 +QString QMqttConfigSettings::getClientId() const
  72 +{
  73 + return m_client_id;
  74 +}
  75 +
  76 +void QMqttConfigSettings::setUserName( const QString& user_name )
  77 +{
  78 + m_user_name = user_name;
  79 +}
  80 +
  81 +QString QMqttConfigSettings::getUserName() const
  82 +{
  83 + return m_user_name;
  84 +}
  85 +
  86 +void QMqttConfigSettings::setPassword( const QByteArray& pass_word )
  87 +{
  88 + m_password = pass_word;
  89 +}
  90 +
  91 +QByteArray QMqttConfigSettings::getPassword() const
  92 +{
  93 + return m_password;
  94 +}
  95 +
  96 +void QMqttConfigSettings::setKeepAlive( const quint16 keep_alive )
  97 +{
  98 + m_keep_alive = keep_alive;
  99 +}
  100 +
  101 +quint16 QMqttConfigSettings::getKeepAlive() const
  102 +{
  103 + return m_keep_alive;
  104 +}
  105 +
  106 +void QMqttConfigSettings::setCleanSession( bool clean_session )
  107 +{
  108 + m_clean_session = clean_session;
  109 +}
  110 +
  111 +bool QMqttConfigSettings::getCleanSession() const
  112 +{
  113 + return m_clean_session;
  114 +}
  115 +
  116 +void QMqttConfigSettings::setAutoReconnect( bool reconnect )
  117 +{
  118 + m_auto_reconnect = reconnect;
  119 +}
  120 +
  121 +bool QMqttConfigSettings::getAutoReconnect() const
  122 +{
  123 + return m_auto_reconnect;
  124 +}
  125 +
  126 +void QMqttConfigSettings::setAutoReconnectInterval( const int auto_reconnect_interval )
  127 +{
  128 + m_auto_reconnect_interval = auto_reconnect_interval;
  129 +}
  130 +
  131 +int QMqttConfigSettings::getAutoReconnectInterval() const
  132 +{
  133 + return m_auto_reconnect_interval;
  134 +}
src/qmqtt_configsettings.h 0 → 100644
  1 +++ a/src/qmqtt_configsettings.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef OSDEV_COMPONENTS_QMQTT_CONFIGSETTINGS_H
  23 +#define OSDEV_COMPONENTS_QMQTT_CONFIGSETTINGS_H
  24 +
  25 +#include <QHostAddress>
  26 +#include <QHostInfo>
  27 +#include <QString>
  28 +#include <QByteArray>
  29 +#include <QUuid>
  30 +
  31 +namespace osdev {
  32 +namespace components {
  33 +
  34 +class QMqttConfigSettings
  35 +{
  36 +public:
  37 + QMqttConfigSettings()
  38 + : m_host_address( QHostAddress::LocalHost )
  39 + , m_host_name( "localhost" )
  40 + , m_host_port( 1883 )
  41 + , m_client_id( QUuid::createUuid().toString() )
  42 + , m_user_name( QString() )
  43 + , m_password( QByteArray() )
  44 + , m_keep_alive( 10 )
  45 + , m_clean_session( false )
  46 + , m_auto_reconnect( true )
  47 + , m_auto_reconnect_interval( 60 )
  48 + {}
  49 + QMqttConfigSettings(const QHostAddress& host, const quint16 port )
  50 + : m_host_address( host )
  51 + , m_host_name( host.toString() )
  52 + , m_host_port( port )
  53 + , m_client_id( QUuid::createUuid().toString() )
  54 + , m_user_name( QString() )
  55 + , m_password( QByteArray() )
  56 + , m_keep_alive( 10 )
  57 + , m_clean_session( false )
  58 + , m_auto_reconnect( true )
  59 + , m_auto_reconnect_interval( 60 )
  60 + {}
  61 +
  62 + virtual ~QMqttConfigSettings(){}
  63 +
  64 + // All Getters. Setters are handled in the implementation.
  65 + void setHostAddress( const QHostAddress &host );
  66 + QHostAddress getHostAddress() const;
  67 +
  68 + void setHostName( const QString& host_name );
  69 + QString getHostName() const;
  70 +
  71 + void setPortNumber( const quint16 port );
  72 + quint16 getPortNumber() const;
  73 +
  74 + void setClientId( const QString& clientId );
  75 + QString getClientId() const;
  76 +
  77 + void setUserName( const QString& user_name );
  78 + QString getUserName() const;
  79 +
  80 + void setPassword( const QByteArray& pass_word );
  81 + QByteArray getPassword() const;
  82 +
  83 + void setKeepAlive( const quint16 keep_alive );
  84 + quint16 getKeepAlive() const;
  85 +
  86 + void setCleanSession( bool clean_session );
  87 + bool getCleanSession() const;
  88 +
  89 + void setAutoReconnect( bool reconnect );
  90 + bool getAutoReconnect() const;
  91 +
  92 + void setAutoReconnectInterval( const int auto_reconnect_interval );
  93 + int getAutoReconnectInterval() const;
  94 +
  95 +private:
  96 + QHostAddress m_host_address;
  97 + QString m_host_name;
  98 + quint16 m_host_port;
  99 + QString m_client_id;
  100 + QString m_user_name;
  101 + QByteArray m_password;
  102 + quint16 m_keep_alive;
  103 + bool m_clean_session;
  104 + bool m_auto_reconnect;
  105 + int m_auto_reconnect_interval;
  106 +};
  107 +
  108 +} /* End namespace components */
  109 +} /* End namespace osdev */
  110 +
  111 +#endif /* OSDEV_COMPONENTS_QMQTT_CONFIGSETTINGS_H */
src/qmqtt_frame.cpp 0 → 100644
  1 +++ a/src/qmqtt_frame.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_frame.h"
  23 +
  24 +#include <QLoggingCategory>
  25 +#include <QDataStream>
  26 +
  27 +namespace QMQTT {
  28 +
  29 +Q_LOGGING_CATEGORY(frame, "qmqtt.frame")
  30 +
  31 +Frame::Frame()
  32 + : _header(0)
  33 + , _data(QByteArray())
  34 +{
  35 +}
  36 +
  37 +Frame::Frame(const quint8 header)
  38 + : _header(header)
  39 + , _data(QByteArray())
  40 +{
  41 +}
  42 +
  43 +Frame::Frame(const quint8 header, const QByteArray &data)
  44 + : _header(header)
  45 + , _data(data)
  46 +{
  47 +}
  48 +
  49 +Frame::Frame(const Frame& other)
  50 +{
  51 + _header = other._header;
  52 + _data = other._data;
  53 +}
  54 +
  55 +Frame& Frame::operator=(const Frame& other)
  56 +{
  57 + _header = other._header;
  58 + _data = other._data;
  59 + return *this;
  60 +}
  61 +
  62 +bool Frame::operator==(const Frame& other) const
  63 +{
  64 + return _header == other._header
  65 + && _data == other._data;
  66 +}
  67 +
  68 +
  69 +Frame::~Frame()
  70 +{
  71 +}
  72 +
  73 +quint8 Frame::header() const
  74 +{
  75 + return _header;
  76 +}
  77 +
  78 +QByteArray Frame::data() const
  79 +{
  80 + return _data;
  81 +}
  82 +
  83 +quint8 Frame::readChar()
  84 +{
  85 + char c = _data.at(0);
  86 + _data.remove(0, 1);
  87 + return c;
  88 +}
  89 +
  90 +quint16 Frame::readInt()
  91 +{
  92 + quint8 msb = static_cast<quint8>(_data.at(0));
  93 + quint8 lsb = static_cast<quint8>(_data.at(1));
  94 + _data.remove(0, 2);
  95 + return (msb << 8) | lsb;
  96 +}
  97 +
  98 +QByteArray Frame::readByteArray()
  99 +{
  100 + quint16 len = readInt();
  101 + QByteArray data = _data.left(len);
  102 + _data.remove(0, len);
  103 + return data;
  104 +}
  105 +
  106 +QString Frame::readString()
  107 +{
  108 + quint16 len = readInt();
  109 + QString s = QString::fromUtf8(_data.left(len));
  110 + _data.remove(0, len);
  111 + return s;
  112 +}
  113 +
  114 +void Frame::writeInt(const quint16 i)
  115 +{
  116 + _data.append(MSB(i));
  117 + _data.append(LSB(i));
  118 +}
  119 +
  120 +void Frame::writeByteArray(const QByteArray &data)
  121 +{
  122 + if (data.size() > (int)USHRT_MAX)
  123 + {
  124 + qCritical("qmqtt: Binary data size bigger than %u bytes, truncate it!", USHRT_MAX);
  125 + writeInt(USHRT_MAX);
  126 + _data.append(data.left(USHRT_MAX));
  127 + return;
  128 + }
  129 +
  130 + writeInt(data.size());
  131 + _data.append(data);
  132 +}
  133 +
  134 +void Frame::writeString(const QString &string)
  135 +{
  136 + QByteArray data = string.toUtf8();
  137 + if (data.size() > (int)USHRT_MAX)
  138 + {
  139 + qCritical("qmqtt: String size bigger than %u bytes, truncate it!", USHRT_MAX);
  140 + data.resize(USHRT_MAX);
  141 + }
  142 + writeInt(data.size());
  143 + _data.append(data);
  144 +}
  145 +
  146 +void Frame::writeChar(const quint8 c)
  147 +{
  148 + _data.append(c);
  149 +}
  150 +
  151 +void Frame::writeRawData(const QByteArray &data)
  152 +{
  153 + _data.append(data);
  154 +}
  155 +
  156 +void Frame::write(QDataStream &stream) const
  157 +{
  158 + QByteArray lenbuf;
  159 +
  160 + if (!encodeLength(lenbuf, _data.size()))
  161 + {
  162 + qCritical("qmqtt: Control packet bigger than 256 MB, dropped!");
  163 + return;
  164 + }
  165 +
  166 + stream << (quint8)_header;
  167 + if(_data.size() == 0) {
  168 + stream << (quint8)0;
  169 + return;
  170 + }
  171 + if (stream.writeRawData(lenbuf.data(), lenbuf.size()) != lenbuf.size())
  172 + {
  173 + qCritical("qmqtt: Control packet write error!");
  174 + return;
  175 + }
  176 + if (stream.writeRawData(_data.data(), _data.size()) != _data.size())
  177 + {
  178 + qCritical("qmqtt: Control packet write error!");
  179 + }
  180 +}
  181 +
  182 +bool Frame::encodeLength(QByteArray &lenbuf, int length) const
  183 +{
  184 + lenbuf.clear();
  185 + quint8 d;
  186 + do {
  187 + d = length % 128;
  188 + length /= 128;
  189 + if (length > 0) {
  190 + d |= 0x80;
  191 + }
  192 + lenbuf.append(d);
  193 + } while (length > 0);
  194 +
  195 + return lenbuf.size() <= 4;
  196 +}
  197 +
  198 +} // namespace QMQTT
src/qmqtt_frame.h 0 → 100644
  1 +++ a/src/qmqtt_frame.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_FRAME_H
  23 +#define QMQTT_FRAME_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QMetaType>
  28 +#include <QByteArray>
  29 +#include <QString>
  30 +
  31 +QT_FORWARD_DECLARE_CLASS(QDataStream)
  32 +
  33 +#define PROTOCOL_MAGIC_3_1_0 "MQIsdp"
  34 +#define PROTOCOL_MAGIC_3_1_1 "MQTT"
  35 +
  36 +#define RANDOM_CLIENT_PREFIX "QMQTT-"
  37 +
  38 +#define CONNECT 0x10
  39 +#define CONNACK 0x20
  40 +#define PUBLISH 0x30
  41 +#define PUBACK 0x40
  42 +#define PUBREC 0x50
  43 +#define PUBREL 0x60
  44 +#define PUBCOMP 0x70
  45 +#define SUBSCRIBE 0x80
  46 +#define SUBACK 0x90
  47 +#define UNSUBSCRIBE 0xA0
  48 +#define UNSUBACK 0xB0
  49 +#define PINGREQ 0xC0
  50 +#define PINGRESP 0xD0
  51 +#define DISCONNECT 0xE0
  52 +
  53 +#define LSB(A) quint8(A & 0x00FF)
  54 +#define MSB(A) quint8((A & 0xFF00) >> 8)
  55 +
  56 +/*
  57 +|--------------------------------------
  58 +| 7 6 5 4 | 3 | 2 1 | 0 |
  59 +| Type | DUP flag | QoS | RETAIN |
  60 +|--------------------------------------
  61 +*/
  62 +#define GETTYPE(HDR) (HDR & 0xF0)
  63 +#define SETQOS(HDR, Q) (HDR | ((Q) << 1))
  64 +#define GETQOS(HDR) ((HDR & 0x06) >> 1)
  65 +#define SETDUP(HDR, D) (HDR | ((D) << 3))
  66 +#define GETDUP(HDR) ((HDR & 0x08) >> 3)
  67 +#define SETRETAIN(HDR, R) (HDR | (R))
  68 +#define GETRETAIN(HDR) (HDR & 0x01)
  69 +
  70 +/*
  71 +|----------------------------------------------------------------------------------
  72 +| 7 | 6 | 5 | 4 3 | 2 | 1 | 0 |
  73 +| username | password | willretain | willqos | willflag | cleansession | reserved |
  74 +|----------------------------------------------------------------------------------
  75 +*/
  76 +#define FLAG_CLEANSESS(F, C) (F | ((C) << 1))
  77 +#define FLAG_WILL(F, W) (F | ((W) << 2))
  78 +#define FLAG_WILLQOS(F, Q) (F | ((Q) << 3))
  79 +#define FLAG_WILLRETAIN(F, R) (F | ((R) << 5))
  80 +#define FLAG_PASSWD(F, P) (F | ((P) << 6))
  81 +#define FLAG_USERNAME(F, U) (F | ((U) << 7))
  82 +
  83 +namespace QMQTT {
  84 +
  85 +class Q_MQTT_EXPORT Frame
  86 +{
  87 +public:
  88 + explicit Frame();
  89 + explicit Frame(const quint8 header);
  90 + explicit Frame(const quint8 header, const QByteArray &data);
  91 + virtual ~Frame();
  92 +
  93 + Frame(const Frame& other);
  94 + Frame& operator=(const Frame& other);
  95 +
  96 + bool operator==(const Frame& other) const;
  97 + inline bool operator!=(const Frame& other) const
  98 + { return !operator==(other); }
  99 +
  100 + quint8 header() const;
  101 + QByteArray data() const;
  102 +
  103 + quint16 readInt();
  104 + quint8 readChar();
  105 + QByteArray readByteArray();
  106 + QString readString();
  107 +
  108 + void writeInt(const quint16 i);
  109 + void writeChar(const quint8 c);
  110 + void writeByteArray(const QByteArray &data);
  111 + void writeString(const QString &string);
  112 + void writeRawData(const QByteArray &data);
  113 +
  114 + //TODO: FIXME LATER
  115 + void write(QDataStream &stream) const;
  116 + bool encodeLength(QByteArray &lenbuf, int length) const;
  117 +
  118 +private:
  119 + quint8 _header;
  120 + QByteArray _data;
  121 +};
  122 +
  123 +} // namespace QMQTT
  124 +
  125 +Q_DECLARE_METATYPE(QMQTT::Frame)
  126 +
  127 +#endif // QMQTT_FRAME_H
src/qmqtt_global.h 0 → 100644
  1 +++ a/src/qmqtt_global.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_GLOBAL_H
  23 +#define QMQTT_GLOBAL_H
  24 +
  25 +#include <QtGlobal>
  26 +
  27 +#if !defined(QT_STATIC) && !defined(MQTT_PROJECT_INCLUDE_SRC)
  28 +# if defined(QT_BUILD_QMQTT_LIB)
  29 +# define Q_MQTT_EXPORT Q_DECL_EXPORT
  30 +# else
  31 +# define Q_MQTT_EXPORT Q_DECL_IMPORT
  32 +# endif
  33 +#else
  34 +# define Q_MQTT_EXPORT
  35 +#endif
  36 +
  37 +#endif // QMQTT_GLOBAL_H
  38 +
src/qmqtt_message.cpp 0 → 100644
  1 +++ a/src/qmqtt_message.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_message.h"
  23 +#include "qmqtt_message_p.h"
  24 +
  25 +namespace QMQTT {
  26 +
  27 +Message::Message()
  28 + : d(new MessagePrivate)
  29 +{
  30 +}
  31 +
  32 +Message::Message(const quint16 id, const QString &topic, const QByteArray &payload,
  33 + const quint8 qos, const bool retain, const bool dup)
  34 + : d(new MessagePrivate(id, topic, payload, qos, retain, dup))
  35 +{
  36 +}
  37 +
  38 +Message::Message(const Message &other)
  39 + : d(other.d)
  40 +{
  41 +}
  42 +
  43 +Message::~Message()
  44 +{
  45 +}
  46 +
  47 +Message &Message::operator=(const Message &other)
  48 +{
  49 + d = other.d;
  50 + return *this;
  51 +}
  52 +
  53 +bool Message::operator==(const Message &other) const
  54 +{
  55 + if (d == other.d)
  56 + return true;
  57 + return d->id == other.d->id
  58 + && d->qos == other.d->qos
  59 + && d->retain == other.d->retain
  60 + && d->dup == other.d->dup
  61 + && d->topic == other.d->topic
  62 + && d->payload == other.d->payload;
  63 +}
  64 +
  65 +quint16 Message::id() const
  66 +{
  67 + return d->id;
  68 +}
  69 +
  70 +void Message::setId(const quint16 id)
  71 +{
  72 + d->id = id;
  73 +}
  74 +
  75 +quint8 Message::qos() const
  76 +{
  77 + return d->qos;
  78 +}
  79 +
  80 +void Message::setQos(const quint8 qos)
  81 +{
  82 + d->qos = qos;
  83 +}
  84 +
  85 +bool Message::retain() const
  86 +{
  87 + return d->retain;
  88 +}
  89 +
  90 +void Message::setRetain(const bool retain)
  91 +{
  92 + d->retain = retain;
  93 +}
  94 +
  95 +bool Message::dup() const
  96 +{
  97 + return d->dup;
  98 +}
  99 +
  100 +void Message::setDup(const bool dup)
  101 +{
  102 + d->dup = dup;
  103 +}
  104 +
  105 +QString Message::topic() const
  106 +{
  107 + return d->topic;
  108 +}
  109 +
  110 +void Message::setTopic(const QString &topic)
  111 +{
  112 + d->topic = topic;
  113 +}
  114 +
  115 +QByteArray Message::payload() const
  116 +{
  117 + return d->payload;
  118 +}
  119 +
  120 +void Message::setPayload(const QByteArray &payload)
  121 +{
  122 + d->payload = payload;
  123 +}
  124 +
  125 +} // namespace QMQTT
src/qmqtt_message.h 0 → 100644
  1 +++ a/src/qmqtt_message.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_MESSAGE_H
  23 +#define QMQTT_MESSAGE_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QMetaType>
  28 +#include <QString>
  29 +#include <QByteArray>
  30 +#include <QSharedDataPointer>
  31 +
  32 +namespace QMQTT {
  33 +
  34 +class MessagePrivate;
  35 +
  36 +class Q_MQTT_EXPORT Message
  37 +{
  38 +public:
  39 + Message();
  40 + explicit Message(const quint16 id, const QString &topic, const QByteArray &payload,
  41 + const quint8 qos = 0, const bool retain = false, const bool dup = false);
  42 + Message(const Message &other);
  43 + ~Message();
  44 +
  45 + Message &operator=(const Message &other);
  46 +#ifdef Q_COMPILER_RVALUE_REFS
  47 + inline Message &operator=(Message &&other) Q_DECL_NOTHROW
  48 + { swap(other); return *this; }
  49 +#endif
  50 +
  51 + bool operator==(const Message &other) const;
  52 + inline bool operator!=(const Message &other) const
  53 + { return !operator==(other); }
  54 +
  55 + inline void swap(Message &other) Q_DECL_NOTHROW
  56 + { qSwap(d, other.d); }
  57 +
  58 + quint16 id() const;
  59 + void setId(const quint16 id);
  60 +
  61 + quint8 qos() const;
  62 + void setQos(const quint8 qos);
  63 +
  64 + bool retain() const;
  65 + void setRetain(const bool retain);
  66 +
  67 + bool dup() const;
  68 + void setDup(const bool dup);
  69 +
  70 + QString topic() const;
  71 + void setTopic(const QString &topic);
  72 +
  73 + QByteArray payload() const;
  74 + void setPayload(const QByteArray &payload);
  75 +
  76 +private:
  77 + QSharedDataPointer<MessagePrivate> d;
  78 +};
  79 +
  80 +} // namespace QMQTT
  81 +
  82 +Q_DECLARE_SHARED(QMQTT::Message)
  83 +
  84 +Q_DECLARE_METATYPE(QMQTT::Message)
  85 +
  86 +#endif // QMQTT_MESSAGE_H
src/qmqtt_message_p.h 0 → 100644
  1 +++ a/src/qmqtt_message_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_MESSAGE_P_H
  23 +#define QMQTT_MESSAGE_P_H
  24 +
  25 +#include <QSharedData>
  26 +#include <QString>
  27 +#include <QByteArray>
  28 +
  29 +namespace QMQTT {
  30 +
  31 +class MessagePrivate : public QSharedData
  32 +{
  33 +public:
  34 + inline MessagePrivate()
  35 + : QSharedData(),
  36 + id(0),
  37 + qos(0),
  38 + retain(false),
  39 + dup(false)
  40 + {}
  41 +
  42 + inline MessagePrivate(const MessagePrivate &other)
  43 + : QSharedData(other),
  44 + id(other.id),
  45 + qos(other.qos),
  46 + retain(other.retain),
  47 + dup(other.dup),
  48 + topic(other.topic),
  49 + payload(other.payload)
  50 + {}
  51 +
  52 + inline MessagePrivate(quint16 id, const QString &topic, const QByteArray &payload,
  53 + quint8 qos, bool retain, bool dup)
  54 + : QSharedData(),
  55 + id(id),
  56 + qos(qos),
  57 + retain(retain),
  58 + dup(dup),
  59 + topic(topic),
  60 + payload(payload)
  61 + {}
  62 +
  63 + quint16 id;
  64 + quint8 qos : 2;
  65 + quint8 retain: 1;
  66 + quint8 dup: 1;
  67 + QString topic;
  68 + QByteArray payload;
  69 +};
  70 +
  71 +} // namespace QMQTT
  72 +
  73 +#endif // QMQTT_MESSAGE_P_H
src/qmqtt_network.cpp 0 → 100644
  1 +++ a/src/qmqtt_network.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_network_p.h"
  23 +#include "qmqtt_socket_p.h"
  24 +#include "qmqtt_ssl_socket_p.h"
  25 +#include "qmqtt_timer_p.h"
  26 +#include "qmqtt_websocket_p.h"
  27 +#include "qmqtt_frame.h"
  28 +
  29 +#include <QDataStream>
  30 +
  31 +const quint16 DEFAULT_PORT = 1883;
  32 +const quint16 DEFAULT_SSL_PORT = 8883;
  33 +const bool DEFAULT_AUTORECONNECT = false;
  34 +const int DEFAULT_AUTORECONNECT_INTERVAL_MS = 5000;
  35 +
  36 +QMQTT::Network::Network(QObject* parent)
  37 + : NetworkInterface(parent)
  38 + , _port(DEFAULT_PORT)
  39 + , _autoReconnect(DEFAULT_AUTORECONNECT)
  40 + , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  41 + , _socket(new QMQTT::Socket)
  42 + , _autoReconnectTimer(new QMQTT::Timer)
  43 + , _readState(Header)
  44 +{
  45 + initialize();
  46 +}
  47 +
  48 +#ifndef QT_NO_SSL
  49 +QMQTT::Network::Network(const QSslConfiguration& config, QObject *parent)
  50 + : NetworkInterface(parent)
  51 + , _port(DEFAULT_SSL_PORT)
  52 + , _autoReconnect(DEFAULT_AUTORECONNECT)
  53 + , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  54 + , _socket(new QMQTT::SslSocket(config))
  55 + , _autoReconnectTimer(new QMQTT::Timer)
  56 + , _readState(Header)
  57 +{
  58 + initialize();
  59 + connect(_socket, &QMQTT::SslSocket::sslErrors, this, &QMQTT::Network::sslErrors);
  60 +}
  61 +#endif // QT_NO_SSL
  62 +
  63 +#ifdef QT_WEBSOCKETS_LIB
  64 +#ifndef QT_NO_SSL
  65 +QMQTT::Network::Network(const QString& origin,
  66 + QWebSocketProtocol::Version version,
  67 + const QSslConfiguration* sslConfig,
  68 + QObject* parent)
  69 + : NetworkInterface(parent)
  70 + , _port(DEFAULT_SSL_PORT)
  71 + , _autoReconnect(DEFAULT_AUTORECONNECT)
  72 + , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  73 + , _socket(new QMQTT::WebSocket(origin, version, sslConfig))
  74 + , _autoReconnectTimer(new QMQTT::Timer)
  75 + , _readState(Header)
  76 +{
  77 + initialize();
  78 +}
  79 +#endif // QT_NO_SSL
  80 +
  81 +QMQTT::Network::Network(const QString& origin,
  82 + QWebSocketProtocol::Version version,
  83 + QObject* parent)
  84 + : NetworkInterface(parent)
  85 + , _port(DEFAULT_PORT)
  86 + , _autoReconnect(DEFAULT_AUTORECONNECT)
  87 + , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  88 + , _socket(new QMQTT::WebSocket(origin, version))
  89 + , _autoReconnectTimer(new QMQTT::Timer)
  90 + , _readState(Header)
  91 +{
  92 + initialize();
  93 +}
  94 +#endif // QT_WEBSOCKETS_LIB
  95 +
  96 +QMQTT::Network::Network(SocketInterface* socketInterface, TimerInterface* timerInterface,
  97 + QObject* parent)
  98 + : NetworkInterface(parent)
  99 + , _port(DEFAULT_PORT)
  100 + , _autoReconnect(DEFAULT_AUTORECONNECT)
  101 + , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  102 + , _socket(socketInterface)
  103 + , _autoReconnectTimer(timerInterface)
  104 + , _readState(Header)
  105 +{
  106 + initialize();
  107 +}
  108 +
  109 +void QMQTT::Network::initialize()
  110 +{
  111 + _socket->setParent(this);
  112 + _autoReconnectTimer->setParent(this);
  113 + _autoReconnectTimer->setSingleShot(true);
  114 + _autoReconnectTimer->setInterval(_autoReconnectInterval);
  115 +
  116 + QObject::connect(_socket, &SocketInterface::connected, this, &Network::connected);
  117 + QObject::connect(_socket, &SocketInterface::disconnected, this, &Network::onDisconnected);
  118 + QObject::connect(_socket->ioDevice(), &QIODevice::readyRead, this, &Network::onSocketReadReady);
  119 + QObject::connect(
  120 + _autoReconnectTimer, &TimerInterface::timeout,
  121 + this, static_cast<void (Network::*)()>(&Network::connectToHost));
  122 + QObject::connect(_socket,
  123 + static_cast<void (SocketInterface::*)(QAbstractSocket::SocketError)>(&SocketInterface::error),
  124 + this, &Network::onSocketError);
  125 +}
  126 +
  127 +QMQTT::Network::~Network()
  128 +{
  129 +}
  130 +
  131 +bool QMQTT::Network::isConnectedToHost() const
  132 +{
  133 + return _socket->state() == QAbstractSocket::ConnectedState;
  134 +}
  135 +
  136 +void QMQTT::Network::connectToHost(const QHostAddress& host, const quint16 port)
  137 +{
  138 + // Reset the hostname, because if it is not empty connectToHost() will use it instead of _host.
  139 + _hostName.clear();
  140 + _host = host;
  141 + _port = port;
  142 + connectToHost();
  143 +}
  144 +
  145 +void QMQTT::Network::connectToHost(const QString& hostName, const quint16 port)
  146 +{
  147 + _hostName = hostName;
  148 + _port = port;
  149 + connectToHost();
  150 +}
  151 +
  152 +void QMQTT::Network::connectToHost()
  153 +{
  154 + _readState = Header;
  155 + if (_hostName.isEmpty())
  156 + {
  157 + _socket->connectToHost(_host, _port);
  158 + }
  159 + else
  160 + {
  161 + _socket->connectToHost(_hostName, _port);
  162 + }
  163 +}
  164 +
  165 +void QMQTT::Network::onSocketError(QAbstractSocket::SocketError socketError)
  166 +{
  167 + emit error(socketError);
  168 + if(_autoReconnect)
  169 + {
  170 + _autoReconnectTimer->start();
  171 + }
  172 +}
  173 +
  174 +void QMQTT::Network::sendFrame(const Frame& frame)
  175 +{
  176 + if(_socket->state() == QAbstractSocket::ConnectedState)
  177 + {
  178 + QDataStream out(_socket->ioDevice());
  179 + frame.write(out);
  180 + }
  181 +}
  182 +
  183 +void QMQTT::Network::disconnectFromHost()
  184 +{
  185 + _socket->disconnectFromHost();
  186 +}
  187 +
  188 +QAbstractSocket::SocketState QMQTT::Network::state() const
  189 +{
  190 + return _socket->state();
  191 +}
  192 +
  193 +bool QMQTT::Network::autoReconnect() const
  194 +{
  195 + return _autoReconnect;
  196 +}
  197 +
  198 +void QMQTT::Network::setAutoReconnect(const bool autoReconnect)
  199 +{
  200 + _autoReconnect = autoReconnect;
  201 +}
  202 +
  203 +int QMQTT::Network::autoReconnectInterval() const
  204 +{
  205 + return _autoReconnectInterval;
  206 +}
  207 +
  208 +void QMQTT::Network::setAutoReconnectInterval(const int autoReconnectInterval)
  209 +{
  210 + _autoReconnectInterval = autoReconnectInterval;
  211 + _autoReconnectTimer->setInterval(_autoReconnectInterval);
  212 +}
  213 +
  214 +void QMQTT::Network::onSocketReadReady()
  215 +{
  216 + QIODevice *ioDevice = _socket->ioDevice();
  217 + // Only read the available (cached) bytes, so the read will never block.
  218 + QByteArray data = ioDevice->read(ioDevice->bytesAvailable());
  219 + foreach(char byte, data) {
  220 + switch (_readState) {
  221 + case Header:
  222 + _header = static_cast<quint8>(byte);
  223 + _readState = Length;
  224 + _length = 0;
  225 + _shift = 0;
  226 + _data.resize(0); // keep allocated buffer
  227 + break;
  228 + case Length:
  229 + _length |= (byte & 0x7F) << _shift;
  230 + _shift += 7;
  231 + if ((byte & 0x80) != 0)
  232 + break;
  233 + if (_length == 0) {
  234 + _readState = Header;
  235 + Frame frame(_header, _data);
  236 + emit received(frame);
  237 + break;
  238 + }
  239 + _readState = PayLoad;
  240 + _data.reserve(_length);
  241 + break;
  242 + case PayLoad:
  243 + _data.append(byte);
  244 + --_length;
  245 + if (_length > 0)
  246 + break;
  247 + _readState = Header;
  248 + Frame frame(_header, _data);
  249 + emit received(frame);
  250 + break;
  251 + }
  252 + }
  253 +}
  254 +
  255 +void QMQTT::Network::onDisconnected()
  256 +{
  257 + emit disconnected();
  258 + if(_autoReconnect)
  259 + {
  260 + _autoReconnectTimer->start();
  261 + }
  262 +}
  263 +
  264 +#ifndef QT_NO_SSL
  265 +void QMQTT::Network::ignoreSslErrors(const QList<QSslError>& errors)
  266 +{
  267 + _socket->ignoreSslErrors(errors);
  268 +}
  269 +
  270 +void QMQTT::Network::ignoreSslErrors()
  271 +{
  272 + _socket->ignoreSslErrors();
  273 +}
  274 +
  275 +QSslConfiguration QMQTT::Network::sslConfiguration() const
  276 +{
  277 + return _socket->sslConfiguration();
  278 +}
  279 +
  280 +void QMQTT::Network::setSslConfiguration(const QSslConfiguration& config)
  281 +{
  282 + _socket->setSslConfiguration(config);
  283 +}
  284 +#endif // QT_NO_SSL
src/qmqtt_network_p.h 0 → 100644
  1 +++ a/src/qmqtt_network_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_NETWORK_P_H
  23 +#define QMQTT_NETWORK_P_H
  24 +
  25 +#include "qmqtt_networkinterface.h"
  26 +
  27 +#include <QObject>
  28 +#include <QHostAddress>
  29 +#include <QString>
  30 +#include <QByteArray>
  31 +
  32 +#ifdef QT_WEBSOCKETS_LIB
  33 +#include <QWebSocket>
  34 +#endif // QT_WEBSOCKETS_LIB
  35 +
  36 +#ifndef QT_NO_SSL
  37 +#include <QSslConfiguration>
  38 +QT_FORWARD_DECLARE_CLASS(QSslError)
  39 +#endif // QT_NO_SSL
  40 +
  41 +namespace QMQTT {
  42 +
  43 +class SocketInterface;
  44 +class TimerInterface;
  45 +class Frame;
  46 +
  47 +class Network : public NetworkInterface
  48 +{
  49 + Q_OBJECT
  50 +
  51 +public:
  52 + Network(QObject* parent = NULL);
  53 +#ifndef QT_NO_SSL
  54 + Network(const QSslConfiguration& config, QObject* parent = NULL);
  55 +#endif // QT_NO_SSL
  56 +#ifdef QT_WEBSOCKETS_LIB
  57 +#ifndef QT_NO_SSL
  58 + Network(const QString& origin,
  59 + QWebSocketProtocol::Version version,
  60 + const QSslConfiguration* sslConfig,
  61 + QObject* parent = NULL);
  62 +#endif // QT_NO_SSL
  63 + Network(const QString& origin,
  64 + QWebSocketProtocol::Version version,
  65 + QObject* parent = NULL);
  66 +#endif // QT_WEBSOCKETS_LIB
  67 + Network(SocketInterface* socketInterface, TimerInterface* timerInterface,
  68 + QObject* parent = NULL);
  69 + ~Network();
  70 +
  71 + void sendFrame(const Frame &frame);
  72 + bool isConnectedToHost() const;
  73 + bool autoReconnect() const;
  74 + void setAutoReconnect(const bool autoReconnect);
  75 + QAbstractSocket::SocketState state() const;
  76 + int autoReconnectInterval() const;
  77 + void setAutoReconnectInterval(const int autoReconnectInterval);
  78 +#ifndef QT_NO_SSL
  79 + void ignoreSslErrors(const QList<QSslError>& errors);
  80 + QSslConfiguration sslConfiguration() const;
  81 + void setSslConfiguration(const QSslConfiguration& config);
  82 +#endif // QT_NO_SSL
  83 +
  84 +public slots:
  85 + void connectToHost(const QHostAddress& host, const quint16 port);
  86 + void connectToHost(const QString& hostName, const quint16 port);
  87 + void disconnectFromHost();
  88 +#ifndef QT_NO_SSL
  89 + void ignoreSslErrors();
  90 +#endif // QT_NO_SSL
  91 +
  92 +protected slots:
  93 + void onSocketError(QAbstractSocket::SocketError socketError);
  94 +
  95 +protected:
  96 + void initialize();
  97 +
  98 + quint16 _port;
  99 + QHostAddress _host;
  100 + QString _hostName;
  101 + bool _autoReconnect;
  102 + int _autoReconnectInterval;
  103 + SocketInterface* _socket;
  104 + TimerInterface* _autoReconnectTimer;
  105 +
  106 + enum ReadState {
  107 + Header,
  108 + Length,
  109 + PayLoad
  110 + };
  111 +
  112 + ReadState _readState;
  113 + quint8 _header;
  114 + int _length;
  115 + int _shift;
  116 + QByteArray _data;
  117 +
  118 +protected slots:
  119 + void onSocketReadReady();
  120 + void onDisconnected();
  121 + void connectToHost();
  122 +
  123 +private:
  124 + Q_DISABLE_COPY(Network)
  125 +};
  126 +
  127 +} // namespace QMQTT
  128 +
  129 +#endif // QMQTT_NETWORK_P_H
src/qmqtt_networkinterface.h 0 → 100644
  1 +++ a/src/qmqtt_networkinterface.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_NETWORK_INTERFACE_H
  23 +#define QMQTT_NETWORK_INTERFACE_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QObject>
  28 +#include <QAbstractSocket>
  29 +#include <QHostAddress>
  30 +#include <QString>
  31 +#include <QList>
  32 +
  33 +#ifndef QT_NO_SSL
  34 +#include <QSslConfiguration>
  35 +QT_FORWARD_DECLARE_CLASS(QSslError)
  36 +#endif // QT_NO_SSL
  37 +
  38 +namespace QMQTT {
  39 +
  40 +class Frame;
  41 +
  42 +class Q_MQTT_EXPORT NetworkInterface : public QObject
  43 +{
  44 + Q_OBJECT
  45 +public:
  46 + explicit NetworkInterface(QObject* parent = NULL) : QObject(parent) {}
  47 + virtual ~NetworkInterface() {}
  48 +
  49 + virtual void sendFrame(const Frame& frame) = 0;
  50 + virtual bool isConnectedToHost() const = 0;
  51 + virtual bool autoReconnect() const = 0;
  52 + virtual void setAutoReconnect(const bool autoReconnect) = 0;
  53 + virtual int autoReconnectInterval() const = 0;
  54 + virtual void setAutoReconnectInterval(const int autoReconnectInterval) = 0;
  55 + virtual QAbstractSocket::SocketState state() const = 0;
  56 +#ifndef QT_NO_SSL
  57 + virtual void ignoreSslErrors(const QList<QSslError>& errors) = 0;
  58 + virtual QSslConfiguration sslConfiguration() const = 0;
  59 + virtual void setSslConfiguration(const QSslConfiguration& config) = 0;
  60 +#endif // QT_NO_SSL
  61 +
  62 +public slots:
  63 + virtual void connectToHost(const QHostAddress& host, const quint16 port) = 0;
  64 + virtual void connectToHost(const QString& hostName, const quint16 port) = 0;
  65 + virtual void disconnectFromHost() = 0;
  66 +#ifndef QT_NO_SSL
  67 + virtual void ignoreSslErrors() = 0;
  68 +#endif // QT_NO_SSL
  69 +
  70 +signals:
  71 + void connected();
  72 + void disconnected();
  73 + void received(const QMQTT::Frame& frame);
  74 + void error(QAbstractSocket::SocketError error);
  75 +#ifndef QT_NO_SSL
  76 + void sslErrors(const QList<QSslError>& errors);
  77 +#endif // QT_NO_SSL
  78 +};
  79 +
  80 +} // namespace QMQTT
  81 +
  82 +#endif // QMQTT_NETWORK_INTERFACE_H
src/qmqtt_pubsubclient.cpp 0 → 100644
  1 +++ a/src/qmqtt_pubsubclient.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +// osdev::components
  23 +#include "qmqtt_pubsubclient.h"
  24 +#include "log.h"
  25 +
  26 +// Qt
  27 +#include <QRandomGenerator>
  28 +
  29 +using namespace osdev::components;
  30 +
  31 +QMqttPubSubClient::QMqttPubSubClient(const QHostAddress& host,
  32 + const quint16 port,
  33 + QObject *parent)
  34 + : QMQTT::Client(host, port, parent)
  35 + , m_mqtt_topic()
  36 + , m_current_state(mqtt::E_CLIENT_UNKNOWN)
  37 + , m_subTemp()
  38 + , m_pubTemp()
  39 +{
  40 + this->connectSignalsAndSlots();
  41 +
  42 + this->connectToHost();
  43 +}
  44 +
  45 +QMqttPubSubClient::~QMqttPubSubClient()
  46 +{
  47 +
  48 +}
  49 +
  50 +void QMqttPubSubClient::subscribe(const QString& message_topic)
  51 +{
  52 + if(m_current_state == mqtt::E_CLIENT_CONNECTED)
  53 + {
  54 + QMQTT::Client::subscribe(message_topic);
  55 + }
  56 + else
  57 + {
  58 + m_subTemp.first = message_topic;
  59 + m_subTemp.second = QString();
  60 + }
  61 +}
  62 +
  63 +void QMqttPubSubClient::unsubscribe(const QString& message_topic)
  64 +{
  65 + if(m_current_state == mqtt::E_CLIENT_SUBSCRIBED)
  66 + {
  67 + QMQTT::Client::unsubscribe( message_topic );
  68 + }
  69 +}
  70 +
  71 +void QMqttPubSubClient::publish(const QString& message_topic, const QString& message_payload)
  72 +{
  73 + if(m_current_state == mqtt::E_CLIENT_CONNECTED ||
  74 + m_current_state == mqtt::E_CLIENT_SUBSCRIBED ||
  75 + m_current_state == mqtt::E_CLIENT_PUBLISHED)
  76 + {
  77 + QMQTT::Message oMessage( QRandomGenerator::global()->generate(),
  78 + message_topic,
  79 + QByteArray(message_payload.toStdString().c_str()),
  80 + 0, true, false );
  81 + QMQTT::Client::publish(oMessage);
  82 + }
  83 + else
  84 + {
  85 + m_pubTemp.first = message_topic;
  86 + m_pubTemp.second = message_payload;
  87 + }
  88 +}
  89 +
  90 +void QMqttPubSubClient::slotOnConnected()
  91 +{
  92 + // Ok. We're connected at the moment. Lets set the state and see what we need to do.
  93 + m_current_state = mqtt::E_CLIENT_CONNECTED;
  94 +
  95 + if(!m_subTemp.first.isEmpty())
  96 + {
  97 + this->subscribe( m_subTemp.first );
  98 + }
  99 + else if(!m_pubTemp.first.isEmpty())
  100 + {
  101 + this->publish( m_pubTemp.first, m_pubTemp.second );
  102 + }
  103 +}
  104 +
  105 +void QMqttPubSubClient::slotOnDisconnected()
  106 +{
  107 + m_current_state = mqtt::E_CLIENT_DISCONNECTED;
  108 +}
  109 +
  110 +void QMqttPubSubClient::slotOnError(const QMQTT::ClientError error)
  111 +{
  112 + m_current_state = mqtt::E_CLIENT_ERROR;
  113 + LogError( "[QMqttPubSubClient::slotOnError]", QString( "An error occured : %1" ).arg( error ) );
  114 + LogError( "[QMqttPubSubClient::slotOnError]", this->getErrorMessage( error ) );
  115 +}
  116 +
  117 +QString QMqttPubSubClient::getErrorMessage( const QMQTT::ClientError error )
  118 +{
  119 +
  120 + QString l_error_message;
  121 +
  122 + switch( error )
  123 + {
  124 + case QMQTT::SocketConnectionRefusedError:
  125 + l_error_message = "[Socket] - Connection Refused";
  126 + break;
  127 + case QMQTT::SocketRemoteHostClosedError:
  128 + l_error_message = "[Socket] - Remote Host Closed";
  129 + emit signalReInitialise();
  130 + break;
  131 + case QMQTT::SocketHostNotFoundError:
  132 + l_error_message = "[Socket] - Host Not Found.";
  133 + break;
  134 + case QMQTT::SocketAccessError:
  135 + l_error_message = "[Socket] - Access Error.";
  136 + break;
  137 + case QMQTT::SocketResourceError:
  138 + l_error_message = "[Socket] - Resource Error.";
  139 + break;
  140 + case QMQTT::SocketTimeoutError:
  141 + l_error_message = "[Socket] - Timeout.";
  142 + break;
  143 + case QMQTT::SocketDatagramTooLargeError:
  144 + l_error_message = "[Socket] - Datagram Too Large.";
  145 + break;
  146 + case QMQTT::SocketNetworkError:
  147 + l_error_message = "[Socket] - Network Error.";
  148 + break;
  149 + case QMQTT::SocketAddressInUseError:
  150 + l_error_message = "[Socket] - Address In Use.";
  151 + break;
  152 + case QMQTT::SocketAddressNotAvailableError:
  153 + l_error_message = "[Socket] - Address Not Available.";
  154 + break;
  155 + case QMQTT::SocketUnsupportedSocketOperationError:
  156 + l_error_message = "[Socket] - Unsupported Socket Operation.";
  157 + break;
  158 + case QMQTT::SocketUnfinishedSocketOperationError:
  159 + l_error_message = "[Socket] - Unfinished Socket Operation.";
  160 + break;
  161 + case QMQTT::SocketProxyAuthenticationRequiredError:
  162 + l_error_message = "[Socket] - Proxy Authentication Required.";
  163 + break;
  164 + case QMQTT::SocketSslHandshakeFailedError:
  165 + l_error_message = "[Socket] - SSL Handshake Failed.";
  166 + break;
  167 + case QMQTT::SocketProxyConnectionRefusedError:
  168 + l_error_message = "[Socket] - Proxy Connection Refused.";
  169 + break;
  170 + case QMQTT::SocketProxyConnectionClosedError:
  171 + l_error_message = "[Socket] - Proxy Connection Closed.";
  172 + break;
  173 + case QMQTT::SocketProxyConnectionTimeoutError:
  174 + l_error_message = "[Socket] - Proxy Connection Closed.";
  175 + break;
  176 + case QMQTT::SocketProxyNotFoundError:
  177 + l_error_message = "[Socket] - Proxy Not Found.";
  178 + break;
  179 + case QMQTT::SocketProxyProtocolError:
  180 + l_error_message = "[Socket] - Proxy Protocol Error.";
  181 + break;
  182 + case QMQTT::SocketOperationError:
  183 + l_error_message = "[Socket] - Operation Error.";
  184 + break;
  185 + case QMQTT::SocketSslInternalError:
  186 + l_error_message = "[Socket] - SSL Internal Error.";
  187 + break;
  188 + case QMQTT::SocketSslInvalidUserDataError:
  189 + l_error_message = "[Socket] - SSL Invalid User Data.";
  190 + break;
  191 + case QMQTT::SocketTemporaryError:
  192 + l_error_message = "[Socket] - Temporary Error.";
  193 + break;
  194 + case QMQTT::MqttUnacceptableProtocolVersionError:
  195 + l_error_message = "[MQTT] - Unacceptable Protocol Version.";
  196 + break;
  197 + case QMQTT::MqttIdentifierRejectedError:
  198 + l_error_message = "[MQTT] - Identifier Rejected.";
  199 + break;
  200 + case QMQTT::MqttServerUnavailableError:
  201 + l_error_message = "[MQTT] - Server Unavailable.";
  202 + break;
  203 + case QMQTT::MqttBadUserNameOrPasswordError:
  204 + l_error_message = "[MQTT] - Bad Username Or Password.";
  205 + break;
  206 + case QMQTT::MqttNotAuthorizedError:
  207 + l_error_message = "[MQTT] - Not Authorized.";
  208 + break;
  209 + case QMQTT::MqttNoPingResponse:
  210 + l_error_message = "[MQTT] - No Ping Response";
  211 + break;
  212 + case QMQTT::UnknownError:
  213 + default:
  214 + l_error_message = "An Unknown Error Occurred";
  215 + break;
  216 + }
  217 +
  218 + return l_error_message;
  219 +}
  220 +
  221 +void QMqttPubSubClient::slotOnSubscribed(const QString& topic, const quint8 qos)
  222 +{
  223 + Q_UNUSED(qos);
  224 + m_current_state = mqtt::E_CLIENT_SUBSCRIBED;
  225 + LogInfo("[QMqttPubSubClient::slotOnSubscribed]", QString("Subscribed to topic %1").arg(topic));
  226 +}
  227 +
  228 +void QMqttPubSubClient::slotOnUnSubscribed(const QString& topic)
  229 +{
  230 + m_current_state = mqtt::E_CLIENT_UNSUBSCRIBED;
  231 + LogInfo("[QMqttPubSubClient::slotOnUnSubscribed]", QString("Unsubscribed to topic %1").arg(topic));
  232 +}
  233 +
  234 +void QMqttPubSubClient::slotOnPublished(const QMQTT::Message& message, quint16 msgid)
  235 +{
  236 +
  237 + m_current_state = mqtt::E_CLIENT_PUBLISHED;
  238 + LogInfo("[QMqttPubSubClient::slotOnPublished]", QString("Message %1 published to topic %2 with id %3").arg(message.topic()).arg(message.payload().toStdString().c_str()).arg(msgid));
  239 +}
  240 +
  241 +void QMqttPubSubClient::slotOnReceived(const QMQTT::Message& message)
  242 +{
  243 + LogDebug("[QMqttPubSubClient::slotOnReceived]", QString("Received payload : %1 from topic : %2").arg(message.payload().toStdString().c_str()).arg(message.topic()));
  244 + emit signalMessageReceived(message.topic(), message.payload().toStdString().c_str());
  245 +}
  246 +
  247 +void QMqttPubSubClient::slotOnPingResp()
  248 +{
  249 + LogDebug("[QMqttPubSubClient::slotOnPingResp]", QString("Ping Response received."));
  250 +}
  251 +
  252 +#ifndef QT_NO_SSL
  253 +void QMqttPubSubClient::slotSslErrors(const QList<QSslError>& errors)
  254 +{
  255 + Q_UNUSED(errors);
  256 +}
  257 +#endif /* QT_NO_SSL */
  258 +
  259 +void QMqttPubSubClient::connectSignalsAndSlots()
  260 +{
  261 + connect(this, &QMQTT::Client::connected, this, &QMqttPubSubClient::slotOnConnected);
  262 + connect(this, &QMQTT::Client::disconnected, this, &QMqttPubSubClient::slotOnDisconnected);
  263 + connect(this, &QMQTT::Client::error, this, &QMqttPubSubClient::slotOnError);
  264 + connect(this, &QMQTT::Client::subscribed, this, &QMqttPubSubClient::slotOnSubscribed);
  265 + connect(this, &QMQTT::Client::unsubscribed, this, &QMqttPubSubClient::slotOnUnSubscribed);
  266 + connect(this, &QMQTT::Client::published, this, &QMqttPubSubClient::slotOnPublished);
  267 + connect(this, &QMQTT::Client::received, this, &QMqttPubSubClient::slotOnReceived);
  268 + connect(this, &QMQTT::Client::pingresp, this, &QMqttPubSubClient::slotOnPingResp);
  269 +#ifndef QT_NO_SSL
  270 + connect(this, &QMQTT::Client::sslErrors, this, &QMqttPubSubClient::slotSslErrors);
  271 +#endif /* QT_NO_SSL */
  272 +}
src/qmqtt_pubsubclient.h 0 → 100644
  1 +++ a/src/qmqtt_pubsubclient.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef OSDEV_COMPONENTS_PUBSUBCLIENT_H
  23 +#define OSDEV_COMPONENTS_PUBSUBCLIENT_H
  24 +
  25 +// Qt
  26 +#include <QObject>
  27 +#include <QPair>
  28 +#include <QString>
  29 +
  30 +// osdev::components
  31 +#include "qmqtt_client.h"
  32 +#include "qmqtt_states.h"
  33 +#include "qmqtt_message.h"
  34 +#include "qmqtt_configsettings.h"
  35 +
  36 +namespace osdev {
  37 +namespace components {
  38 +
  39 +class QMqttPubSubClient : public QMQTT::Client
  40 +{
  41 + Q_OBJECT
  42 +
  43 +public:
  44 + explicit QMqttPubSubClient(const QHostAddress& host = QHostAddress::LocalHost,
  45 + const quint16 port = 1883,
  46 + QObject *parent = nullptr);
  47 +
  48 + virtual ~QMqttPubSubClient();
  49 +
  50 + void subscribe(const QString& message_topic);
  51 + void unsubscribe(const QString& message_topic);
  52 + void publish(const QString& message_topic, const QString& message_payload);
  53 +
  54 + QString getErrorMessage( const QMQTT::ClientError error );
  55 +
  56 +signals:
  57 + void signalMessageReceived(const QString& message_topic, const QString& message_payload);
  58 + void signalReInitialise();
  59 +
  60 +private slots:
  61 + // All status Slots
  62 + void slotOnConnected();
  63 + void slotOnDisconnected();
  64 + void slotOnError(const QMQTT::ClientError error);
  65 + void slotOnSubscribed(const QString& topic, const quint8 qos);
  66 + void slotOnUnSubscribed(const QString& topic);
  67 + void slotOnPublished(const QMQTT::Message& message, quint16 msgid);
  68 + void slotOnReceived(const QMQTT::Message& message);
  69 + void slotOnPingResp();
  70 +#ifndef QT_NO_SSL
  71 + void slotSslErrors(const QList<QSslError>& errors);
  72 +#endif /* QT_NO_SSL */
  73 +
  74 +private:
  75 + void connectSignalsAndSlots();
  76 +
  77 +private:
  78 + QString m_mqtt_topic;
  79 + mqtt::E_CLIENT_STATE m_current_state;
  80 + QPair<QString, QString> m_subTemp;
  81 + QPair<QString, QString> m_pubTemp;
  82 +
  83 +};
  84 +
  85 +} /* End namespace components */
  86 +} /* End namespace osdev */
  87 +
  88 +#endif /* OSDEV_COMPONENTS_PUBSUBCLIENT_H */
src/qmqtt_routedmessage.h 0 → 100644
  1 +++ a/src/qmqtt_routedmessage.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_ROUTEDMESSAGE_H
  23 +#define QMQTT_ROUTEDMESSAGE_H
  24 +
  25 +#include "qmqtt_message.h"
  26 +
  27 +#include <QMetaType>
  28 +#include <QHash>
  29 +#include <QString>
  30 +
  31 +namespace QMQTT {
  32 +
  33 +class RouteSubscription;
  34 +
  35 +class Q_MQTT_EXPORT RoutedMessage
  36 +{
  37 +public:
  38 + inline RoutedMessage()
  39 + {}
  40 + inline RoutedMessage(const Message &message)
  41 + : _message(message)
  42 + {}
  43 +
  44 + inline const Message &message() const
  45 + { return _message; }
  46 + inline QHash<QString, QString> parameters() const
  47 + { return _parameters; }
  48 +
  49 +private:
  50 + friend class RouteSubscription;
  51 +
  52 + Message _message;
  53 + QHash<QString, QString> _parameters;
  54 +};
  55 +
  56 +} // namespace QMQTT
  57 +
  58 +Q_DECLARE_METATYPE(QMQTT::RoutedMessage)
  59 +
  60 +#endif // QMQTT_ROUTEDMESSAGE_H
src/qmqtt_router.cpp 0 → 100644
  1 +++ a/src/qmqtt_router.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_router.h"
  23 +#include "qmqtt_client.h"
  24 +#include "qmqtt_routesubscription.h"
  25 +
  26 +#include <QLoggingCategory>
  27 +
  28 +namespace QMQTT {
  29 +
  30 +Q_LOGGING_CATEGORY(router, "qmqtt.router")
  31 +
  32 +Router::Router(Client *parent) : QObject(parent), _client(parent)
  33 +{
  34 +}
  35 +
  36 +RouteSubscription *Router::subscribe(const QString &route)
  37 +{
  38 + RouteSubscription *subscription = new RouteSubscription(this);
  39 + subscription->setRoute(route);
  40 + connect(_client, &Client::connected, subscription, [this, subscription]() {
  41 + _client->subscribe(subscription->_topic, 0);
  42 + });
  43 + if (_client->isConnectedToHost())
  44 + _client->subscribe(subscription->_topic, 0);
  45 + connect(_client, &Client::received, subscription, &RouteSubscription::routeMessage);
  46 + return subscription;
  47 +}
  48 +
  49 +Client *Router::client() const
  50 +{
  51 + return _client;
  52 +}
  53 +
  54 +} // namespace QMQTT
  55 +
src/qmqtt_router.h 0 → 100644
  1 +++ a/src/qmqtt_router.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_ROUTER_H
  23 +#define QMQTT_ROUTER_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QObject>
  28 +
  29 +namespace QMQTT {
  30 +
  31 +class Client;
  32 +class RouteSubscription;
  33 +
  34 +class Q_MQTT_EXPORT Router : public QObject
  35 +{
  36 + Q_OBJECT
  37 +public:
  38 + explicit Router(Client *parent = 0);
  39 +
  40 + RouteSubscription *subscribe(const QString &route);
  41 + Client *client() const;
  42 +
  43 +private:
  44 + Client *_client;
  45 +};
  46 +
  47 +} // namespace QMQTT
  48 +
  49 +#endif // QMQTT_ROUTER_H
src/qmqtt_routesubscription.cpp 0 → 100644
  1 +++ a/src/qmqtt_routesubscription.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_routesubscription.h"
  23 +#include "qmqtt_router.h"
  24 +#include "qmqtt_client.h"
  25 +#include "qmqtt_routedmessage.h"
  26 +
  27 +#include <QLoggingCategory>
  28 +#include <QLatin1String>
  29 +#include <QLatin1Char>
  30 +#include <QRegularExpressionMatch>
  31 +#include <QStringList>
  32 +
  33 +namespace QMQTT {
  34 +
  35 +Q_LOGGING_CATEGORY(routerSubscription, "qmqtt.routersubscription")
  36 +
  37 +RouteSubscription::RouteSubscription(Router *parent)
  38 + : QObject(parent),
  39 + _client(parent->client())
  40 +{
  41 + Q_ASSERT(!_client.isNull());
  42 +}
  43 +
  44 +RouteSubscription::~RouteSubscription()
  45 +{
  46 + if (Q_LIKELY(!_client.isNull() && _client->isConnectedToHost()))
  47 + _client->unsubscribe(_topic);
  48 +}
  49 +
  50 +QString RouteSubscription::route() const
  51 +{
  52 + return _topic;
  53 +}
  54 +
  55 +void RouteSubscription::setRoute(const QString &route)
  56 +{
  57 + QRegularExpression parameterNamesRegExp(QStringLiteral("\\:([a-zA-Z0-9]+)")); // note how names must not contain dashes or underscores
  58 +
  59 + // Remove paramter names to get the actual topic "route"
  60 + QString topic = route;
  61 + topic.remove(parameterNamesRegExp);
  62 +
  63 + // Remove the MQTT wildcards to get a regular expression, which matches the parameters
  64 + QString parameterRegExp = route;
  65 + parameterRegExp
  66 + .remove(QLatin1Char('+'))
  67 + .replace(parameterNamesRegExp, QStringLiteral("([a-zA-Z0-9_-]+)")) // note how parameter values may contain dashes or underscores
  68 + .remove(QLatin1Char('#'))
  69 + .replace(QLatin1String("$"), QLatin1String("\\$"));
  70 +
  71 + // Extract the parameter names
  72 + QRegularExpressionMatchIterator it = parameterNamesRegExp.globalMatch(route);
  73 + QStringList names;
  74 + while(it.hasNext()) {
  75 + QRegularExpressionMatch match = it.next();
  76 + QString parameterName = match.captured(1);
  77 + names << parameterName;
  78 + }
  79 +
  80 + _topic = topic;
  81 + _parameterNames = names;
  82 + _regularExpression = QRegularExpression(parameterRegExp);
  83 +}
  84 +
  85 +void RouteSubscription::routeMessage(const Message &message)
  86 +{
  87 + QString topic = message.topic();
  88 + QRegularExpressionMatch match = _regularExpression.match(topic);
  89 + if(!match.hasMatch()) {
  90 + return;
  91 + }
  92 +
  93 + RoutedMessage routedMessage(message);
  94 +
  95 + for(int i = 0, c = _parameterNames.size(); i < c; ++i) {
  96 + QString name = _parameterNames.at(i);
  97 + QString value = match.captured(i + 1);
  98 +
  99 + routedMessage._parameters.insert(name, value);
  100 + }
  101 +
  102 + emit received(routedMessage);
  103 +}
  104 +
  105 +} // namespace QMQTT
src/qmqtt_routesubscription.h 0 → 100644
  1 +++ a/src/qmqtt_routesubscription.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_ROUTESUBSCRIPTION_H
  23 +#define QMQTT_ROUTESUBSCRIPTION_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QObject>
  28 +#include <QPointer>
  29 +#include <QString>
  30 +#include <QRegularExpression>
  31 +#include <QStringList>
  32 +
  33 +namespace QMQTT {
  34 +
  35 +class Client;
  36 +class Message;
  37 +class RoutedMessage;
  38 +class Router;
  39 +
  40 +class Q_MQTT_EXPORT RouteSubscription : public QObject
  41 +{
  42 + Q_OBJECT
  43 +public:
  44 + ~RouteSubscription();
  45 +
  46 + QString route() const;
  47 +
  48 +signals:
  49 + void received(const RoutedMessage &message);
  50 +
  51 +private slots:
  52 + void routeMessage(const Message &message);
  53 +
  54 +private:
  55 + friend class Router;
  56 +
  57 + explicit RouteSubscription(Router *parent = 0);
  58 + void setRoute(const QString &route);
  59 +
  60 + QPointer<Client> _client;
  61 + QString _topic;
  62 + QRegularExpression _regularExpression;
  63 + QStringList _parameterNames;
  64 +};
  65 +
  66 +} // namespace QMQTT
  67 +
  68 +#endif // QMQTT_ROUTESUBSCRIPTION_H
src/qmqtt_socket.cpp 0 → 100644
  1 +++ a/src/qmqtt_socket.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_socket_p.h"
  23 +
  24 +#include <QTcpSocket>
  25 +
  26 +QMQTT::Socket::Socket(QObject* parent)
  27 + : SocketInterface(parent)
  28 + , _socket(new QTcpSocket(this))
  29 +{
  30 + connect(_socket.data(), &QTcpSocket::connected, this, &SocketInterface::connected);
  31 + connect(_socket.data(), &QTcpSocket::disconnected, this, &SocketInterface::disconnected);
  32 + connect(_socket.data(),
  33 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
  34 + static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::errorOccurred),
  35 +#else
  36 + static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error),
  37 +#endif
  38 + this,
  39 + static_cast<void (SocketInterface::*)(QAbstractSocket::SocketError)>(&SocketInterface::error));
  40 +}
  41 +
  42 +QMQTT::Socket::~Socket()
  43 +{
  44 +}
  45 +
  46 +QIODevice *QMQTT::Socket::ioDevice()
  47 +{
  48 + return _socket.data();
  49 +}
  50 +
  51 +void QMQTT::Socket::connectToHost(const QHostAddress& address, quint16 port)
  52 +{
  53 + _socket->connectToHost(address, port);
  54 +}
  55 +
  56 +void QMQTT::Socket::connectToHost(const QString& hostName, quint16 port)
  57 +{
  58 + _socket->connectToHost(hostName, port);
  59 +}
  60 +
  61 +void QMQTT::Socket::disconnectFromHost()
  62 +{
  63 + _socket->disconnectFromHost();
  64 +}
  65 +
  66 +QAbstractSocket::SocketState QMQTT::Socket::state() const
  67 +{
  68 + return _socket->state();
  69 +}
  70 +
  71 +QAbstractSocket::SocketError QMQTT::Socket::error() const
  72 +{
  73 + return _socket->error();
  74 +}
src/qmqtt_socket_p.h 0 → 100644
  1 +++ a/src/qmqtt_socket_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_SOCKET_P_H
  23 +#define QMQTT_SOCKET_P_H
  24 +
  25 +#include "qmqtt_socketinterface.h"
  26 +
  27 +#include <QObject>
  28 +#include <QHostAddress>
  29 +#include <QString>
  30 +#include <QAbstractSocket>
  31 +#include <QScopedPointer>
  32 +
  33 +QT_FORWARD_DECLARE_CLASS(QIODevice)
  34 +QT_FORWARD_DECLARE_CLASS(QTcpSocket)
  35 +
  36 +namespace QMQTT
  37 +{
  38 +
  39 +class Socket : public SocketInterface
  40 +{
  41 + Q_OBJECT
  42 +public:
  43 + explicit Socket(QObject* parent = NULL);
  44 + virtual ~Socket();
  45 +
  46 + virtual QIODevice *ioDevice();
  47 + void connectToHost(const QHostAddress& address, quint16 port);
  48 + void connectToHost(const QString& hostName, quint16 port);
  49 + void disconnectFromHost();
  50 + QAbstractSocket::SocketState state() const;
  51 + QAbstractSocket::SocketError error() const;
  52 +
  53 +protected:
  54 + QScopedPointer<QTcpSocket> _socket;
  55 +};
  56 +
  57 +}
  58 +
  59 +#endif // QMQTT_SOCKET_P_H
src/qmqtt_socketinterface.h 0 → 100644
  1 +++ a/src/qmqtt_socketinterface.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_SOCKET_INTERFACE_H
  23 +#define QMQTT_SOCKET_INTERFACE_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QObject>
  28 +#include <QHostAddress>
  29 +#include <QString>
  30 +#include <QAbstractSocket>
  31 +#include <QList>
  32 +
  33 +#ifndef QT_NO_SSL
  34 +#include <QSslConfiguration>
  35 +QT_FORWARD_DECLARE_CLASS(QSslError)
  36 +#endif // QT_NO_SSL
  37 +
  38 +QT_FORWARD_DECLARE_CLASS(QIODevice)
  39 +
  40 +namespace QMQTT
  41 +{
  42 +
  43 +class Q_MQTT_EXPORT SocketInterface : public QObject
  44 +{
  45 + Q_OBJECT
  46 +public:
  47 + explicit SocketInterface(QObject* parent = NULL) : QObject(parent) {}
  48 + virtual ~SocketInterface() {}
  49 +
  50 + virtual QIODevice* ioDevice() = 0;
  51 + virtual void connectToHost(const QHostAddress& address, quint16 port) = 0;
  52 + virtual void connectToHost(const QString& hostName, quint16 port) = 0;
  53 + virtual void disconnectFromHost() = 0;
  54 + virtual QAbstractSocket::SocketState state() const = 0;
  55 + virtual QAbstractSocket::SocketError error() const = 0;
  56 +#ifndef QT_NO_SSL
  57 + virtual void ignoreSslErrors(const QList<QSslError>& errors) { Q_UNUSED(errors); }
  58 + virtual void ignoreSslErrors() {}
  59 + virtual QSslConfiguration sslConfiguration() const { return QSslConfiguration(); }
  60 + virtual void setSslConfiguration(const QSslConfiguration& config) { Q_UNUSED(config); }
  61 +#endif // QT_NO_SSL
  62 +
  63 +signals:
  64 + void connected();
  65 + void disconnected();
  66 + void error(QAbstractSocket::SocketError socketError);
  67 +#ifndef QT_NO_SSL
  68 + void sslErrors(const QList<QSslError>& errors);
  69 +#endif // QT_NO_SSL
  70 +};
  71 +
  72 +}
  73 +
  74 +#endif // QMQTT_SOCKET_INTERFACE_H
src/qmqtt_ssl_socket.cpp 0 → 100644
  1 +++ a/src/qmqtt_ssl_socket.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_ssl_socket_p.h"
  23 +
  24 +#ifndef QT_NO_SSL
  25 +
  26 +#include <QSslSocket>
  27 +#include <QSslError>
  28 +
  29 +QMQTT::SslSocket::SslSocket(const QSslConfiguration& config, QObject* parent)
  30 + : SocketInterface(parent)
  31 + , _socket(new QSslSocket(this))
  32 +{
  33 + _socket->setSslConfiguration(config);
  34 + connect(_socket.data(), &QSslSocket::encrypted, this, &SocketInterface::connected);
  35 + connect(_socket.data(), &QSslSocket::disconnected, this, &SocketInterface::disconnected);
  36 + connect(_socket.data(),
  37 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
  38 + static_cast<void (QSslSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::errorOccurred),
  39 +#else
  40 + static_cast<void (QSslSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::error),
  41 +#endif
  42 + this,
  43 + static_cast<void (SocketInterface::*)(QAbstractSocket::SocketError)>(&SocketInterface::error));
  44 + connect(_socket.data(),
  45 + static_cast<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors),
  46 + this,
  47 + &SslSocket::sslErrors);
  48 +}
  49 +
  50 +QMQTT::SslSocket::~SslSocket()
  51 +{
  52 +}
  53 +
  54 +QIODevice *QMQTT::SslSocket::ioDevice()
  55 +{
  56 + return _socket.data();
  57 +}
  58 +
  59 +void QMQTT::SslSocket::connectToHost(const QHostAddress& address, quint16 port)
  60 +{
  61 + _socket->connectToHostEncrypted(address.toString(), port);
  62 +}
  63 +
  64 +void QMQTT::SslSocket::connectToHost(const QString& hostName, quint16 port)
  65 +{
  66 + _socket->connectToHostEncrypted(hostName, port);
  67 +}
  68 +
  69 +void QMQTT::SslSocket::disconnectFromHost()
  70 +{
  71 + _socket->disconnectFromHost();
  72 +}
  73 +
  74 +QAbstractSocket::SocketState QMQTT::SslSocket::state() const
  75 +{
  76 + return _socket->state();
  77 +}
  78 +
  79 +QAbstractSocket::SocketError QMQTT::SslSocket::error() const
  80 +{
  81 + return _socket->error();
  82 +}
  83 +
  84 +void QMQTT::SslSocket::ignoreSslErrors(const QList<QSslError>& errors)
  85 +{
  86 + _socket->ignoreSslErrors(errors);
  87 +}
  88 +
  89 +void QMQTT::SslSocket::ignoreSslErrors()
  90 +{
  91 + _socket->ignoreSslErrors();
  92 +}
  93 +
  94 +QSslConfiguration QMQTT::SslSocket::sslConfiguration() const
  95 +{
  96 + return _socket->sslConfiguration();
  97 +}
  98 +
  99 +void QMQTT::SslSocket::setSslConfiguration(const QSslConfiguration& config)
  100 +{
  101 + _socket->setSslConfiguration(config);
  102 +}
  103 +
  104 +#endif // QT_NO_SSL
src/qmqtt_ssl_socket_p.h 0 → 100644
  1 +++ a/src/qmqtt_ssl_socket_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_SSL_SOCKET_P_H
  23 +#define QMQTT_SSL_SOCKET_P_H
  24 +
  25 +#ifndef QT_NO_SSL
  26 +
  27 +#include "qmqtt_socketinterface.h"
  28 +
  29 +#include <QObject>
  30 +#include <QHostAddress>
  31 +#include <QString>
  32 +#include <QList>
  33 +#include <QScopedPointer>
  34 +
  35 +QT_FORWARD_DECLARE_CLASS(QSslSocket)
  36 +QT_FORWARD_DECLARE_CLASS(QSslError)
  37 +#include <QSslConfiguration>
  38 +
  39 +namespace QMQTT
  40 +{
  41 +
  42 +class SslSocket : public SocketInterface
  43 +{
  44 + Q_OBJECT
  45 +public:
  46 + explicit SslSocket(const QSslConfiguration& config, QObject* parent = NULL);
  47 + virtual ~SslSocket();
  48 +
  49 + virtual QIODevice *ioDevice();
  50 + void connectToHost(const QHostAddress& address, quint16 port);
  51 + void connectToHost(const QString& hostName, quint16 port);
  52 + void disconnectFromHost();
  53 + QAbstractSocket::SocketState state() const;
  54 + QAbstractSocket::SocketError error() const;
  55 + void ignoreSslErrors(const QList<QSslError>& errors);
  56 + void ignoreSslErrors();
  57 + QSslConfiguration sslConfiguration() const;
  58 + void setSslConfiguration(const QSslConfiguration& config);
  59 +
  60 +protected:
  61 + QScopedPointer<QSslSocket> _socket;
  62 +};
  63 +
  64 +}
  65 +
  66 +#endif // QT_NO_SSL
  67 +
  68 +#endif // QMQTT_SSL_SOCKET_P_H
src/qmqtt_states.h 0 → 100644
  1 +++ a/src/qmqtt_states.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef OSDEV_COMPONENTS_MQTT_STATES_H
  23 +#define OSDEV_COMPONENTS_MQTT_STATES_H
  24 +
  25 +namespace osdev {
  26 +namespace components {
  27 +namespace mqtt {
  28 +enum E_CLIENT_STATE
  29 +{
  30 + E_CLIENT_UNKNOWN = 0,
  31 + E_CLIENT_CONNECTED,
  32 + E_CLIENT_DISCONNECTED,
  33 + E_CLIENT_ERROR,
  34 + E_CLIENT_SUBSCRIBED,
  35 + E_CLIENT_UNSUBSCRIBED,
  36 + E_CLIENT_PUBLISHED,
  37 + E_CLIENT_SSL_ERRORS
  38 +};
  39 +
  40 +} /* End namespace mqtt */
  41 +} /* End namespace components */
  42 +} /* End namespace osdev */
  43 +
  44 +#endif /* OSDEV_COMPONENTS_MQTT_STATES_H */
src/qmqtt_timer.cpp 0 → 100644
  1 +++ a/src/qmqtt_timer.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "qmqtt_timer_p.h"
  23 +
  24 +QMQTT::Timer::Timer(QObject* parent)
  25 + : TimerInterface(parent)
  26 +{
  27 + connect(&_timer, &QTimer::timeout, this, &TimerInterface::timeout);
  28 +}
  29 +
  30 +QMQTT::Timer::~Timer()
  31 +{
  32 +}
  33 +
  34 +bool QMQTT::Timer::isSingleShot() const
  35 +{
  36 + return _timer.isSingleShot();
  37 +}
  38 +
  39 +void QMQTT::Timer::setSingleShot(bool singleShot)
  40 +{
  41 + _timer.setSingleShot(singleShot);
  42 +}
  43 +
  44 +int QMQTT::Timer::interval() const
  45 +{
  46 + return _timer.interval();
  47 +}
  48 +
  49 +void QMQTT::Timer::setInterval(int msec)
  50 +{
  51 + _timer.setInterval(msec);
  52 +}
  53 +
  54 +void QMQTT::Timer::start()
  55 +{
  56 + _timer.start();
  57 +}
  58 +
  59 +void QMQTT::Timer::stop()
  60 +{
  61 + _timer.stop();
  62 +}
src/qmqtt_timer_p.h 0 → 100644
  1 +++ a/src/qmqtt_timer_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_TIMER_P_H
  23 +#define QMQTT_TIMER_P_H
  24 +
  25 +#include "qmqtt_timerinterface.h"
  26 +
  27 +#include <QObject>
  28 +#include <QTimer>
  29 +
  30 +namespace QMQTT {
  31 +
  32 +class Timer : public TimerInterface
  33 +{
  34 + Q_OBJECT
  35 +public:
  36 + explicit Timer(QObject *parent = 0);
  37 + virtual ~Timer();
  38 +
  39 + bool isSingleShot() const;
  40 + void setSingleShot(bool singleShot);
  41 + int interval() const;
  42 + void setInterval(int msec);
  43 + void start();
  44 + void stop();
  45 +
  46 +protected:
  47 + QTimer _timer;
  48 +};
  49 +
  50 +}
  51 +
  52 +#endif // QMQTT_TIMER_P_H
src/qmqtt_timerinterface.h 0 → 100644
  1 +++ a/src/qmqtt_timerinterface.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_TIMER_INTERFACE_H
  23 +#define QMQTT_TIMER_INTERFACE_H
  24 +
  25 +#include "qmqtt_global.h"
  26 +
  27 +#include <QObject>
  28 +
  29 +namespace QMQTT {
  30 +
  31 +class Q_MQTT_EXPORT TimerInterface : public QObject
  32 +{
  33 + Q_OBJECT
  34 +public:
  35 + explicit TimerInterface(QObject* parent = NULL) : QObject(parent) {}
  36 + virtual ~TimerInterface() {}
  37 +
  38 + virtual bool isSingleShot() const = 0;
  39 + virtual void setSingleShot(bool singleShot) = 0;
  40 + virtual int interval() const = 0;
  41 + virtual void setInterval(int msec) = 0;
  42 + virtual void start() = 0;
  43 + virtual void stop() = 0;
  44 +
  45 +signals:
  46 + void timeout();
  47 +};
  48 +
  49 +}
  50 +
  51 +#endif // QMQTT_TIMER_INTERFACE_H
  52 +
src/qmqtt_websocket.cpp 0 → 100644
  1 +++ a/src/qmqtt_websocket.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifdef QT_WEBSOCKETS_LIB
  23 +
  24 +#include "qmqtt_websocket_p.h"
  25 +
  26 +#include <QNetworkRequest>
  27 +#include <QUrl>
  28 +#include <QSslError>
  29 +
  30 +#ifndef QT_NO_SSL
  31 +QMQTT::WebSocket::WebSocket(const QString& origin,
  32 + QWebSocketProtocol::Version version,
  33 + const QSslConfiguration* sslConfig,
  34 + QObject* parent)
  35 + : SocketInterface(parent)
  36 + , _socket(new QWebSocket(origin, version, this))
  37 + , _ioDevice(new WebSocketIODevice(_socket, this))
  38 +{
  39 + initialize();
  40 + if (sslConfig != NULL)
  41 + _socket->setSslConfiguration(*sslConfig);
  42 + connect(_socket, &QWebSocket::sslErrors, this, &WebSocket::sslErrors);
  43 +}
  44 +#endif // QT_NO_SSL
  45 +
  46 +QMQTT::WebSocket::WebSocket(const QString& origin,
  47 + QWebSocketProtocol::Version version,
  48 + QObject* parent)
  49 + : SocketInterface(parent)
  50 + , _socket(new QWebSocket(origin, version, this))
  51 + , _ioDevice(new WebSocketIODevice(_socket, this))
  52 +{
  53 + initialize();
  54 +}
  55 +
  56 +void QMQTT::WebSocket::initialize()
  57 +{
  58 + connect(_socket, &QWebSocket::connected, this, &WebSocket::connected);
  59 + connect(_socket, &QWebSocket::disconnected, this, &WebSocket::disconnected);
  60 + connect(_socket,
  61 + static_cast<void (QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error),
  62 + this,
  63 + static_cast<void (SocketInterface::*)(QAbstractSocket::SocketError)>(&SocketInterface::error));
  64 +}
  65 +
  66 +QMQTT::WebSocket::~WebSocket()
  67 +{
  68 +}
  69 +
  70 +void QMQTT::WebSocket::connectToHost(const QHostAddress& address, quint16 port)
  71 +{
  72 + Q_UNUSED(address)
  73 + Q_UNUSED(port)
  74 + qFatal("No supported");
  75 +}
  76 +
  77 +void QMQTT::WebSocket::connectToHost(const QString& hostName, quint16 port)
  78 +{
  79 + Q_UNUSED(port)
  80 + QUrl url(hostName);
  81 + QNetworkRequest request(url);
  82 + request.setRawHeader("Sec-WebSocket-Protocol", "mqtt");
  83 + _ioDevice->connectToHost(request);
  84 +}
  85 +
  86 +void QMQTT::WebSocket::disconnectFromHost()
  87 +{
  88 + _socket->close();
  89 +}
  90 +
  91 +QAbstractSocket::SocketState QMQTT::WebSocket::state() const
  92 +{
  93 + return _socket->state();
  94 +}
  95 +
  96 +QAbstractSocket::SocketError QMQTT::WebSocket::error() const
  97 +{
  98 + return _socket->error();
  99 +}
  100 +
  101 +#ifndef QT_NO_SSL
  102 +void QMQTT::WebSocket::ignoreSslErrors(const QList<QSslError>& errors)
  103 +{
  104 + _socket->ignoreSslErrors(errors);
  105 +}
  106 +
  107 +void QMQTT::WebSocket::ignoreSslErrors()
  108 +{
  109 + _socket->ignoreSslErrors();
  110 +}
  111 +
  112 +QSslConfiguration QMQTT::WebSocket::sslConfiguration() const
  113 +{
  114 + return _socket->sslConfiguration();
  115 +}
  116 +
  117 +void QMQTT::WebSocket::setSslConfiguration(const QSslConfiguration& config)
  118 +{
  119 + _socket->setSslConfiguration(config);
  120 +}
  121 +
  122 +#endif // QT_NO_SSL
  123 +
  124 +#endif // QT_WEBSOCKETS_LIB
src/qmqtt_websocket_p.h 0 → 100644
  1 +++ a/src/qmqtt_websocket_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_WEBSOCKET_H
  23 +#define QMQTT_WEBSOCKET_H
  24 +
  25 +#ifdef QT_WEBSOCKETS_LIB
  26 +
  27 +#include <qmqtt_socketinterface.h>
  28 +#include <qmqtt_websocketiodevice_p.h>
  29 +
  30 +#include <QObject>
  31 +#include <QWebSocket>
  32 +#include <QHostAddress>
  33 +#include <QString>
  34 +#include <QList>
  35 +#include <QAbstractSocket>
  36 +
  37 +QT_FORWARD_DECLARE_CLASS(QIODevice)
  38 +
  39 +#ifndef QT_NO_SSL
  40 +#include <QSslConfiguration>
  41 +QT_FORWARD_DECLARE_CLASS(QSslError)
  42 +#endif // QT_NO_SSL
  43 +
  44 +namespace QMQTT
  45 +{
  46 +
  47 +class WebSocket : public SocketInterface
  48 +{
  49 + Q_OBJECT
  50 +public:
  51 +#ifndef QT_NO_SSL
  52 + WebSocket(const QString& origin,
  53 + QWebSocketProtocol::Version version,
  54 + const QSslConfiguration* sslConfig,
  55 + QObject* parent = NULL);
  56 +#endif // QT_NO_SSL
  57 +
  58 + WebSocket(const QString& origin,
  59 + QWebSocketProtocol::Version version,
  60 + QObject* parent = NULL);
  61 +
  62 + virtual ~WebSocket();
  63 +
  64 + QIODevice *ioDevice()
  65 + {
  66 + return _ioDevice;
  67 + }
  68 +
  69 + void connectToHost(const QHostAddress& address, quint16 port);
  70 + void connectToHost(const QString& hostName, quint16 port);
  71 + void disconnectFromHost();
  72 + QAbstractSocket::SocketState state() const;
  73 + QAbstractSocket::SocketError error() const;
  74 +#ifndef QT_NO_SSL
  75 + void ignoreSslErrors(const QList<QSslError>& errors);
  76 + void ignoreSslErrors();
  77 + QSslConfiguration sslConfiguration() const;
  78 + void setSslConfiguration(const QSslConfiguration& config);
  79 +#endif // QT_NO_SSL
  80 +
  81 +private:
  82 + void initialize();
  83 +
  84 + QWebSocket *_socket;
  85 + WebSocketIODevice *_ioDevice;
  86 +};
  87 +
  88 +}
  89 +
  90 +#endif // QT_WEBSOCKETS_LIB
  91 +
  92 +#endif // QMQTT_WEBSOCKET_H
src/qmqtt_websocketiodevice.cpp 0 → 100644
  1 +++ a/src/qmqtt_websocketiodevice.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifdef QT_WEBSOCKETS_LIB
  23 +
  24 +#include "qmqtt_websocketiodevice_p.h"
  25 +
  26 +#include <QWebSocket>
  27 +
  28 +QMQTT::WebSocketIODevice::WebSocketIODevice(QWebSocket *socket, QObject *parent)
  29 + : QIODevice(parent)
  30 + , _webSocket(socket)
  31 +{
  32 + connect(_webSocket, &QWebSocket::bytesWritten, this, &WebSocketIODevice::bytesWritten);
  33 + connect(_webSocket, &QWebSocket::binaryMessageReceived,
  34 + this, &WebSocketIODevice::binaryMessageReceived);
  35 +}
  36 +
  37 +bool QMQTT::WebSocketIODevice::connectToHost(const QNetworkRequest &request)
  38 +{
  39 + _webSocket->open(request);
  40 + return QIODevice::open(QIODevice::ReadWrite);
  41 +}
  42 +
  43 +qint64 QMQTT::WebSocketIODevice::bytesAvailable() const
  44 +{
  45 + return _buffer.count();
  46 +}
  47 +
  48 +void QMQTT::WebSocketIODevice::binaryMessageReceived(const QByteArray &frame)
  49 +{
  50 + _buffer.append(frame);
  51 + emit readyRead();
  52 +}
  53 +
  54 +qint64 QMQTT::WebSocketIODevice::readData(char *data, qint64 maxSize)
  55 +{
  56 + int size = qMin(static_cast<int>(maxSize), _buffer.count());
  57 + for (int i=0; i<size; ++ i)
  58 + data[i] = _buffer[i];
  59 + _buffer.remove(0, size);
  60 + return size;
  61 +}
  62 +
  63 +qint64 QMQTT::WebSocketIODevice::writeData(const char *data, qint64 maxSize)
  64 +{
  65 + QByteArray d(data, static_cast<int>(maxSize));
  66 + return _webSocket->sendBinaryMessage(d);
  67 +}
  68 +
  69 +#endif // QT_WEBSOCKETS_LIB
src/qmqtt_websocketiodevice_p.h 0 → 100644
  1 +++ a/src/qmqtt_websocketiodevice_p.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#ifndef QMQTT_WEBSOCKETIODEVICE_H
  23 +#define QMQTT_WEBSOCKETIODEVICE_H
  24 +
  25 +#ifdef QT_WEBSOCKETS_LIB
  26 +
  27 +#include <QByteArray>
  28 +#include <QIODevice>
  29 +#include <QList>
  30 +#include <QAbstractSocket>
  31 +
  32 +QT_FORWARD_DECLARE_CLASS(QWebSocket)
  33 +QT_FORWARD_DECLARE_CLASS(QNetworkRequest)
  34 +QT_FORWARD_DECLARE_CLASS(QSslError)
  35 +
  36 +namespace QMQTT
  37 +{
  38 +
  39 +class WebSocketIODevice : public QIODevice
  40 +{
  41 + Q_OBJECT
  42 +public:
  43 + explicit WebSocketIODevice(QWebSocket *socket, QObject *parent = NULL);
  44 +
  45 + bool connectToHost(const QNetworkRequest &request);
  46 +
  47 + virtual qint64 bytesAvailable() const;
  48 +
  49 +signals:
  50 + void connected();
  51 +
  52 + void disconnected();
  53 +
  54 + void error(QAbstractSocket::SocketError error);
  55 +
  56 + void sslErrors(const QList<QSslError> &errors);
  57 +
  58 +protected:
  59 + virtual qint64 readData(char *data, qint64 maxSize);
  60 +
  61 + virtual qint64 writeData(const char *data, qint64 maxSize);
  62 +
  63 +private slots:
  64 + void binaryMessageReceived(const QByteArray &frame);
  65 +
  66 +private:
  67 + QByteArray _buffer;
  68 + QWebSocket *_webSocket;
  69 +};
  70 +
  71 +}
  72 +
  73 +#endif // QT_WEBSOCKETS_LIB
  74 +
  75 +#endif // QMQTT_WEBSOCKETIODEVICE_H
tests/CMakeLists.txt 0 → 100644
  1 +++ a/tests/CMakeLists.txt
  1 +cmake_minimum_required(VERSION 3.0)
  2 +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
  3 +
  4 +include(projectheader)
  5 +project_header(test_logutils)
  6 +
  7 +include_directories( SYSTEM
  8 + ${CMAKE_CURRENT_SOURCE_DIR}/../../src
  9 +)
  10 +
  11 +include(compiler)
  12 +set(SRC_LIST
  13 +)
  14 +
  15 +# add_executable( ${PROJECT_NAME}
  16 +# ${SRC_LIST}
  17 +# )
  18 +
  19 +# target_link_libraries(
  20 +# ${PROJECT_NAME}
  21 +# )
  22 +
  23 +# set_target_properties( ${PROJECT_NAME} PROPERTIES
  24 +# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
  25 +# LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
  26 +# ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive
  27 +# )
  28 +
  29 +# include(installation)
  30 +# install_application()