Hello community,

here is the log from the commit of package noson for openSUSE:Factory checked 
in at 2019-01-24 14:13:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/noson (Old)
 and      /work/SRC/openSUSE:Factory/.noson.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "noson"

Thu Jan 24 14:13:51 2019 rev:3 rq:667840 version:1.10.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/noson/noson.changes      2018-08-04 
21:55:01.621459719 +0200
+++ /work/SRC/openSUSE:Factory/.noson.new.28833/noson.changes   2019-01-24 
14:13:53.143329858 +0100
@@ -1,0 +2,14 @@
+Mon Jan 21 17:14:29 UTC 2019 - bo...@opensuse.org
+
+- Update to 1.10.4
+  * Add fallback to parse malformed xml
+  * Refactor secure socket and fix SNI issue
+  * Add functions to handles bass and treble levels
+  * Add functions to provides the protocol identifier from an URI
+  * Fix the parse of alarm recurrence
+  * Remove unused builtin functions since standard C++98 is no 
+    longer supported
+  * Improve SMAPI interoperability
+  * Improve OAuth registration for third part services
+
+-------------------------------------------------------------------

Old:
----
  1.8.2.tar.gz

New:
----
  1.10.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ noson.spec ++++++
--- /var/tmp/diff_new_pack.Kmj223/_old  2019-01-24 14:13:53.683329234 +0100
+++ /var/tmp/diff_new_pack.Kmj223/_new  2019-01-24 14:13:53.687329231 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package noson
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           noson
-Version:        1.8.2
+Version:        1.10.4
 Release:        0
 Summary:        C++ library for accessing sonos devices
 License:        GPL-3.0-or-later

++++++ 1.8.2.tar.gz -> 1.10.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/README.md new/noson-1.10.4/README.md
--- old/noson-1.8.2/README.md   2018-07-22 23:32:32.000000000 +0200
+++ new/noson-1.10.4/README.md  2019-01-10 10:19:26.000000000 +0100
@@ -11,18 +11,15 @@
 
 ### Linux, BSD, OSX
 
-Start by creating a build folder
-<pre><code>mkdir -p build
-rm -rf build/*
-cd build/</code></pre>
-
-To build execute the following:
-<pre><code>cmake -DCMAKE_BUILD_TYPE=Release ..
-make</code></pre>
+Configure, make and install
+
+<pre><code>cmake -DCMAKE_BUILD_TYPE=Release $NOSON_PROJECT_DIR
+make
+sudo make install</code></pre>
 
 ### Windows
 
-Start by installing VC strudio 2012 and CMAKE tool
+Start by installing VC studio 2012 and CMAKE tool
 
 To build open a command tool CMD.EXE from the project folder and execute the 
following
 <pre><code>mkdir build_vc
@@ -36,5 +33,7 @@
 
 ## Generate the documentation
 
+sudo apt-get install graphviz
+
 doxygen <root path of noson>/docs/doxygen-dev.cfg
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/docs/doxygen-dev.cfg 
new/noson-1.10.4/docs/doxygen-dev.cfg
--- old/noson-1.8.2/docs/doxygen-dev.cfg        2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/docs/doxygen-dev.cfg       2019-01-10 10:19:26.000000000 
+0100
@@ -686,7 +686,7 @@
 # Note that relative paths are relative to the directory from which doxygen is
 # run.
 
-EXCLUDE                =
+EXCLUDE                = ../noson/src/private
 
 # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
 # directories that are symbolic links (a Unix file system feature) are excluded
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/CMakeLists.txt 
new/noson-1.10.4/noson/CMakeLists.txt
--- old/noson-1.8.2/noson/CMakeLists.txt        2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/CMakeLists.txt       2019-01-10 10:19:26.000000000 
+0100
@@ -14,15 +14,11 @@
   OPTION (STATIC_CRT "Link the static CRT libraries" OFF)
 endif ()
 
-if (NOT MSVC)
-  OPTION (REQUIRE_CXX_98 "Require standard c++98" OFF)
-endif ()
-
 ###############################################################################
 # set lib version here
 set (noson_VERSION_MAJOR 1)
-set (noson_VERSION_MINOR 8)
-set (noson_VERSION_PATCH 2)
+set (noson_VERSION_MINOR 10)
+set (noson_VERSION_PATCH 4)
 
 set (noson_VERSION 
${noson_VERSION_MAJOR}.${noson_VERSION_MINOR}.${noson_VERSION_PATCH})
 set (NOSON_LIB_VERSION ${noson_VERSION})
@@ -53,23 +49,10 @@
 
   include(CheckCXXCompilerFlag)
   CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
-  if(NOT REQUIRE_CXX_98 AND COMPILER_SUPPORTS_CXX11)
+  if(COMPILER_SUPPORTS_CXX11)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-    message(STATUS "Using standard c++11")
   else()
-    CHECK_CXX_COMPILER_FLAG("-std=c++98" COMPILER_SUPPORTS_CXX98)
-    if(COMPILER_SUPPORTS_CXX98)
-      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98")
-      message(STATUS "Using standard c++98")
-    endif()
-    include (CheckLibraryExists)
-    include (CheckAtomic)
-    if (HAS_BUILTIN_SYNC_ADD_AND_FETCH)
-      add_definitions ("-DHAS_BUILTIN_SYNC_ADD_AND_FETCH")
-    endif ()
-    if (HAS_BUILTIN_SYNC_SUB_AND_FETCH)
-      add_definitions ("-DHAS_BUILTIN_SYNC_SUB_AND_FETCH")
-    endif ()
+    message(FATAL_ERROR "CXX compiler doesn't support standard c++11") 
   endif ()
 endif ()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/alarm.cpp 
new/noson-1.10.4/noson/src/alarm.cpp
--- old/noson-1.8.2/noson/src/alarm.cpp 2018-07-22 23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/alarm.cpp        2019-01-10 10:19:26.000000000 
+0100
@@ -179,7 +179,7 @@
       unsigned lon = strlen(RecurrenceTable[Recurrence_ON]);
       if (it->length() > lon && it->substr(0, lon) == 
RecurrenceTable[Recurrence_ON])
       {
-        std::string days = it->substr(lon + 1, std::string::npos);
+        std::string days = it->substr(lon, std::string::npos);
         for (unsigned i = 0; i < days.length(); ++i)
         {
           char dno = days[i] - 0x30;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/musicservices.cpp 
new/noson-1.10.4/noson/src/musicservices.cpp
--- old/noson-1.8.2/noson/src/musicservices.cpp 2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/musicservices.cpp        2019-01-10 
10:19:26.000000000 +0100
@@ -28,6 +28,8 @@
 #include "private/wsresponse.h"
 #include "private/os/threads/mutex.h"
 
+#define USER_AGENT "Linux UPnP/1.0 Sonos/36.4-41270 (ACR_noson)"
+
 using namespace NSROOT;
 
 const std::string MusicServices::Name("MusicServices");
@@ -200,9 +202,8 @@
     // store new value of version
     versionPtr->assign(vars.GetValue("AvailableServiceListVersion"));
     std::string agent;
-    //@FIXME make the user agent string according to the template: Linux 
UPnP/1.0 Sonos/26.99-12345
-    //Resolved by SoCo: 
https://github.com/SoCo/SoCo/blob/18ee1ec11bba8463c4536aa7c2a25f5c20a051a4/soco/music_services/music_service.py#L55
-    agent.assign("Linux UPnP/1.0 Sonos/26.99-12345");
+    // configure a valid user-agent
+    agent.assign(USER_AGENT);
 
     // Fill the list of services.
     for (std::vector<ElementList>::const_iterator it = data.begin(); it != 
data.end(); ++it)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/private/builtin.h 
new/noson-1.10.4/noson/src/private/builtin.h
--- old/noson-1.8.2/noson/src/private/builtin.h 2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/private/builtin.h        2019-01-10 
10:19:26.000000000 +0100
@@ -55,48 +55,6 @@
 #define string_to_uint8 __str2uint8
 extern int string_to_uint8(const char *str, uint8_t *num);
 
-#define int64_to_string __int64str
-static CC_INLINE void int64_to_string(int64_t num, char *str)
-{
-  sprintf(str, "%lld", (long long)num);
-}
-
-#define int32_to_string __int32str
-static CC_INLINE void int32_to_string(int32_t num, char *str)
-{
-  sprintf(str, "%ld", (long)num);
-}
-
-#define int16_to_string __int16str
-static CC_INLINE void int16_to_string(int16_t num, char *str)
-{
-  sprintf(str, "%d", num);
-}
-
-#define int8_to_string __int8str
-static CC_INLINE void int8_to_string(int8_t num, char *str)
-{
-  sprintf(str, "%d", num);
-}
-
-#define uint32_to_string __uint32str
-static CC_INLINE void uint32_to_string(uint32_t num, char *str)
-{
-  sprintf(str, "%lu", (unsigned long)num);
-}
-
-#define uint16_to_string __uint16str
-static CC_INLINE void uint16_to_string(uint16_t num, char *str)
-{
-  sprintf(str, "%u", num);
-}
-
-#define uint8_to_string __uint8str
-static CC_INLINE void uint8_to_string(uint8_t num, char *str)
-{
-  sprintf(str, "%u", num);
-}
-
 #define TIMESTAMP_UTC_LEN (sizeof("YYYY-MM-DDTHH:MM:SSZ") - 1)
 #define TIMESTAMP_LEN     (sizeof("YYYY-MM-DDTHH:MM:SS") - 1)
 #define DATESTAMP_LEN     (sizeof("YYYY-MM-DD") - 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/private/securesocket.cpp 
new/noson-1.10.4/noson/src/private/securesocket.cpp
--- old/noson-1.8.2/noson/src/private/securesocket.cpp  2018-07-22 
23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/private/securesocket.cpp 2019-01-10 
10:19:26.000000000 +0100
@@ -34,14 +34,6 @@
 #define ERRNO_INTR EINTR
 #endif /* __WINDOWS__ */
 
-#if HAVE_OPENSSL
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-#include <openssl/x509.h>
-#include <openssl/x509_vfy.h>
-#endif
-
 using namespace NSROOT;
 
 SSLSessionFactory* SSLSessionFactory::m_instance = 0;
@@ -58,51 +50,80 @@
   SAFE_DELETE(m_instance);
 }
 
+#if HAVE_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+/* Cipher suites, https://www.openssl.org/docs/apps/ciphers.html */
+const char* const PREFERRED_CIPHERS = 
"HIGH:!aNULL:!kRSA:!SRP:!PSK:!CAMELLIA:!RC4:!MD5:!DSS";
+
 SSLSessionFactory::SSLSessionFactory()
 : m_enabled(false)
 , m_ctx(NULL)
 {
-#if HAVE_OPENSSL
-  OpenSSL_add_all_algorithms();
-  SSL_load_error_strings();
-  ERR_load_crypto_strings();
   if (SSL_library_init() < 0)
     DBG(DBG_ERROR, "%s: could not initialize the SSL library\n", __FUNCTION__);
   else
   {
-    if ((m_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
+    SSL_load_error_strings();
+    /* SSL_load_error_strings loads both libssl and libcrypto strings */
+    /* ERR_load_crypto_strings(); */
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    m_ctx = SSL_CTX_new(TLS_client_method());
+#else
+    m_ctx = SSL_CTX_new(SSLv23_client_method());
+#endif
+    if (m_ctx == NULL)
       DBG(DBG_ERROR, "%s: could not create the SSL context\n", __FUNCTION__);
     else
     {
-      m_enabled = true;
       SSL_CTX_set_verify(static_cast<SSL_CTX*>(m_ctx), SSL_VERIFY_NONE, 0);
+
+      /* Remove the most egregious. Because SSLv2 and SSLv3 have been removed,
+       * a TLSv1.0 handshake is used. The client accepts TLSv1.0 and above.
+       * An added benefit of TLS 1.0 and above are TLS extensions like Server
+       * Name Indicatior (SNI).
+       */
+      const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 
SSL_OP_NO_COMPRESSION;
+      (void)SSL_CTX_set_options(static_cast<SSL_CTX*>(m_ctx), flags);
+
+      /* Each cipher suite takes 2 bytes in the ClientHello, so advertising 
every
+       * cipher suite available at the client is going to cause a big 
ClientHello
+       * (or bigger then needed to get the job done).
+       * When using SSL_CTX_set_cipher_list or SSL_set_cipher_list with the 
string
+       * below you'll cut the number of cipher suites down to about 45.
+       */
+      if (SSL_CTX_set_cipher_list(static_cast<SSL_CTX*>(m_ctx), 
PREFERRED_CIPHERS) != 1)
+        DBG(DBG_ERROR, "%s: Set cipher list failed\n", __FUNCTION__);
+
+      /* The SSL trace callback is only used for verbose logging */
+      /* SSL_CTX_set_msg_callback(static_cast<SSL_CTX*>(m_ctx), ssl_trace); */
+
       DBG(DBG_INFO, "%s: SSL engine initialized\n", __FUNCTION__);
+      m_enabled = true;
     }
   }
-#else
-  DBG(DBG_INFO, "%s: SSL library disabled\n", __FUNCTION__);
-#endif
 }
 
 SSLSessionFactory::~SSLSessionFactory()
 {
-#if HAVE_OPENSSL
   if (m_ctx)
     SSL_CTX_free(static_cast<SSL_CTX*>(m_ctx));
   ERR_free_strings();
   EVP_cleanup();
   DBG(DBG_INFO, "%s: SSL resources destroyed\n", __FUNCTION__);
-#endif
 }
 
-SecureSocket* SSLSessionFactory::NewSocket(bool disableSSLv2 /*= true*/)
+SecureSocket* SSLSessionFactory::NewSocket()
 {
   if (m_enabled)
   {
-#if HAVE_OPENSSL
     SSL* ssl = SSL_new(static_cast<SSL_CTX*>(m_ctx));
-    if (disableSSLv2)
-      SSL_set_options(static_cast<SSL*>(ssl), SSL_OP_NO_SSLv2);
     /* SSL_MODE_AUTO_RETRY
      * With this option set, if the server suddenly wants a new handshake,
      * OpenSSL handles it in the background. Without this option, any read
@@ -111,9 +132,6 @@
      */
     SSL_set_mode(static_cast<SSL*>(ssl), SSL_MODE_AUTO_RETRY);
     return new SecureSocket(ssl);
-#else
-    (void)disableSSLv2;
-#endif
   }
   return NULL;
 }
@@ -129,24 +147,25 @@
 
 SecureSocket::~SecureSocket()
 {
-#if HAVE_OPENSSL
   Disconnect();
   SSL_free(static_cast<SSL*>(m_ssl));
-#endif
 }
 
 bool SecureSocket::Connect(const char* server, unsigned port, int rcvbuf)
 {
   m_ssl_error = 0;
-#if HAVE_OPENSSL
   if (m_connected)
     Disconnect();
-  // Connect the tcp socket to the server
+
+  /* Connect the tcp socket to the server */
   if (!TcpSocket::Connect(server, port, rcvbuf))
     return false;
-  // setup ssl
+
+  /* setup SSL */
   SSL_set_fd(static_cast<SSL*>(m_ssl), m_socket);
-  // try SSL handshake
+  SSL_set_tlsext_host_name(static_cast<SSL*>(m_ssl), server); /* fix SNI */
+
+  /* do SSL handshake */
   for (;;)
   {
     int r = SSL_connect(static_cast<SSL*>(m_ssl));
@@ -168,7 +187,7 @@
   }
   DBG(DBG_PROTO, "%s: SSL handshake initialized\n", __FUNCTION__);
   m_connected = true;
-  // check for a valid certificate
+  /* check for a valid certificate */
   std::string str("");
   if (!IsCertificateValid(str))
   {
@@ -177,17 +196,10 @@
   }
   DBG(DBG_PROTO, "%s: %s\n", __FUNCTION__, str.c_str());
   return true;
-#else
-  (void)server;
-  (void)port;
-  (void)rcvbuf;
-#endif
-  return false;
 }
 
 size_t SecureSocket::ReceiveData(void* buf, size_t n)
 {
-#if HAVE_OPENSSL
   if (m_connected && n > 0)
   {
     m_ssl_error = SSL_ERROR_NONE;
@@ -234,16 +246,11 @@
       break;
     }
   }
-#else
-  (void)buf;
-  (void)n;
-#endif
   return 0;
 }
 
 bool SecureSocket::SendData(const char* buf, size_t size)
 {
-#if HAVE_OPENSSL
   if (m_connected && size > 0)
   {
     m_ssl_error = SSL_ERROR_NONE;
@@ -270,16 +277,11 @@
       break;
     }
   }
-#else
-  (void)buf;
-  (void)size;
-#endif
   return false;
 }
 
 void SecureSocket::Disconnect()
 {
-#if HAVE_OPENSSL
   if (m_connected)
   {
     SSL_shutdown(static_cast<SSL*>(m_ssl));
@@ -291,7 +293,6 @@
     X509_free(static_cast<X509*>(m_cert));
     m_cert = NULL;
   }
-#endif
 }
 
 bool SecureSocket::IsValid() const
@@ -301,7 +302,6 @@
 
 bool SecureSocket::IsCertificateValid(std::string& str)
 {
-#if HAVE_OPENSSL
   if (m_cert)
     X509_free(static_cast<X509*>(m_cert));
   m_cert = SSL_get_peer_certificate(static_cast<SSL*>(m_ssl));
@@ -314,8 +314,75 @@
     str.assign(X509_NAME_oneline(name, buf, sizeof(buf) - 1));
     return true;
   }
+  return false;
+}
+
 #else
+
+SSLSessionFactory::SSLSessionFactory()
+: m_enabled(false)
+, m_ctx(NULL)
+{
+  DBG(DBG_INFO, "%s: SSL feature is disabled\n", __FUNCTION__);
+}
+
+SSLSessionFactory::~SSLSessionFactory()
+{
+}
+
+SecureSocket* SSLSessionFactory::NewSocket()
+{
+  return new SecureSocket(NULL);
+}
+
+SecureSocket::SecureSocket(void* ssl)
+: TcpSocket()
+, m_ssl(ssl)
+, m_cert(NULL)
+, m_connected(false)
+, m_ssl_error(0)
+{
+}
+
+SecureSocket::~SecureSocket()
+{
+}
+
+bool SecureSocket::Connect(const char* server, unsigned port, int rcvbuf)
+{
+  (void)server;
+  (void)port;
+  (void)rcvbuf;
+  return false;
+}
+
+size_t SecureSocket::ReceiveData(void* buf, size_t n)
+{
+  (void)buf;
+  (void)n;
+  return 0;
+}
+
+bool SecureSocket::SendData(const char* buf, size_t size)
+{
+  (void)buf;
+  (void)size;
+  return false;
+}
+
+void SecureSocket::Disconnect()
+{
+}
+
+bool SecureSocket::IsValid() const
+{
+  return m_connected;
+}
+
+bool SecureSocket::IsCertificateValid(std::string& str)
+{
   (void)str;
-#endif
   return false;
 }
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/private/securesocket.h 
new/noson-1.10.4/noson/src/private/securesocket.h
--- old/noson-1.8.2/noson/src/private/securesocket.h    2018-07-22 
23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/private/securesocket.h   2019-01-10 
10:19:26.000000000 +0100
@@ -36,7 +36,7 @@
     static SSLSessionFactory& Instance();
     static void Destroy();
     bool isEnabled() const { return m_enabled; }
-    SecureSocket* NewSocket(bool disableSSLv2 = true);
+    SecureSocket* NewSocket();
 
   private:
     SSLSessionFactory();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/private/xmldict.h 
new/noson-1.10.4/noson/src/private/xmldict.h
--- old/noson-1.8.2/noson/src/private/xmldict.h 2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/private/xmldict.h        2019-01-10 
10:19:26.000000000 +0100
@@ -88,8 +88,10 @@
     XMLNS* FindName(const char* name);
     const XMLNS* FindName(const char* name) const;
 
-  private:
     typedef std::list<XMLNS> XMLNSList;
+    XMLNSList List() { return m_names; }
+
+  private:
     XMLNSList m_names;
   };
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/renderingcontrol.cpp 
new/noson-1.10.4/noson/src/renderingcontrol.cpp
--- old/noson-1.8.2/noson/src/renderingcontrol.cpp      2018-07-22 
23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/renderingcontrol.cpp     2019-01-10 
10:19:26.000000000 +0100
@@ -142,6 +142,57 @@
   return false;
 }
 
+bool RenderingControl::GetTreble(int8_t* value)
+{
+  ElementList args;
+  args.push_back(ElementPtr(new Element("InstanceID", "0")));
+  ElementList vars = Request("GetTreble", args);
+  if (!vars.empty() && vars[0]->compare("GetTrebleResponse") == 0)
+  {
+    ElementList::const_iterator it = vars.FindKey("CurrentTreble");
+    if (it != vars.end())
+      return (string_to_int8((*it)->c_str(), value) == 0);
+  }
+  return false;
+}
+
+bool RenderingControl::SetTreble(int8_t value)
+{
+  ElementList args;
+  args.push_back(ElementPtr(new Element("InstanceID", "0")));
+  args.push_back(ElementPtr(new Element("DesiredTreble", 
std::to_string(value))));
+  ElementList vars = Request("SetTreble", args);
+  if (!vars.empty() && vars[0]->compare("SetTrebleResponse") == 0)
+    return true;
+  return false;
+}
+
+bool RenderingControl::GetBass(int8_t* value)
+{
+  ElementList args;
+  args.push_back(ElementPtr(new Element("InstanceID", "0")));
+  ElementList vars = Request("GetBass", args);
+  if (!vars.empty() && vars[0]->compare("GetBassResponse") == 0)
+  {
+    ElementList::const_iterator it = vars.FindKey("CurrentBass");
+    if (it != vars.end()) {
+      return (string_to_int8((*it)->c_str(), value) == 0);
+    }
+  }
+  return false;
+}
+
+bool RenderingControl::SetBass(int8_t value)
+{
+  ElementList args;
+  args.push_back(ElementPtr(new Element("InstanceID", "0")));
+  args.push_back(ElementPtr(new Element("DesiredBass", 
std::to_string(value))));
+  ElementList vars = Request("SetBass", args);
+  if (!vars.empty() && vars[0]->compare("SetBassResponse") == 0)
+    return true;
+  return false;
+}
+
 void RenderingControl::HandleEventMessage(EventMessagePtr msg)
 {
   if (!msg)
@@ -192,6 +243,16 @@
           if (string_to_int32((*++it).c_str(), &num) == 0)
             prop->NightMode = num;
         }
+        else if (*it == "Bass")
+        {
+          if (string_to_int32((*++it).c_str(), &num) == 0)
+            prop->Bass = num;
+        }
+        else if (*it == "Treble")
+        {
+          if (string_to_int32((*++it).c_str(), &num) == 0)
+            prop->Treble = num;
+        }
 
         ++it;
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/renderingcontrol.h 
new/noson-1.10.4/noson/src/renderingcontrol.h
--- old/noson-1.8.2/noson/src/renderingcontrol.h        2018-07-22 
23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/renderingcontrol.h       2019-01-10 
10:19:26.000000000 +0100
@@ -67,6 +67,14 @@
 
     bool SetNightmode(uint8_t value);
 
+    bool GetTreble(int8_t* value);
+
+    bool SetTreble(int8_t value);
+
+    bool GetBass(int8_t* value);
+
+    bool SetBass(int8_t value);
+
     // Implements EventSubscriber
     virtual void HandleEventMessage(EventMessagePtr msg);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/service.cpp 
new/noson-1.10.4/noson/src/service.cpp
--- old/noson-1.8.2/noson/src/service.cpp       2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/service.cpp      2019-01-10 10:19:26.000000000 
+0100
@@ -35,6 +35,17 @@
 
 using namespace NSROOT;
 
+namespace NSROOT
+{
+  void __traceServiceError(tinyxml2::XMLDocument& doc)
+  {
+    DBG(DBG_ERROR, "%s: invalid or not supported response\n", __FUNCTION__);
+    tinyxml2::XMLPrinter out;
+    doc.Accept(&out);
+    DBG(DBG_ERROR, "%s\n", out.CStr());
+  }
+}
+
 Service::Service(const std::string& serviceHost, unsigned servicePort)
 : m_host(serviceHost)
 , m_port(servicePort)
@@ -107,14 +118,22 @@
   }
   const tinyxml2::XMLElement* elem; // an element
   // Check for response: Envelope/Body/{respTag}
-  if (!(elem = rootdoc.RootElement()) || !XMLNS::NameEqual(elem->Name(), 
"Envelope") ||
-          !(elem = elem->FirstChildElement()) || 
!XMLNS::NameEqual(elem->Name(), "Body") ||
-          !(elem = elem->FirstChildElement()))
+  if (!(elem = rootdoc.RootElement()) || !XMLNS::NameEqual(elem->Name(), 
"Envelope"))
   {
-    DBG(DBG_ERROR, "%s: invalid or not supported response\n", __FUNCTION__);
-    tinyxml2::XMLPrinter out;
-    rootdoc.Accept(&out);
-    DBG(DBG_ERROR, "%s\n", out.CStr());
+    __traceServiceError(rootdoc);
+    SetFault(vars);
+    return vars;
+  }
+
+  // search the element 'Body'
+  elem = elem->FirstChildElement();
+  while (elem && !XMLNS::NameEqual(elem->Name(), "Body"))
+    elem = elem->NextSiblingElement(NULL);
+
+  if (!elem || !(elem = elem->FirstChildElement()))
+  {
+    __traceServiceError(rootdoc);
+    SetFault(vars);
     return vars;
   }
   vars.push_back(ElementPtr(new Element("TAG", 
XMLNS::LocalName(elem->Name()))));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/smapi.cpp 
new/noson-1.10.4/noson/src/smapi.cpp
--- old/noson-1.8.2/noson/src/smapi.cpp 2018-07-22 23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/smapi.cpp        2019-01-10 10:19:26.000000000 
+0100
@@ -47,7 +47,7 @@
   }
   XMLDict SMAPIDict = __initSMAPIDict();
 
-  void __dumpInvalidResponse(tinyxml2::XMLDocument& doc)
+  void __traceSMAPIError(tinyxml2::XMLDocument& doc)
   {
     DBG(DBG_ERROR, "%s: invalid or not supported response\n", __FUNCTION__);
     tinyxml2::XMLPrinter out;
@@ -275,7 +275,7 @@
   const tinyxml2::XMLElement* elem = rootdoc.RootElement();
   if (!elem || !(elem = elem->FirstChildElement(NULL)))
   {
-    __dumpInvalidResponse(rootdoc);
+    __traceSMAPIError(rootdoc);
     return false;
   }
   while (elem)
@@ -291,7 +291,7 @@
   
string_to_uint16(m_service->GetPolicy()->GetAttribut("PollInterval").c_str(), 
&poll);
   if (!m_authLinkTimeout)
     m_authLinkTimeout = new OS::CTimeout();
-  m_authLinkTimeout->Set(poll * 1000);
+  m_authLinkTimeout->Set((poll < 60 ? 60 : poll) * 1000);
   m_authLinkCode = vars.GetValue("linkCode");
   m_authLinkDeviceId = vars.GetValue("linkDeviceId");
   regUrl = vars.GetValue("regUrl");
@@ -322,21 +322,21 @@
   const tinyxml2::XMLElement* elem = rootdoc.RootElement();
   if (!elem || !(elem = elem->FirstChildElement(NULL)))
   {
-    __dumpInvalidResponse(rootdoc);
+    __traceSMAPIError(rootdoc);
     return false;
   }
   while (elem && !XMLNS::NameEqual(elem->Name(), "authorizeAccount"))
     elem = elem->NextSiblingElement(NULL);
   if (!elem || !(elem = elem->FirstChildElement(NULL)))
   {
-    __dumpInvalidResponse(rootdoc);
+    __traceSMAPIError(rootdoc);
     return false;
   }
   while (elem && !XMLNS::NameEqual(elem->Name(), "deviceLink"))
     elem = elem->NextSiblingElement(NULL);
   if (!elem || !(elem = elem->FirstChildElement(NULL)))
   {
-    __dumpInvalidResponse(rootdoc);
+    __traceSMAPIError(rootdoc);
     return false;
   }
   while (elem)
@@ -377,7 +377,11 @@
 
   const std::string& tag = resp.GetValue("TAG");
   if (tag == "Fault")
+  {
+    // show the feedback and return true to request a retry
+    DBG(DBG_INFO, "%s: %s\n", __FUNCTION__, 
m_fault.GetValue("faultstring").c_str());
     return true;
+  }
   else if (tag == "getDeviceAuthTokenResponse")
   {
     const std::string& data = resp.GetValue("getDeviceAuthTokenResult");
@@ -391,7 +395,7 @@
     const tinyxml2::XMLElement* elem = rootdoc.RootElement();
     if (!elem || !(elem = elem->FirstChildElement(NULL)))
     {
-      __dumpInvalidResponse(rootdoc);
+      __traceSMAPIError(rootdoc);
       return false;
     }
     while (elem)
@@ -421,6 +425,14 @@
   return false;
 }
 
+const std::string& SMAPI::GetFaultString() const
+{
+  OS::CLockGuard lock(*m_mutex);
+  if (m_fault.GetValue("TAG") == "Fault")
+    return m_fault.GetValue("faultstring");
+  return m_fault.GetValue("errorstring");
+}
+
 bool SMAPI::parsePresentationMap(const std::string& xml)
 {
   tinyxml2::XMLDocument rootdoc;
@@ -606,6 +618,7 @@
   if (rootdoc.Parse(data.c_str(), len) != tinyxml2::XML_SUCCESS)
   {
     DBG(DBG_ERROR, "%s: parse xml failed\n", __FUNCTION__);
+    SetFault(vars);
     return vars;
   }
   const tinyxml2::XMLElement* elem; // an element
@@ -613,17 +626,23 @@
 
   if (!(elem = rootdoc.RootElement()) || !XMLNS::NameEqual(elem->Name(), 
"Envelope"))
   {
-    __dumpInvalidResponse(rootdoc);
+    __traceSMAPIError(rootdoc);
+    SetFault(vars);
     return vars;
   }
   // learn declared namespaces in the element Envelope for translations
   XMLNames xmlnames;
   xmlnames.AddXMLNS(elem);
 
-  if (!(elem = elem->FirstChildElement()) || !XMLNS::NameEqual(elem->Name(), 
"Body") ||
-          !(elem = elem->FirstChildElement()))
+  // search the element 'Body'
+  elem = elem->FirstChildElement();
+  while (elem && !XMLNS::NameEqual(elem->Name(), "Body"))
+    elem = elem->NextSiblingElement(NULL);
+
+  if (!elem || !(elem = elem->FirstChildElement()))
   {
-    __dumpInvalidResponse(rootdoc);
+    __traceSMAPIError(rootdoc);
+    SetFault(vars);
     return vars;
   }
   vars.push_back(ElementPtr(new Element("TAG", 
XMLNS::LocalName(elem->Name()))));
@@ -664,14 +683,18 @@
     {
       if (elem->GetText())
       {
-        vars.push_back(ElementPtr(new 
Element(SMAPIDict.TranslateQName(xmlnames, elem->Name()), elem->GetText())));
+        // Some services supply malformed xml with undefined namespace and so 
translating qualified name will fail.
+        //vars.push_back(ElementPtr(new 
Element(SMAPIDict.TranslateQName(xmlnames, elem->Name()), elem->GetText())));
+        vars.push_back(ElementPtr(new Element(XMLNS::LocalName(elem->Name()), 
elem->GetText())));
         DBG(DBG_PROTO, "%s: %s = %s\n", __FUNCTION__, 
vars.back()->GetKey().c_str(), vars.back()->c_str());
       }
       else if (!elem->NoChildren())
       {
         tinyxml2::XMLPrinter out;
         elem->Accept(&out);
-        vars.push_back(ElementPtr(new 
Element(SMAPIDict.TranslateQName(xmlnames, elem->Name()), out.CStr())));
+        // Some services supply malformed xml with undefined namespace and so 
translating qualified name will fail.
+        //vars.push_back(ElementPtr(new 
Element(SMAPIDict.TranslateQName(xmlnames, elem->Name()), out.CStr())));
+        vars.push_back(ElementPtr(new Element(XMLNS::LocalName(elem->Name()), 
out.CStr())));
         DBG(DBG_PROTO, "%s: dump (%s)\n%s\n", __FUNCTION__, 
vars.back()->GetKey().c_str(), vars.back()->c_str());
       }
       elem = elem->NextSiblingElement(NULL);
@@ -723,16 +746,17 @@
       // Retry the request
       vars = DoCall(action, args);
     }
-    else if (XMLNS::NameEqual(str.c_str(), "Client.AuthTokenExpired") && 
!m_authTokenExpired)
-    {
-      m_authTokenExpired = true;
-      makeSoapHeader(); // refresh hearder
-    }
-    // handle others fault like Client.SessionIdInvalid, Client.LoginInvalid
     else if (!m_authTokenExpired)
     {
-      m_authTokenExpired = true;
-      makeSoapHeader(); // refresh header;
+      if (XMLNS::NameEqual(str.c_str(), "Client.AuthTokenExpired") ||
+              XMLNS::NameEqual(str.c_str(), "Client.LoginDisabled") ||
+              XMLNS::NameEqual(str.c_str(), "Client.LoginInvalid") ||
+              XMLNS::NameEqual(str.c_str(), "Client.LoginUnauthorized") ||
+              XMLNS::NameEqual(str.c_str(), "Client.SessionIdInvalid"))
+      {
+        m_authTokenExpired = true;
+        makeSoapHeader(); // refresh hearder
+      }
     }
   }
   return vars;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/smapi.h 
new/noson-1.10.4/noson/src/smapi.h
--- old/noson-1.8.2/noson/src/smapi.h   2018-07-22 23:32:32.000000000 +0200
+++ new/noson-1.10.4/noson/src/smapi.h  2019-01-10 10:19:26.000000000 +0100
@@ -118,6 +118,12 @@
      */
     bool GetDeviceAuthToken(SMOAKeyring::Data& auth);
 
+    /**
+     * Returns the message of fault
+     * @return the fault string
+     */
+    const std::string& GetFaultString() const;
+
   private:
     OS::CMutex* m_mutex;
     PlayerPtr m_player;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/smapimetadata.cpp 
new/noson-1.10.4/noson/src/smapimetadata.cpp
--- old/noson-1.8.2/noson/src/smapimetadata.cpp 2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/smapimetadata.cpp        2019-01-10 
10:19:26.000000000 +0100
@@ -56,8 +56,11 @@
   m_list.clear();
   m_startIndex = m_itemCount = m_totalCount = 0;
   m_root.assign(root);
-  if (m_service)
+  // don't parse an empty content
+  if (!xml.empty() && m_service)
     m_valid = ParseMessage(xml);
+  else
+    m_valid = false;
 }
 
 SMAPIItemList SMAPIMetadata::GetItems()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/sonosplayer.cpp 
new/noson-1.10.4/noson/src/sonosplayer.cpp
--- old/noson-1.8.2/noson/src/sonosplayer.cpp   2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/sonosplayer.cpp  2019-01-10 10:19:26.000000000 
+0100
@@ -394,6 +394,46 @@
   return false;
 }
 
+bool Player::GetBass(const std::string &uuid, int8_t* value)
+{
+  for (RCTable::const_iterator it = m_RCTable.begin(); it != m_RCTable.end(); 
++it)
+  {
+    if (it->uuid == uuid)
+      return it->renderingControl->GetBass(value);
+  }
+  return false;
+}
+
+bool Player::SetBass(const std::string &uuid, int8_t value)
+{
+  for (RCTable::const_iterator it = m_RCTable.begin(); it != m_RCTable.end(); 
++it)
+  {
+    if (it->uuid == uuid)
+      return it->renderingControl->SetBass(value);
+  }
+  return false;
+}
+
+bool Player::GetTreble(const std::string &uuid, int8_t* value)
+{
+  for (RCTable::const_iterator it = m_RCTable.begin(); it != m_RCTable.end(); 
++it)
+  {
+    if (it->uuid == uuid)
+      return it->renderingControl->GetTreble(value);
+  }
+  return false;
+}
+
+bool Player::SetTreble(const std::string &uuid, int8_t value)
+{
+  for (RCTable::const_iterator it = m_RCTable.begin(); it != m_RCTable.end(); 
++it)
+  {
+    if (it->uuid == uuid)
+      return it->renderingControl->SetTreble(value);
+  }
+  return false;
+}
+
 bool Player::SetCurrentURI(const DigitalItemPtr& item)
 {
   // Fix items from 'My radios' haven't required tag desc
@@ -768,3 +808,15 @@
   }
   return itemId;
 }
+
+Protocol_t Player::GetURIProtocol(const std::string& uri)
+{
+  size_t pos = uri.find_first_of(":");
+  if (pos == std::string::npos)
+    return Protocol_unknown;
+  std::string proto = uri.substr(0, pos);
+  int i = 0;
+  while (i < Protocol_unknown && proto != ProtocolTable[i])
+    ++i;
+  return static_cast<Protocol_t>(i);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/sonosplayer.h 
new/noson-1.10.4/noson/src/sonosplayer.h
--- old/noson-1.8.2/noson/src/sonosplayer.h     2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/sonosplayer.h    2019-01-10 10:19:26.000000000 
+0100
@@ -111,6 +111,12 @@
     bool GetNightmode(const std::string& uuid, uint8_t* value);
     bool SetNightmode(const std::string& uuid, uint8_t value);
 
+    bool GetBass(const std::string& uuid, int8_t* value);
+    bool SetBass(const std::string& uuid, int8_t value);
+
+    bool GetTreble(const std::string& uuid, int8_t* value);
+    bool SetTreble(const std::string& uuid, int8_t value);
+
     bool SetCurrentURI(const DigitalItemPtr& item);
     bool PlayStream(const std::string& streamURL, const std::string& title);
     bool PlayQueue(bool start);
@@ -158,6 +164,8 @@
 
     // Helpers
     std::string GetItemIdFromUriMetadata(const DigitalItemPtr& uriMetadata);
+    Protocol_t GetURIProtocol(const std::string& uri);
+
 
   private:
     bool m_valid;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/sonossystem.cpp 
new/noson-1.10.4/noson/src/sonossystem.cpp
--- old/noson-1.8.2/noson/src/sonossystem.cpp   2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/sonossystem.cpp  2019-01-10 10:19:26.000000000 
+0100
@@ -311,7 +311,7 @@
 
   // on first call we fill the container requesting sonos service
   if ((*ccPtr)++ == 0 && !LoadMSLogo(logos))
-    DBG(DBG_ERROR, "%s: cache for service images cannot be filled", 
__FUNCTION__);
+    DBG(DBG_ERROR, "%s: cache for service images cannot be filled\n", 
__FUNCTION__);
 
   const std::string& typeId = service->GetServiceType();
   for (ElementList::const_iterator it = logos.begin(); it != logos.end(); ++it)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/noson/src/sonostypes.h 
new/noson-1.10.4/noson/src/sonostypes.h
--- old/noson-1.8.2/noson/src/sonostypes.h      2018-07-22 23:32:32.000000000 
+0200
+++ new/noson-1.10.4/noson/src/sonostypes.h     2019-01-10 10:19:26.000000000 
+0100
@@ -184,6 +184,8 @@
     , MuteLF(0)
     , MuteRF(0)
     , NightMode(0)
+    , Treble(0)
+    , Bass(0)
     { }
 
     virtual ~RCSProperty() { }
@@ -195,6 +197,8 @@
     int MuteLF;
     int MuteRF;
     int NightMode;
+    int Treble;
+    int Bass;
   };
 
   class SRProperty
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/noson-1.8.2/test/src/test.cpp 
new/noson-1.10.4/test/src/test.cpp
--- old/noson-1.8.2/test/src/test.cpp   2018-07-22 23:32:32.000000000 +0200
+++ new/noson-1.10.4/test/src/test.cpp  2019-01-10 10:19:26.000000000 +0100
@@ -139,7 +139,8 @@
         while (it != bdir.end())
         {
           PRINT4("Item %d: [%d] [%s] [%s]\n", ++i, (*it)->IsItem(), 
(*it)->GetValue("dc:title").c_str(), (*it)->GetObjectID().c_str());
-          PRINT3("     %d: %s, %s\n", i, (*it)->GetValue("res").c_str(), 
(*it)->GetProperty("res")->GetAttribut("protocolInfo").c_str());
+          if ((*it)->GetProperty("res"))
+           PRINT3("     %d: %s, %s\n", i, (*it)->GetValue("res").c_str(), 
(*it)->GetProperty("res")->GetAttribut("protocolInfo").c_str());
           SONOS::DigitalItemPtr payload;
           if (SONOS::System::ExtractObjectFromFavorite(*it, payload))
             PRINT2("   F %d: %s\n", i, payload->GetObjectID().c_str());


Reply via email to