<commit_before>/* This source file must have a .cpp extension so that all C++ compilers
   recognize the extension without flags.  Borland does not know .cxx for
   example.  */
#ifndef __cplusplus
# error "A C compiler has been selected for C++."
#endif

/* Version number components: V=Version, R=Revision, P=Patch
   Version date components:   YYYY=Year, MM=Month,   DD=Day  */

#if defined(__COMO__)
# define COMPILER_ID "Comeau"
  /* __COMO_VERSION__ = VRR */
# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100)
# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100)

#elif defined(__INTEL_COMPILER) || defined(__ICC)
# define COMPILER_ID "Intel"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
  /* __INTEL_COMPILER = VRP */
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
# if defined(__INTEL_COMPILER_UPDATE)
#  define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
# else
#  define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER   % 10)
# endif
# if defined(__INTEL_COMPILER_BUILD_DATE)
  /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
#  define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
# endif
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif

#elif defined(__PATHCC__)
# define COMPILER_ID "PathScale"
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
# if defined(__PATHCC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
# endif

#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
# define COMPILER_ID "Embarcadero"
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__     & 0xFFFF)

#elif defined(__BORLANDC__)
# define COMPILER_ID "Borland"
  /* __BORLANDC__ = 0xVRR */
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)

#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
# define COMPILER_ID "Watcom"
   /* __WATCOMC__ = VVRR */
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif

#elif defined(__WATCOMC__)
# define COMPILER_ID "OpenWatcom"
   /* __WATCOMC__ = VVRP + 1100 */
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif

#elif defined(__SUNPRO_CC)
# define COMPILER_ID "SunPro"
# if __SUNPRO_CC >= 0x5100
   /* __SUNPRO_CC = 0xVRRP */
#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12)
#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF)
#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC    & 0xF)
# else
   /* __SUNPRO_CC = 0xVRP */
#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8)
#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF)
#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC    & 0xF)
# endif

#elif defined(__HP_aCC)
# define COMPILER_ID "HP"
  /* __HP_aCC = VVRRPP */
# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000)
# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__HP_aCC     % 100)

#elif defined(__DECCXX)
# define COMPILER_ID "Compaq"
  /* __DECCXX_VER = VVRRTPPPP */
# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000)
# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000  % 100)
# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER         % 10000)

#elif defined(__IBMCPP__) && defined(__COMPILER_VER__)
# define COMPILER_ID "zOS"
  /* __IBMCPP__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)

#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800
# define COMPILER_ID "XL"
  /* __IBMCPP__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)

#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800
# define COMPILER_ID "VisualAge"
  /* __IBMCPP__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)

#elif defined(__PGI)
# define COMPILER_ID "PGI"
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
# if defined(__PGIC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
# endif

#elif defined(_CRAYC)
# define COMPILER_ID "Cray"
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)

#elif defined(__TI_COMPILER_VERSION__)
# define COMPILER_ID "TI"
  /* __TI_COMPILER_VERSION__ = VVVRRRPPP */
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000   % 1000)
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__        % 1000)

#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version)
# define COMPILER_ID "Fujitsu"

#elif defined(__SCO_VERSION__)
# define COMPILER_ID "SCO"

#elif defined(__clang__) && defined(__apple_build_version__)
# define COMPILER_ID "AppleClang"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)

#elif defined(__clang__)
# define COMPILER_ID "Clang"
# if defined(_MSC_VER)
#  define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
   /* _MSC_VER = VVRR */
#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif

#elif defined(__GNUC__) || defined(__GNUG__)
# define COMPILER_ID "GNU"
# if defined(__GNUC__)
#  define COMPILER_VERSION_MAJOR DEC(__GNUC__)
# else
#  define COMPILER_VERSION_MAJOR DEC(__GNUG__)
# endif
# if defined(__GNUC_MINOR__)
#  define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
#  define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif

#elif defined(_MSC_VER)
# define COMPILER_ID "MSVC"
  /* _MSC_VER = VVRR */
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
# if defined(_MSC_FULL_VER)
#  if _MSC_VER >= 1400
    /* _MSC_FULL_VER = VVRRPPPPP */
#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
#  else
    /* _MSC_FULL_VER = VVRRPPPP */
#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
#  endif
# endif
# if defined(_MSC_BUILD)
#  define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
# endif

#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
# define COMPILER_ID "ADSP"
#if defined(__VISUALDSPVERSION__)
  /* __VISUALDSPVERSION__ = 0xVVRRPP00 */
# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8  & 0xFF)
#endif

#elif defined(__IAR_SYSTEMS_ICC__ ) || defined(__IAR_SYSTEMS_ICC)
# define COMPILER_ID "IAR"

#elif defined(__ARMCC_VERSION)
# define COMPILER_ID "ARMCC"
#if __ARMCC_VERSION >= 1000000
  /* __ARMCC_VERSION = VRRPPPP */
  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION     % 10000)
#else
  /* __ARMCC_VERSION = VRPPPP */
  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION    % 10000)
#endif

#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION)
# define COMPILER_ID "MIPSpro"
# if defined(_SGI_COMPILER_VERSION)
  /* _SGI_COMPILER_VERSION = VRP */
#  define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100)
#  define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10)
#  define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION    % 10)
# else
  /* _COMPILER_VERSION = VRP */
#  define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100)
#  define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10)
#  define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION    % 10)
# endif

/* These compilers are either not known or too old to define an
  identification macro.  Try to identify the platform and guess that
  it is the native compiler.  */
#elif defined(__sgi)
# define COMPILER_ID "MIPSpro"

#elif defined(__hpux) || defined(__hpua)
# define COMPILER_ID "HP"

#else /* unknown compiler */
# define COMPILER_ID ""
#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
#ifdef SIMULATE_ID
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
#endif

#ifdef __QNXNTO__
char const* qnxnto = "INFO" ":" "qnxnto[]";
#endif

#if defined(__CRAYXE) || defined(__CRAYXC)
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
#endif

#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)

/* Identify known platforms by name.  */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"

#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"

#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"

#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"

#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"

#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"

#elif defined(__NetBSD__) || defined(__NetBSD)
# define PLATFORM_ID "NetBSD"

#elif defined(__OpenBSD__) || defined(__OPENBSD)
# define PLATFORM_ID "OpenBSD"

#elif defined(__sun) || defined(sun)
# define PLATFORM_ID "SunOS"

#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
# define PLATFORM_ID "AIX"

#elif defined(__sgi) || defined(__sgi__) || defined(_SGI)
# define PLATFORM_ID "IRIX"

#elif defined(__hpux) || defined(__hpux__)
# define PLATFORM_ID "HP-UX"

#elif defined(__HAIKU__)
# define PLATFORM_ID "Haiku"

#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
# define PLATFORM_ID "BeOS"

#elif defined(__QNX__) || defined(__QNXNTO__)
# define PLATFORM_ID "QNX"

#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
# define PLATFORM_ID "Tru64"

#elif defined(__riscos) || defined(__riscos__)
# define PLATFORM_ID "RISCos"

#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
# define PLATFORM_ID "SINIX"

#elif defined(__UNIX_SV__)
# define PLATFORM_ID "UNIX_SV"

#elif defined(__bsdos__)
# define PLATFORM_ID "BSDOS"

#elif defined(_MPRAS) || defined(MPRAS)
# define PLATFORM_ID "MP-RAS"

#elif defined(__osf) || defined(__osf__)
# define PLATFORM_ID "OSF1"

#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
# define PLATFORM_ID "SCO_SV"

#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
# define PLATFORM_ID "ULTRIX"

#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
# define PLATFORM_ID "Xenix"

#elif defined(__WATCOMC__)
# if defined(__LINUX__)
#  define PLATFORM_ID "Linux"

# elif defined(__DOS__)
#  define PLATFORM_ID "DOS"

# elif defined(__OS2__)
#  define PLATFORM_ID "OS2"

# elif defined(__WINDOWS__)
#  define PLATFORM_ID "Windows3x"

# else /* unknown platform */
#  define PLATFORM_ID
# endif

#else /* unknown platform */
# define PLATFORM_ID

#endif

/* For windows compilers MSVC and Intel we can determine
   the architecture of the compiler being used.  This is because
   the compilers do not have flags that can change the architecture,
   but rather depend on which compiler is being used
*/
#if defined(_WIN32) && defined(_MSC_VER)
# if defined(_M_IA64)
#  define ARCHITECTURE_ID "IA64"

# elif defined(_M_X64) || defined(_M_AMD64)
#  define ARCHITECTURE_ID "x64"

# elif defined(_M_IX86)
#  define ARCHITECTURE_ID "X86"

# elif defined(_M_ARM)
#  if _M_ARM == 4
#   define ARCHITECTURE_ID "ARMV4I"
#  elif _M_ARM == 5
#   define ARCHITECTURE_ID "ARMV5I"
#  else
#   define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
#  endif

# elif defined(_M_MIPS)
#  define ARCHITECTURE_ID "MIPS"

# elif defined(_M_SH)
#  define ARCHITECTURE_ID "SHx"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#elif defined(__WATCOMC__)
# if defined(_M_I86)
#  define ARCHITECTURE_ID "I86"

# elif defined(_M_IX86)
#  define ARCHITECTURE_ID "X86"

# else /* unknown architecture */
#  define ARCHITECTURE_ID ""
# endif

#else
#  define ARCHITECTURE_ID
#endif

/* Convert integer to decimal digit literals.  */
#define DEC(n)                   \
  ('0' + (((n) / 10000000)%10)), \
  ('0' + (((n) / 1000000)%10)),  \
  ('0' + (((n) / 100000)%10)),   \
  ('0' + (((n) / 10000)%10)),    \
  ('0' + (((n) / 1000)%10)),     \
  ('0' + (((n) / 100)%10)),      \
  ('0' + (((n) / 10)%10)),       \
  ('0' +  ((n) % 10))

/* Convert integer to hex digit literals.  */
#define HEX(n)             \
  ('0' + ((n)>>28 & 0xF)), \
  ('0' + ((n)>>24 & 0xF)), \
  ('0' + ((n)>>20 & 0xF)), \
  ('0' + ((n)>>16 & 0xF)), \
  ('0' + ((n)>>12 & 0xF)), \
  ('0' + ((n)>>8  & 0xF)), \
  ('0' + ((n)>>4  & 0xF)), \
  ('0' + ((n)     & 0xF))

/* Construct a string literal encoding the version number components. */
#ifdef COMPILER_VERSION_MAJOR
char const info_version[] = {
  'I', 'N', 'F', 'O', ':',
  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
  COMPILER_VERSION_MAJOR,
# ifdef COMPILER_VERSION_MINOR
  '.', COMPILER_VERSION_MINOR,
#  ifdef COMPILER_VERSION_PATCH
   '.', COMPILER_VERSION_PATCH,
#   ifdef COMPILER_VERSION_TWEAK
    '.', COMPILER_VERSION_TWEAK,
#   endif
#  endif
# endif
  ']','\0'};
#endif

/* Construct a string literal encoding the version number components. */
#ifdef SIMULATE_VERSION_MAJOR
char const info_simulate_version[] = {
  'I', 'N', 'F', 'O', ':',
  's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
  SIMULATE_VERSION_MAJOR,
# ifdef SIMULATE_VERSION_MINOR
  '.', SIMULATE_VERSION_MINOR,
#  ifdef SIMULATE_VERSION_PATCH
   '.', SIMULATE_VERSION_PATCH,
#   ifdef SIMULATE_VERSION_TWEAK
    '.', SIMULATE_VERSION_TWEAK,
#   endif
#  endif
# endif
  ']','\0'};
#endif

/* Construct the string literal in pieces to prevent the source from
   getting matched.  Store it in a pointer rather than an array
   because some compilers will just produce instructions to fill the
   array rather than assigning a pointer to a static array.  */
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";

const char* info_language_dialect_default = "INFO" ":" "dialect_default["
#if __cplusplus > 201402L
  "17"
#elif __cplusplus >= 201402L
  "14"
#elif __cplusplus >= 201103L
  "11"
#else
  "98"
#endif
"]";

/*--------------------------------------------------------------------------*/

int main(int argc, char* argv[])
{
  int require = 0;
  require += info_compiler[argc];
  require += info_platform[argc];
#ifdef COMPILER_VERSION_MAJOR
  require += info_version[argc];
#endif
#ifdef SIMULATE_ID
  require += info_simulate[argc];
#endif
#ifdef SIMULATE_VERSION_MAJOR
  require += info_simulate_version[argc];
#endif
#if defined(__CRAYXE) || defined(__CRAYXC)
  require += info_cray[argc];
#endif
  require += info_language_dialect_default[argc];
  (void)argv;
  return require;
}
<commit_msg>forget CMake cpp file<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/app_host/binaries_installer.h"

#include "base/logging.h"
#include "base/threading/platform_thread.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "google_update/google_update_idl.h"

using base::win::ScopedBstr;
using base::win::ScopedComPtr;

namespace app_host {

namespace {

const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
const wchar_t kBinariesAppId[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
const int kInstallationPollingIntervalMs = 50;

HRESULT CreateInstalledApp(IAppBundle* app_bundle,
                           const wchar_t* app_guid,
                           IApp** app) {
  ScopedComPtr<IApp> temp_app;
  ScopedComPtr<IDispatch> idispatch;
  HRESULT hr = app_bundle->createInstalledApp(ScopedBstr(app_guid),
                                              idispatch.Receive());
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to configure App Bundle: " << hr;
  } else {
    hr = temp_app.QueryFrom(idispatch);
    if (FAILED(hr)) {
      LOG(ERROR) << "Unexpected error querying IApp from "
                 << "IAppBundle->createInstalledApp return value: " << hr;
    } else {
      *app = temp_app.Detach();
    }
  }

  return hr;
}

HRESULT GetCurrentState(IApp* app,
                        ICurrentState** current_state,
                        CurrentState* state_value) {
  HRESULT hr = S_OK;

  ScopedComPtr<ICurrentState> temp_current_state;
  {
    ScopedComPtr<IDispatch> idispatch;
    hr = app->get_currentState(idispatch.Receive());
    if (FAILED(hr)) {
      LOG(ERROR) << "Failed to get App Bundle state: " << hr;
    } else {
      hr = temp_current_state.QueryFrom(idispatch);
      if (FAILED(hr)) {
        LOG(ERROR) << "Unexpected error querying ICurrentState from "
                   << "IApp::get_currentState return value: " << hr;
      }
    }
  }

  if (SUCCEEDED(hr)) {
    LONG long_state_value;
    hr = temp_current_state->get_stateValue(&long_state_value);
    if (FAILED(hr))
      LOG(ERROR) << "Failed to get App Bundle state value: " << hr;
    *state_value = static_cast<CurrentState>(long_state_value);
    *current_state = temp_current_state.Detach();
  }

  return hr;
}

HRESULT CheckIsBusy(IAppBundle* app_bundle, bool* is_busy) {
  VARIANT_BOOL variant_is_busy = VARIANT_TRUE;
  HRESULT hr = app_bundle->isBusy(&variant_is_busy);
  if (FAILED(hr))
    LOG(ERROR) << "Failed to check app_bundle->isBusy: " << hr;
  else
    *is_busy = (variant_is_busy == VARIANT_TRUE);
  return hr;
}

HRESULT OnUpdateAvailable(IAppBundle* app_bundle) {
  // If the app bundle is busy we will just wait some more.
  bool is_busy = false;
  HRESULT hr = CheckIsBusy(app_bundle, &is_busy);
  if (SUCCEEDED(hr) && !is_busy) {
    hr = app_bundle->download();
    if (FAILED(hr))
      LOG(ERROR) << "Failed to initiate bundle download: " << hr;
  }
  return hr;
}

HRESULT OnReadyToInstall(IAppBundle* app_bundle) {
  // If the app bundle is busy we will just wait some more.
  bool is_busy = false;
  HRESULT hr = CheckIsBusy(app_bundle, &is_busy);
  if (SUCCEEDED(hr) && !is_busy) {
    hr = app_bundle->install();
    if (FAILED(hr))
      LOG(ERROR) << "Failed to initiate bundle install: " << hr;
  }
  return hr;
}

HRESULT OnError(ICurrentState* current_state) {
  LONG error_code;
  HRESULT hr = current_state->get_errorCode(&error_code);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to retrieve bundle error code: " << hr;
  } else {
    hr = error_code;

    ScopedBstr completion_message;
    HRESULT completion_message_hr =
      current_state->get_completionMessage(completion_message.Receive());
    if (FAILED(completion_message_hr)) {
      LOG(ERROR) << "Bundle installation failed with error " << hr
                 << ". Error message retrieval failed with error: "
                 << completion_message_hr;
    } else {
      LOG(ERROR) << "Bundle installation failed with error " << hr << ": "
                 << completion_message;
    }
  }

  return hr;
}

HRESULT CreateGoogleUpdate3(IGoogleUpdate3** update3) {
  ScopedComPtr<IGoogleUpdate3> temp_update3;
  HRESULT hr = temp_update3.CreateInstance(CLSID_GoogleUpdate3UserClass);
  if (SUCCEEDED(hr)) {
    *update3 = temp_update3.Detach();
  } else {
    // TODO(erikwright): Try in-proc to support running elevated? According
    // to update3_utils.cc (CreateGoogleUpdate3UserClass):
    // The primary reason for the LocalServer activation failing on Vista/Win7
    // is that COM does not look at HKCU registration when the code is running
    // elevated. We fall back to an in-proc mode. The in-proc mode is limited to
    // one install at a time, so we use it only as a backup mechanism.
    LOG(ERROR) << "Failed to instantiate GoogleUpdate3: " << hr;
  }
  return hr;
}

HRESULT CreateAppBundle(IGoogleUpdate3* update3, IAppBundle** app_bundle) {
  HRESULT hr = S_OK;

  ScopedComPtr<IAppBundle> temp_app_bundle;
  {
    ScopedComPtr<IDispatch> idispatch;
    hr = update3->createAppBundle(idispatch.Receive());
    if (FAILED(hr)) {
      LOG(ERROR) << "Failed to createAppBundle: " << hr;
    } else {
      hr = temp_app_bundle.QueryFrom(idispatch);
      if (FAILED(hr)) {
        LOG(ERROR) << "Unexpected error querying IAppBundle from "
                   << "IGoogleUpdate3->createAppBundle return value: " << hr;
      }
    }
  }

  if (SUCCEEDED(hr)) {
    hr = temp_app_bundle->initialize();
    if (FAILED(hr))
      LOG(ERROR) << "Failed to initialize App Bundle: " << hr;
    else
      *app_bundle = temp_app_bundle.Detach();
  }

  return hr;
}

HRESULT GetAppHostApValue(IGoogleUpdate3* update3, BSTR* ap_value) {
  ScopedComPtr<IAppBundle> app_bundle;
  HRESULT hr = CreateAppBundle(update3, app_bundle.Receive());
  if (SUCCEEDED(hr)) {
    ScopedComPtr<IApp> app;
    hr = CreateInstalledApp(app_bundle, kAppHostAppId, app.Receive());
    if (SUCCEEDED(hr)) {
      hr = app->get_ap(ap_value);
      if (FAILED(hr))
        LOG(ERROR) << "Failed to get the App Host AP value.";
    }
  }

  return hr;
}

HRESULT SelectBinariesApValue(IGoogleUpdate3* update3, BSTR* ap_value) {
  HRESULT hr = GetAppHostApValue(update3, ap_value);
  if (FAILED(hr)) {
    // TODO(erikwright): distinguish between AppHost not installed and an
    // error in GetAppHostApValue.
    // TODO(erikwright): Use stable by default when App Host support is in
    // stable.
    ScopedBstr temp_ap_value;
    if (NULL == temp_ap_value.Allocate(L"2.0-dev-multi-apphost")) {
      LOG(ERROR) << "Unexpected error in ScopedBstr::Allocate.";
      hr = E_FAIL;
    } else {
      *ap_value = temp_ap_value.Release();
      hr = S_OK;
    }
  }

  return hr;
}

HRESULT CreateBinariesIApp(IAppBundle* app_bundle, BSTR ap, IApp** app) {
  HRESULT hr = S_OK;

  ScopedComPtr<IApp> temp_app;
  {
    ScopedComPtr<IDispatch> idispatch;
    hr = app_bundle->createApp(ScopedBstr(kBinariesAppId), idispatch.Receive());
    if (FAILED(hr)) {
      LOG(ERROR) << "Failed to configure App Bundle: " << hr;
    } else {
      hr = temp_app.QueryFrom(idispatch);
      if (FAILED(hr)) {
        LOG(ERROR) << "Unexpected error querying IApp from "
                   << "IAppBundle->createApp return value: " << hr;
      }
    }
  }

  if (SUCCEEDED(hr)) {
    hr = temp_app->put_isEulaAccepted(VARIANT_TRUE);
    if (FAILED(hr))
      LOG(ERROR) << "Failed to set 'EULA Accepted': " << hr;
  }

  if (SUCCEEDED(hr)) {
    hr = temp_app->put_ap(ap);
    if (FAILED(hr))
      LOG(ERROR) << "Failed to set AP value: " << hr;
  }

  if (SUCCEEDED(hr))
    *app = temp_app.Detach();

  return hr;
}

bool CheckIfDone(IAppBundle* app_bundle, IApp* app, HRESULT* hr) {
  ScopedComPtr<ICurrentState> current_state;
  CurrentState state_value;
  *hr = GetCurrentState(app, current_state.Receive(), &state_value);

  bool complete = false;

  if (SUCCEEDED(hr)) {
    switch (state_value) {
      case STATE_WAITING_TO_CHECK_FOR_UPDATE:
      case STATE_CHECKING_FOR_UPDATE:
      case STATE_WAITING_TO_DOWNLOAD:
      case STATE_RETRYING_DOWNLOAD:
      case STATE_DOWNLOADING:
      case STATE_WAITING_TO_INSTALL:
      case STATE_INSTALLING:
      case STATE_DOWNLOAD_COMPLETE:
      case STATE_EXTRACTING:
      case STATE_APPLYING_DIFFERENTIAL_PATCH:
        // These states will all transition on their own.
        break;

      case STATE_UPDATE_AVAILABLE:
        *hr = OnUpdateAvailable(app_bundle);
        break;

      case STATE_READY_TO_INSTALL:
        *hr = OnReadyToInstall(app_bundle);
        break;

      case STATE_NO_UPDATE:
        LOG(INFO) << "Google Update reports that the binaries are already "
                  << "installed and up-to-date.";
        complete = true;
        break;

      case STATE_INSTALL_COMPLETE:
        complete = true;
        break;

      case STATE_ERROR:
        *hr = OnError(current_state);
        break;

      case STATE_INIT:
      case STATE_PAUSED:
      default:
        LOG(ERROR) << "Unexpected bundle state: " << state_value << ".";
        *hr = E_FAIL;
        break;
    }
  }

  return FAILED(*hr) || complete;
}

}  // namespace

// Attempts to install the Chrome Binaries using the IGoogleUpdate3 interface.
// Blocks until the installation process completes, without message pumping.
HRESULT InstallBinaries() {
  base::win::ScopedCOMInitializer initialize_com;

  HRESULT hr = S_OK;
  if (!initialize_com.succeeded()) {
    LOG(ERROR) << "COM initialization failed";
    hr = E_FAIL;
  }

  ScopedComPtr<IGoogleUpdate3> update3;
  if (SUCCEEDED(hr)) {
    hr = CreateGoogleUpdate3(update3.Receive());
  }

  ScopedBstr ap_value;
  if (SUCCEEDED(hr)) {
    hr = SelectBinariesApValue(update3, ap_value.Receive());
  }

  ScopedComPtr<IAppBundle> app_bundle;
  if (SUCCEEDED(hr)) {
    hr = CreateAppBundle(update3, app_bundle.Receive());
  }

  ScopedComPtr<IApp> app;
  if (SUCCEEDED(hr)) {
    hr = CreateBinariesIApp(app_bundle, ap_value, app.Receive());
  }

  if (SUCCEEDED(hr)) {
    hr = app_bundle->checkForUpdate();
    if (FAILED(hr)) {
      LOG(ERROR) << "Failed to initiate update check: " << hr;
    }
  }

  if (SUCCEEDED(hr)) {
    // We rely upon Omaha to eventually time out and transition to a failure
    // state.
    while (!CheckIfDone(app_bundle, app, &hr)) {
      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
          kInstallationPollingIntervalMs));
    }
  }

  return hr;
}

}  // namespace app_host
<commit_msg>Mostly cleanup.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/app_host/binaries_installer.h"

#include "base/logging.h"
#include "base/threading/platform_thread.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "google_update/google_update_idl.h"

namespace app_host {

// Helpers --------------------------------------------------------------------

namespace {

const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
const wchar_t kBinariesAppId[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
const int kInstallationPollingIntervalMs = 50;

HRESULT CreateInstalledApp(IAppBundle* app_bundle,
                           const wchar_t* app_guid,
                           IApp** app) {
  base::win::ScopedComPtr<IDispatch> idispatch;
  HRESULT hr = app_bundle->createInstalledApp(base::win::ScopedBstr(app_guid),
                                              idispatch.Receive());
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to configure App Bundle: " << hr;
    return hr;
  }

  base::win::ScopedComPtr<IApp> temp_app;
  hr = temp_app.QueryFrom(idispatch);
  if (FAILED(hr)) {
    LOG(ERROR) << "Unexpected error querying IApp from "
               << "IAppBundle->createInstalledApp return value: " << hr;
  } else {
    *app = temp_app.Detach();
  }
  return hr;
}

HRESULT GetAppHostApValue(IGoogleUpdate3* update3,
                          IAppBundle* app_bundle,
                          BSTR* ap_value) {
  base::win::ScopedComPtr<IApp> app;
  HRESULT hr = CreateInstalledApp(app_bundle, kAppHostAppId, app.Receive());
  if (FAILED(hr))
    return hr;

  hr = app->get_ap(ap_value);
  if (FAILED(hr))
    LOG(ERROR) << "Failed to get the App Host AP value.";
  return hr;
}

HRESULT GetCurrentState(IApp* app,
                        ICurrentState** current_state,
                        CurrentState* state_value) {
  base::win::ScopedComPtr<IDispatch> idispatch;
  HRESULT hr = app->get_currentState(idispatch.Receive());
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to get App Bundle state: " << hr;
    return hr;
  }

  base::win::ScopedComPtr<ICurrentState> temp_current_state;
  hr = temp_current_state.QueryFrom(idispatch);
  if (FAILED(hr)) {
    LOG(ERROR) << "Unexpected error querying ICurrentState from "
               << "IApp::get_currentState return value: " << hr;
    return hr;
  }

  LONG long_state_value;
  hr = temp_current_state->get_stateValue(&long_state_value);
  if (SUCCEEDED(hr)) {
    *state_value = static_cast<CurrentState>(long_state_value);
    *current_state = temp_current_state.Detach();
  } else {
    LOG(ERROR) << "Failed to get App Bundle state value: " << hr;
  }
  return hr;
}

bool CheckIsBusy(IAppBundle* app_bundle, HRESULT* hr) {
  VARIANT_BOOL variant_is_busy = VARIANT_TRUE;
  *hr = app_bundle->isBusy(&variant_is_busy);
  if (FAILED(*hr))
    LOG(ERROR) << "Failed to check app_bundle->isBusy: " << *hr;
  return (variant_is_busy == VARIANT_TRUE);
}

void OnUpdateAvailable(IAppBundle* app_bundle, HRESULT* hr) {
  // If the app bundle is busy we will just wait some more.
  if (CheckIsBusy(app_bundle, hr) || FAILED(*hr))
    return;
  *hr = app_bundle->download();
  if (FAILED(*hr))
    LOG(ERROR) << "Failed to initiate bundle download: " << *hr;
}

void OnReadyToInstall(IAppBundle* app_bundle, HRESULT* hr) {
  // If the app bundle is busy we will just wait some more.
  if (CheckIsBusy(app_bundle, hr) || FAILED(*hr))
    return;
  *hr = app_bundle->install();
  if (FAILED(*hr))
    LOG(ERROR) << "Failed to initiate bundle install: " << *hr;
}

HRESULT OnError(ICurrentState* current_state) {
  LONG error_code;
  HRESULT hr = current_state->get_errorCode(&error_code);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to retrieve bundle error code: " << hr;
    return hr;
  }

  base::win::ScopedBstr completion_message;
  HRESULT completion_message_hr =
    current_state->get_completionMessage(completion_message.Receive());
  if (FAILED(completion_message_hr)) {
    LOG(ERROR) << "Bundle installation failed with error " << error_code
               << ". Error message retrieval failed with error: "
               << completion_message_hr;
  } else {
    LOG(ERROR) << "Bundle installation failed with error " << error_code << ": "
               << completion_message;
  }
  return error_code;
}

HRESULT CreateGoogleUpdate3(IGoogleUpdate3** update3) {
  base::win::ScopedComPtr<IGoogleUpdate3> temp_update3;
  HRESULT hr = temp_update3.CreateInstance(CLSID_GoogleUpdate3UserClass);
  if (SUCCEEDED(hr)) {
    *update3 = temp_update3.Detach();
  } else {
    // TODO(erikwright): Try in-proc to support running elevated? According
    // to update3_utils.cc (CreateGoogleUpdate3UserClass):
    // The primary reason for the LocalServer activation failing on Vista/Win7
    // is that COM does not look at HKCU registration when the code is running
    // elevated. We fall back to an in-proc mode. The in-proc mode is limited to
    // one install at a time, so we use it only as a backup mechanism.
    LOG(ERROR) << "Failed to instantiate GoogleUpdate3: " << hr;
  }
  return hr;
}

HRESULT CreateAppBundle(IGoogleUpdate3* update3, IAppBundle** app_bundle) {
  base::win::ScopedComPtr<IDispatch> idispatch;
  HRESULT hr = update3->createAppBundle(idispatch.Receive());
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to createAppBundle: " << hr;
    return hr;
  }

  base::win::ScopedComPtr<IAppBundle> temp_app_bundle;
  hr = temp_app_bundle.QueryFrom(idispatch);
  if (FAILED(hr)) {
    LOG(ERROR) << "Unexpected error querying IAppBundle from "
               << "IGoogleUpdate3->createAppBundle return value: " << hr;
    return hr;
  }

  hr = temp_app_bundle->initialize();
  if (FAILED(hr))
    LOG(ERROR) << "Failed to initialize App Bundle: " << hr;
  else
    *app_bundle = temp_app_bundle.Detach();
  return hr;
}

HRESULT SelectBinariesApValue(IGoogleUpdate3* update3,
                              IAppBundle* app_bundle,
                              BSTR* ap_value) {
  HRESULT hr = GetAppHostApValue(update3, app_bundle, ap_value);
  if (SUCCEEDED(hr))
    return hr;

  // TODO(erikwright): distinguish between AppHost not installed and an
  // error in GetAppHostApValue.
  // TODO(erikwright): Use stable by default when App Host support is in
  // stable.
  base::win::ScopedBstr temp_ap_value;
  if (temp_ap_value.Allocate(L"2.0-dev-multi-apphost") == NULL) {
    LOG(ERROR) << "Unexpected error in ScopedBstr::Allocate.";
    return E_FAIL;
  }
  *ap_value = temp_ap_value.Release();
  return S_OK;
}

HRESULT CreateBinariesIApp(IAppBundle* app_bundle, BSTR ap, IApp** app) {
  base::win::ScopedComPtr<IDispatch> idispatch;
  HRESULT hr = app_bundle->createApp(base::win::ScopedBstr(kBinariesAppId),
                                     idispatch.Receive());
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to configure App Bundle: " << hr;
    return hr;
  }

  base::win::ScopedComPtr<IApp> temp_app;
  hr = temp_app.QueryFrom(idispatch);
  if (FAILED(hr)) {
    LOG(ERROR) << "Unexpected error querying IApp from "
               << "IAppBundle->createApp return value: " << hr;
    return hr;
  }

  hr = temp_app->put_isEulaAccepted(VARIANT_TRUE);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to set 'EULA Accepted': " << hr;
    return hr;
  }

  hr = temp_app->put_ap(ap);
  if (FAILED(hr))
    LOG(ERROR) << "Failed to set AP value: " << hr;
  else
    *app = temp_app.Detach();
  return hr;
}

bool CheckIfDone(IAppBundle* app_bundle, IApp* app, HRESULT* hr) {
  base::win::ScopedComPtr<ICurrentState> current_state;
  CurrentState state_value;
  *hr = GetCurrentState(app, current_state.Receive(), &state_value);
  if (FAILED(*hr))
    return true;

  switch (state_value) {
    case STATE_WAITING_TO_CHECK_FOR_UPDATE:
    case STATE_CHECKING_FOR_UPDATE:
    case STATE_WAITING_TO_DOWNLOAD:
    case STATE_RETRYING_DOWNLOAD:
    case STATE_DOWNLOADING:
    case STATE_WAITING_TO_INSTALL:
    case STATE_INSTALLING:
    case STATE_DOWNLOAD_COMPLETE:
    case STATE_EXTRACTING:
    case STATE_APPLYING_DIFFERENTIAL_PATCH:
      // These states will all transition on their own.
      return false;

    case STATE_UPDATE_AVAILABLE:
      OnUpdateAvailable(app_bundle, hr);
      return FAILED(*hr);

    case STATE_READY_TO_INSTALL:
      OnReadyToInstall(app_bundle, hr);
      return FAILED(*hr);

    case STATE_NO_UPDATE:
      LOG(INFO) << "Google Update reports that the binaries are already "
                << "installed and up-to-date.";
      return true;

    case STATE_INSTALL_COMPLETE:
      return true;

    case STATE_ERROR:
      *hr = OnError(current_state);
      return FAILED(*hr);

    case STATE_INIT:
    case STATE_PAUSED:
    default:
      LOG(ERROR) << "Unexpected bundle state: " << state_value << ".";
      *hr = E_FAIL;
      return true;
  }
}

}  // namespace

// Globals --------------------------------------------------------------------

HRESULT InstallBinaries() {
  base::win::ScopedCOMInitializer initialize_com;
  if (!initialize_com.succeeded()) {
    LOG(ERROR) << "COM initialization failed";
    return E_FAIL;
  }

  base::win::ScopedComPtr<IGoogleUpdate3> update3;
  HRESULT hr = CreateGoogleUpdate3(update3.Receive());
  if (FAILED(hr))
    return hr;

  base::win::ScopedComPtr<IAppBundle> app_bundle;
  hr = CreateAppBundle(update3, app_bundle.Receive());
  if (FAILED(hr))
    return hr;

  base::win::ScopedBstr ap_value;
  hr = SelectBinariesApValue(update3, app_bundle, ap_value.Receive());
  if (FAILED(hr))
    return hr;

  base::win::ScopedComPtr<IApp> app;
  hr = CreateBinariesIApp(app_bundle, ap_value, app.Receive());
  if (FAILED(hr))
    return hr;

  hr = app_bundle->checkForUpdate();
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to initiate update check: " << hr;
    return hr;
  }

  // We rely upon Omaha to eventually time out and transition to a failure
  // state.
  while (!CheckIfDone(app_bundle, app, &hr)) {
    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
        kInstallationPollingIntervalMs));
  }
  return hr;
}

}  // namespace app_host
<|endoftext|>


<commit_before>/*
 FILNAMN: 		server.cc
 PROGRAMMERARE:	hanel742, eriek984, jened502, tobgr602, niker917, davha227
 SKAPAD DATUM:	2013-11-18
 BESKRIVNING:
 */

#include "thread.h"

using namespace std;

// ---------------------------------------
// Helper functions

void Thread::handleMessage(QString inData){
    int i;

    QString from;
    i = inData.indexOf(compare);
    from = inData.left(i);
    string stdFrom = from.toStdString();
    inData = inData.mid(i+1);

    QString to;
    i = inData.indexOf(compare);
    to = inData.left(i);
    string stdTo = to.toStdString();
    inData = inData.mid(i+1);

    QString contents;
    i = inData.indexOf(compare);
    contents = inData.left(i);
    string stdContents = contents.toStdString();
    inData = inData.mid(i+1);

    Message message(stdContents, stdFrom, stdTo);
    userPointer->sendMessage(message);
}

// ----------------------

void Thread::handleInitiate(string stdInData) {
    try
    {
        userPointer = masterPointer->createUser(stdInData);
        userPointer->setThread(this);
        requestStruct();
        userPointer->sendHistory();
    }
    catch (...)
    {
        reinitiate();
    }
}

// ----------------------

void Thread::handleStructure() {
    vector<string> structure = userPointer->getStruct();

    QByteArray sendData;
    sendData += "/structure";
    sendData += compare;

    unsigned int i;

    for (i = 0; i+1 < structure.size() ; i++) {
        sendData += QString::fromStdString(structure.at(i));
        sendData += compare;
    }
    i++;
    sendData += QString::fromStdString(structure.at(i));
    sendData += breaker;

    TcpSocket->write(sendData);

}

// ---------------------------------------

Thread::Thread(qintptr ID, Master* masterptr, QObject *parent) : QThread(parent)
{
    masterPointer=masterptr;
    this->socketDescriptor = ID;
    compare += 0x1F;
    breaker += 0x1E;
}

// ---------------------------------------

void Thread::run()
{
    //thread starts here
    cout << socketDescriptor << " starting thread"<<endl;
    TcpSocket = new QTcpSocket();

    if(!TcpSocket->setSocketDescriptor(this->socketDescriptor))
    {
        emit error(TcpSocket->error());
        return;
    }

    connect(TcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead()),Qt::DirectConnection);

    connect(TcpSocket,SIGNAL(disconnected()),this,SLOT(disconnected()),Qt::DirectConnection);
    cout << socketDescriptor << " client connected"<<endl;

    //creates a messageloop
    exec();

}

// ---------------------------------------

// ---------------------------

void Thread::readyRead()
{

    QByteArray Data = TcpSocket->readAll();

    int i;
    int n;

    QString commandName;
    QString inData = Data;

    QString rest;

    while ( !inData.isEmpty() ) {

        i = inData.indexOf(compare);

        commandName = inData.left(i);
        inData = inData.mid(i+1);

        n = inData.indexOf(breaker);

        if (inData.size() < 2) {

            break;
        }
        rest = inData.mid(n+1);

        inData = inData.left(n);

        QString temp = inData;
        string stdInData = temp.toStdString();

        // Check which command that's supposed to run
        if (commandName == "/initiate") {
            handleInitiate(stdInData);
        }

        else if (commandName == "/message") {
            handleMessage(inData);
        }

        else if ( commandName == "/structure" ) {
            handleStructure();
        }

        else {
            qDebug() << commandName;
            TcpSocket->write("Ej giltigt kommando");
            cout << socketDescriptor << "Data in: "<< stdInData<<endl;
        }

        inData = rest;

    }
}

// ---------------------------------------

void Thread::disconnected()
{
    cout << socketDescriptor << "Disconnected"<<endl;
    try {
        masterPointer->removeUser(userPointer->getName());
    } catch (...) {

    }

    TcpSocket->deleteLater();
    //exits the thread
    exit(0);
}

// -----------------------------------------

//svarar klienten
void Thread::sendMessage(Message messageObject){
    QByteArray array = "/message";
    array += 0x1F; //unit separator
    array += QString::fromStdString(messageObject.getFrom());
    array += 0x1F;
    array += QString::fromStdString(messageObject.getTo());
    array += 0x1F;
    array += QString::fromStdString(messageObject.getMessage());
    array += 0x1F;
    array += QString::fromStdString(messageObject.getServerTime());
    array += 0x1E;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);

}

// -----------------------------------------

void Thread::sendHistory(){
    QByteArray array = "/history";
    array += 0x1F; //unit separator

    for (unsigned int i=0; i < userPointer->getParentRoom()->log.size(); i++)
    {

        Message tempMessage = userPointer->getParentRoom()->log.at(i);

        array += QString::fromStdString(tempMessage.getFrom());
        array += 0x1F; //unit separator
        array += QString::fromStdString(tempMessage.getTo());
        array += 0x1F; //unit separator
        array += QString::fromStdString(tempMessage.getMessage());
        array += 0x1F; //unit separator
        array += QString::fromStdString(tempMessage.getServerTime());
        array += 0x1E; //unit separator
    }
    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);

}

// -----------------------------------------

void Thread::reinitiate(){
    QByteArray array = "/reinitiate";
    array += 0x1E; //unit separator

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

// -----------------------------------------

void Thread::requestStruct() {
    QByteArray array = "/structure";
    array += 0x1E;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}
<commit_msg>Worked on sending several commands at start, fixed a couple, but structure crashes.<commit_after>/*
 FILNAMN: 		server.cc
 PROGRAMMERARE:	hanel742, eriek984, jened502, tobgr602, niker917, davha227
 SKAPAD DATUM:	2013-11-18
 BESKRIVNING:
 */

#include "thread.h"

using namespace std;

// ---------------------------------------
// Helper functions

void Thread::handleMessage(QString inData){
    int i;

    QString from;
    i = inData.indexOf(compare);
    from = inData.left(i);
    string stdFrom = from.toStdString();
    inData = inData.mid(i+1);

    QString to;
    i = inData.indexOf(compare);
    to = inData.left(i);
    string stdTo = to.toStdString();
    inData = inData.mid(i+1);

    QString contents;
    i = inData.indexOf(compare);
    contents = inData.left(i);
    string stdContents = contents.toStdString();
    inData = inData.mid(i+1);

    Message message(stdContents, stdFrom, stdTo);
    userPointer->sendMessage(message);
}

// ----------------------

void Thread::handleInitiate(string stdInData) {
    try
    {
        userPointer = masterPointer->createUser(stdInData);
        userPointer->setThread(this);
        requestStruct();
        userPointer->sendHistory();
    }
    catch (...)
    {
        reinitiate();
    }
}

// ----------------------

void Thread::handleStructure() {
    vector<string> structure = userPointer->getStruct();

    QByteArray sendData;
    sendData += "/structure";
    sendData += compare;

    unsigned int i;

    for (i = 0; i+1 < structure.size() ; i++) {
        sendData += QString::fromStdString(structure.at(i));
        sendData += compare;
    }
    i++;
    sendData += QString::fromStdString(structure.at(i));
    sendData += breaker;

    TcpSocket->write(sendData);

}

// ---------------------------------------

Thread::Thread(qintptr ID, Master* masterptr, QObject *parent) : QThread(parent)
{
    masterPointer=masterptr;
    this->socketDescriptor = ID;
    compare += 0x1F;
    breaker += 0x1E;
}

// ---------------------------------------

void Thread::run()
{
    //thread starts here
    cout << socketDescriptor << " starting thread"<<endl;
    TcpSocket = new QTcpSocket();

    if(!TcpSocket->setSocketDescriptor(this->socketDescriptor))
    {
        emit error(TcpSocket->error());
        return;
    }

    connect(TcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead()),Qt::DirectConnection);

    connect(TcpSocket,SIGNAL(disconnected()),this,SLOT(disconnected()),Qt::DirectConnection);
    cout << socketDescriptor << " client connected"<<endl;

    //creates a messageloop
    exec();

}

// ---------------------------------------

// ---------------------------

void Thread::readyRead()
{

    QByteArray Data = TcpSocket->readAll();

    int i;
    int n;

    QString commandName;
    QString inData = Data;

    QString rest;

    while ( !inData.isEmpty() ) {

        i = inData.indexOf(compare);

        commandName = inData.left(i);
        inData = inData.mid(i+1);

        n = inData.indexOf(breaker);

        if (inData.size() < 2) {

            break;
        }
        rest = inData.mid(n+1);

        inData = inData.left(n);

        QString temp = inData;
        string stdInData = temp.toStdString();

        // Check which command that's supposed to run
        if (commandName == "/initiate") {
            cout <<"Initiate. " << stdInData << endl;
            handleInitiate(stdInData);
        }

        else if (commandName == "/message") {
            qDebug() << "/message thread";
            handleMessage(inData);
        }

        else if ( commandName == "/structure" ) {
            //handleStructure();
            cout << "Handled structure, but not really" << endl;
        }

        else {
            cout << "Ej giltigt kommando" << commandName.toStdString() << endl;
            TcpSocket->write("Ej giltigt kommando");
            cout << socketDescriptor << "Data in: "<< stdInData<<endl;
        }

        inData = rest;

    }
}

// ---------------------------------------

void Thread::disconnected()
{
    cout << socketDescriptor << "Disconnected"<<endl;
    try {
        masterPointer->removeUser(userPointer->getName());
    } catch (...) {

    }

    TcpSocket->deleteLater();
    //exits the thread
    exit(0);
}

// -----------------------------------------

//svarar klienten
void Thread::sendMessage(Message messageObject){
    QByteArray array = "/message";
    array += 0x1F; //unit separator
    array += QString::fromStdString(messageObject.getFrom());
    array += 0x1F;
    array += QString::fromStdString(messageObject.getTo());
    array += 0x1F;
    array += QString::fromStdString(messageObject.getMessage());
    array += 0x1F;
    array += QString::fromStdString(messageObject.getServerTime());
    array += 0x1E;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);

}

// -----------------------------------------

void Thread::sendHistory(){
    QByteArray array = "/history";
    array += 0x1F; //unit separator
    unsigned int logSize = userPointer->getParentRoom()->log.size();

    for (unsigned int i = 0; i < logSize; i++){

        Message tempMessage = userPointer->getParentRoom()->log.at(i);

        array += QString::fromStdString(tempMessage.getFrom());
        array += 0x1F; //unit separator
        array += QString::fromStdString(tempMessage.getTo());
        array += 0x1F; //unit separator
        array += QString::fromStdString(tempMessage.getMessage());
        array += 0x1F; //unit separator
        array += QString::fromStdString(tempMessage.getServerTime());
        if ( i+1 == logSize ){
            cout << "0x1E" << endl;
            array += 0x1E;
            break;
        }
        array += 0x1F; //unit separator
    }
    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);

}

// -----------------------------------------

void Thread::reinitiate(){
    QByteArray array = "/reinitiate";
    array += 0x1F;
    array += 0x1E; //unit separator

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

// -----------------------------------------

void Thread::requestStruct() {
    QByteArray array = "/structure";
    array += 0x1F;
    array += 0x1E;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2011-2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stdlib.h>
#include <stdio.h>
#include <fnord-base/application.h>
#include <fnord-base/cli/flagparser.h>
#include <fnord-base/exception.h>
#include <fnord-base/exceptionhandler.h>
#include <fnord-base/inspect.h>
#include <fnord-base/random.h>
#include <fnord-base/io/fileutil.h>
#include <fnord-base/io/inputstream.h>
#include <fnord-base/io/outputstream.h>
#include <fnord-base/logging.h>
#include <fnord-base/net/udpserver.h>
#include <fnord-base/stats/statsd.h>
#include <fnord-base/stdtypes.h>
#include <fnord-base/thread/threadpool.h>
#include <fnord-http/httpserver.h>
#include <fnord-metricdb/metricservice.h>
#include <environment.h>

using fnord::metric_service::MetricService;
using namespace fnordmetric;

static const char kCrashErrorMsg[] =
    "FnordMetric crashed :( -- Please report a bug at "
    "github.com/paulasmuth/fnordmetric";

static MetricService makeMetricService(
    const std::string& backend_type,
    TaskScheduler* backend_scheduler) {

  /* open inmemory backend */
  if (backend_type == "inmemory") {
    fnord::logInfo("fnordmetric-server", "Opening new inmemory backend");
    return MetricService::newWithInMemoryBackend();
  }

  /* open disk backend */
  if (backend_type == "disk") {
    if (!env()->flags()->isSet("datadir")) {
      RAISE(
          kUsageError,
          "the --datadir flag must be set when using the disk backend");
    }

    auto datadir = env()->flags()->getString("datadir");

    if (!fnord::FileUtil::exists(datadir)) {
      RAISEF(kIOError, "File $0 does not exist", datadir);
    }

    if (!fnord::FileUtil::isDirectory(datadir)) {
      RAISEF(kIOError, "File $0 is not a directory", datadir);
    }

    fnord::logInfo("fnordmetric-server", "Opening disk backend at $0", datadir);
    return MetricService::newWithDiskBackend(datadir, backend_scheduler);
  }

  RAISEF(kUsageError, "unknown backend type: $0", backend_type);
}

static int startServer() {
  fnord::thread::ThreadPool server_pool;
  fnord::thread::ThreadPool worker_pool;

  /* setup MetricService */
  auto metric_service = makeMetricService(
      env()->flags()->getString("storage_backend"),
      &server_pool);

  /* Setup statsd server */
  /*if (env()->flags()->isSet("statsd_port")) {
    auto port = env()->flags()->getInt("statsd_port");
    fnord::logInfo("Starting statsd server on port $0", port);

    auto statsd_server = new StatsdServer(&server_pool, &worker_pool);
    statsd_server->onSample([&metric_service] (
        const std::string& key,
        double value,
        const std::vector<std::pair<std::string, std::string>>& labels) {
      if (env()->verbose()) {
        fnord::logDebug(
            "statsd sample: $0=$1 $2",
            key.c_str(),
            value,
            fnord::inspect(labels).c_str());
      }

      metric_service.insertSample(key, value, labels);
    });

    statsd_server->listen(port);
  }*/

  /* Setup http server */
  /*if (env()->flags()->isSet("http_port")) {
    auto port = env()->flags()->getInt("http_port");
    env()->logger()->printf(
        "INFO",
        "Starting HTTP server on port %i",
        port);

    auto http_api = new HTTPAPI(metric_service.metricRepository());

    auto http_server = new fnord::http::HTTPServer(
        &server_pool,
        &worker_pool);

    http_server->addHandler(AdminUI::getHandler());
    http_server->addHandler(JSONRPCHTTPAdapter::make(&json_rpc));
    http_server->addHandler(std::unique_ptr<http::HTTPHandler>(http_api));
    http_server->listen(port);
  }*/

  return 0;
}

static void printUsage() {
  auto err_stream = fnord::OutputStream::getStderr();
  err_stream->printf("usage: fnordmetric-server [options]\n");
  err_stream->printf("\noptions:\n");
  env()->flags()->printUsage(err_stream.get());
  err_stream->printf("\nexamples:\n");
  err_stream->printf("    $ fnordmetric-server --http_port 8080 --statsd_port 8125 --datadir /tmp/fnordmetric-data\n");
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  env()->flags()->defineFlag(
      "http_port",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8080",
      "Start the web interface on this port",
      "<port>");

  env()->flags()->defineFlag(
      "statsd_port",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8125",
      "Start the statsd interface on this port",
      "<port>");

  env()->flags()->defineFlag(
      "storage_backend",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "disk",
      "One of 'disk', 'inmemory', 'mysql' or 'hbase'. Default: 'disk'",
      "<name>");

  env()->flags()->defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "Store the database in this directory (disk backend only)",
      "<path>");

  env()->flags()->defineFlag(
      "disable_external_sources",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "Disable queries against external data sources like CSV files or MySQL");

  env()->flags()->defineFlag(
      "verbose",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      "Be verbose");

  env()->flags()->defineFlag(
      "help",
      cli::FlagParser::T_SWITCH,
      false,
      "h",
      NULL,
      "You are reading it...");

  env()->flags()->parseArgv(argc, argv);
  env()->setVerbose(env()->flags()->isSet("verbose"));

  if (env()->flags()->isSet("help")) {
    printUsage();
    return 0;
  }

  try {
    return startServer();
  } catch (const fnord::Exception& e) {
    fnord::logError("fnordmetric-server", e, "FATAL ERROR");

    if (e.getTypeName() == kUsageError) {
      printUsage();
    }

    return 1;
  }

  return 0;
}

<commit_msg>start new http, statsd server<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2011-2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stdlib.h>
#include <stdio.h>
#include <fnord-base/application.h>
#include <fnord-base/cli/flagparser.h>
#include <fnord-base/exception.h>
#include <fnord-base/exceptionhandler.h>
#include <fnord-base/inspect.h>
#include <fnord-base/random.h>
#include <fnord-base/io/fileutil.h>
#include <fnord-base/io/inputstream.h>
#include <fnord-base/io/outputstream.h>
#include <fnord-base/logging.h>
#include <fnord-base/net/udpserver.h>
#include <fnord-base/stats/statsd.h>
#include <fnord-base/stdtypes.h>
#include <fnord-base/thread/threadpool.h>
#include <fnord-base/thread/eventloop.h>
#include <fnord-http/httpserver.h>
#include <fnord-http/httprouter.h>
#include <fnord-json/json.h>
#include <fnord-json/jsonrpc.h>
#include <fnord-metricdb/metricservice.h>
#include <fnord-metricdb/httpapiservlet.h>
#include <environment.h>

using fnord::metric_service::MetricService;
using namespace fnordmetric;

static const char kCrashErrorMsg[] =
    "FnordMetric crashed :( -- Please report a bug at "
    "github.com/paulasmuth/fnordmetric";

static MetricService makeMetricService(
    const std::string& backend_type,
    TaskScheduler* backend_scheduler) {

  /* open inmemory backend */
  if (backend_type == "inmemory") {
    fnord::logInfo("fnordmetric-server", "Opening new inmemory backend");
    return MetricService::newWithInMemoryBackend();
  }

  /* open disk backend */
  if (backend_type == "disk") {
    if (!env()->flags()->isSet("datadir")) {
      RAISE(
          kUsageError,
          "the --datadir flag must be set when using the disk backend");
    }

    auto datadir = env()->flags()->getString("datadir");

    if (!fnord::FileUtil::exists(datadir)) {
      RAISEF(kIOError, "File $0 does not exist", datadir);
    }

    if (!fnord::FileUtil::isDirectory(datadir)) {
      RAISEF(kIOError, "File $0 is not a directory", datadir);
    }

    fnord::logInfo("fnordmetric-server", "Opening disk backend at $0", datadir);
    return MetricService::newWithDiskBackend(datadir, backend_scheduler);
  }

  RAISEF(kUsageError, "unknown backend type: $0", backend_type);
}

static int startServer() {
  /* Setup statsd server */
  return 0;
}

static void printUsage() {
  auto err_stream = fnord::OutputStream::getStderr();
  err_stream->printf("usage: fnordmetric-server [options]\n");
  err_stream->printf("\noptions:\n");
  env()->flags()->printUsage(err_stream.get());
  err_stream->printf("\nexamples:\n");
  err_stream->printf("    $ fnordmetric-server --http_port 8080 --statsd_port 8125 --datadir /tmp/fnordmetric-data\n");
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  env()->flags()->defineFlag(
      "http_port",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8080",
      "Start the web interface on this port",
      "<port>");

  env()->flags()->defineFlag(
      "statsd_port",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8125",
      "Start the statsd interface on this port",
      "<port>");

  env()->flags()->defineFlag(
      "storage_backend",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "disk",
      "One of 'disk', 'inmemory', 'mysql' or 'hbase'. Default: 'disk'",
      "<name>");

  env()->flags()->defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "Store the database in this directory (disk backend only)",
      "<path>");

  env()->flags()->defineFlag(
      "disable_external_sources",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "Disable queries against external data sources like CSV files or MySQL");

  env()->flags()->defineFlag(
      "verbose",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      "Be verbose");

  env()->flags()->defineFlag(
      "help",
      cli::FlagParser::T_SWITCH,
      false,
      "h",
      NULL,
      "You are reading it...");

  env()->flags()->parseArgv(argc, argv);
  env()->setVerbose(env()->flags()->isSet("verbose"));

  if (env()->flags()->isSet("help")) {
    printUsage();
    return 0;
  }

  fnord::thread::EventLoop evloop;
  fnord::thread::ThreadPool server_pool;
  fnord::thread::ThreadPool worker_pool;

  fnord::json::JSONRPC rpc;
  fnord::json::JSONRPCHTTPAdapter rpc_http(&rpc);

  try {
    /* setup MetricService */
    auto metric_service = makeMetricService(
        env()->flags()->getString("storage_backend"),
        &server_pool);

    /* start http server */
    auto http_port = env()->flags()->getInt("http_port");
    fnord::logInfo(
        "fnordmeric-server",
        "Starting HTTP server on port $0",
        http_port);

    fnord::http::HTTPRouter http_router;
    fnord::http::HTTPServer http_server(&http_router, &evloop);
    http_server.listen(http_port);

    fnord::metric_service::HTTPAPIServlet metrics_api(&metric_service);
    http_router.addRouteByPrefixMatch("/metrics", &metrics_api);
    http_router.addRouteByPrefixMatch("/rpc", &rpc_http);
    //auto http_api = new HTTPAPI(metric_service.metricRepository());
    //http_server->addHandler(AdminUI::getHandler());
    //http_server->addHandler(std::unique_ptr<http::HTTPHandler>(http_api));

    /* set up statsd server */
    fnord::statsd::StatsdServer statsd_server(&evloop, &evloop);
    statsd_server.onSample([&metric_service] (
        const std::string& key,
        double value,
        const std::vector<std::pair<std::string, std::string>>& labels) {
      if (env()->verbose()) {
        fnord::logDebug(
            "statsd sample: $0=$1 $2",
            key,
            value,
            fnord::inspect(labels).c_str());
      }

      metric_service.insertSample(key, value, labels);
    });

    /* start statsd server */
    if (env()->flags()->isSet("statsd_port")) {
      auto statsd_port = env()->flags()->getInt("statsd_port");

      fnord::logInfo(
          "fnordmetric-server",
          "Starting StatsD server on port $0",
          statsd_port);

      statsd_server.listen(statsd_port);
    }

    /* start event loop */
    evloop.run();
  } catch (const fnord::Exception& e) {
    fnord::logError("fnordmetric-server", e, "FATAL ERROR");

    if (e.getTypeName() == kUsageError) {
      printUsage();
    }

    return 1;
  }

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2020 The QXmpp developers
 *
 * Authors:
 *  Manjeet Dahiya
 *  Jeremy Lainé
 *
 * Source:
 *  https://github.com/qxmpp-project/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppStream.h"

#include "QXmppConstants_p.h"
#include "QXmppLogger.h"
#include "QXmppStanza.h"
#include "QXmppStreamManagement_p.h"
#include "QXmppUtils.h"

#include <QBuffer>
#include <QDomDocument>
#include <QHostAddress>
#include <QMap>
#include <QRegExp>
#include <QSslSocket>
#include <QStringList>
#include <QTime>
#include <QXmlStreamWriter>

#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
static bool randomSeeded = false;
#endif
static const QByteArray streamRootElementEnd = QByteArrayLiteral("</stream:stream>");

class QXmppStreamPrivate
{
public:
    QXmppStreamPrivate();

    QByteArray dataBuffer;
    QSslSocket *socket;

    // incoming stream state
    QByteArray streamStart;

    bool streamManagementEnabled;
    QMap<unsigned, QByteArray> unacknowledgedStanzas;
    unsigned lastOutgoingSequenceNumber;
    unsigned lastIncomingSequenceNumber;
};

QXmppStreamPrivate::QXmppStreamPrivate()
    : socket(nullptr), streamManagementEnabled(false), lastOutgoingSequenceNumber(0), lastIncomingSequenceNumber(0)
{
}

///
/// Constructs a base XMPP stream.
///
/// \param parent
///
QXmppStream::QXmppStream(QObject *parent)
    : QXmppLoggable(parent),
      d(new QXmppStreamPrivate)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
    // Make sure the random number generator is seeded
    if (!randomSeeded) {
        qsrand(QTime(0, 0, 0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
        randomSeeded = true;
    }
#endif
}

///
/// Destroys a base XMPP stream.
///
QXmppStream::~QXmppStream()
{
    delete d;
}

///
/// Disconnects from the remote host.
///
void QXmppStream::disconnectFromHost()
{
    d->streamManagementEnabled = false;
    if (d->socket) {
        if (d->socket->state() == QAbstractSocket::ConnectedState) {
            sendData(streamRootElementEnd);
            d->socket->flush();
        }
        // FIXME: according to RFC 6120 section 4.4, we should wait for
        // the incoming stream to end before closing the socket
        d->socket->disconnectFromHost();
    }
}

///
/// Handles a stream start event, which occurs when the underlying transport
/// becomes ready (socket connected, encryption started).
///
/// If you redefine handleStart(), make sure to call the base class's method.
///
void QXmppStream::handleStart()
{
    d->streamManagementEnabled = false;
    d->dataBuffer.clear();
    d->streamStart.clear();
}

///
/// Returns true if the stream is connected.
///
bool QXmppStream::isConnected() const
{
    return d->socket &&
        d->socket->state() == QAbstractSocket::ConnectedState;
}

///
/// Sends raw data to the peer.
///
/// \param data
///
bool QXmppStream::sendData(const QByteArray &data)
{
    logSent(QString::fromUtf8(data));
    if (!d->socket || d->socket->state() != QAbstractSocket::ConnectedState)
        return false;
    return d->socket->write(data) == data.size();
}

///
/// Sends an XMPP packet to the peer.
///
/// \param packet
///
bool QXmppStream::sendPacket(const QXmppStanza &packet)
{
    // prepare packet
    QByteArray data;
    QXmlStreamWriter xmlStream(&data);
    packet.toXml(&xmlStream);

    bool isXmppStanza = packet.isXmppStanza();
    if (isXmppStanza && d->streamManagementEnabled)
        d->unacknowledgedStanzas[++d->lastOutgoingSequenceNumber] = data;

    // send packet
    bool success = sendData(data);
    if (isXmppStanza)
        sendAcknowledgementRequest();
    return success;
}

///
/// Returns the QSslSocket used for this stream.
///
QSslSocket *QXmppStream::socket() const
{
    return d->socket;
}

///
/// Sets the QSslSocket used for this stream.
///
void QXmppStream::setSocket(QSslSocket *socket)
{
    d->socket = socket;
    if (!d->socket)
        return;

    // socket events
    connect(socket, &QAbstractSocket::connected, this, &QXmppStream::_q_socketConnected);
    connect(socket, &QSslSocket::encrypted, this, &QXmppStream::_q_socketEncrypted);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
    connect(socket, &QSslSocket::errorOccurred, this, &QXmppStream::_q_socketError);
#else
    connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error), this, &QXmppStream::_q_socketError);
#endif
    connect(socket, &QIODevice::readyRead, this, &QXmppStream::_q_socketReadyRead);
}

void QXmppStream::_q_socketConnected()
{
    info(QStringLiteral("Socket connected to %1 %2").arg(d->socket->peerAddress().toString(), QString::number(d->socket->peerPort())));
    handleStart();
}

void QXmppStream::_q_socketEncrypted()
{
    debug("Socket encrypted");
    handleStart();
}

void QXmppStream::_q_socketError(QAbstractSocket::SocketError socketError)
{
    Q_UNUSED(socketError);
    warning(QStringLiteral("Socket error: ") + socket()->errorString());
}

void QXmppStream::_q_socketReadyRead()
{
    d->dataBuffer.append(d->socket->readAll());

    // handle whitespace pings
    if (!d->dataBuffer.isEmpty() && d->dataBuffer.trimmed().isEmpty()) {
        d->dataBuffer.clear();
        handleStanza(QDomElement());
    }

    // FIXME : maybe these QRegExps could be static?
    QRegExp startStreamRegex(R"(^(<\?xml.*\?>)?\s*<stream:stream.*>)");
    startStreamRegex.setMinimal(true);
    QRegExp endStreamRegex("</stream:stream>$");
    endStreamRegex.setMinimal(true);

    // check whether we need to add stream start / end elements
    //
    // NOTE: as we may only have partial XML content, do not alter the stream's
    // state until we have a valid XML document!
    QByteArray completeXml = d->dataBuffer;
    const QString strData = QString::fromUtf8(d->dataBuffer);
    bool streamStart = false;
    if (d->streamStart.isEmpty() && startStreamRegex.indexIn(strData) != -1)
        streamStart = true;
    else
        completeXml.prepend(d->streamStart);
    bool streamEnd = false;
    if (endStreamRegex.indexIn(strData) != -1)
        streamEnd = true;
    else
        completeXml.append(streamRootElementEnd);

    // check whether we have a valid XML document
    QDomDocument doc;
    if (!doc.setContent(completeXml, true))
        return;

    // remove data from buffer
    logReceived(strData);
    d->dataBuffer.clear();

    // process stream start
    if (streamStart) {
        d->streamStart = startStreamRegex.cap(0).toUtf8();
        handleStream(doc.documentElement());
    }

    // process stanzas
    QDomElement nodeRecv = doc.documentElement().firstChildElement();
    while (!nodeRecv.isNull()) {
        if (QXmppStreamManagementAck::isStreamManagementAck(nodeRecv))
            handleAcknowledgement(nodeRecv);
        else if (QXmppStreamManagementReq::isStreamManagementReq(nodeRecv))
            sendAcknowledgement();
        else {
            handleStanza(nodeRecv);
            if (nodeRecv.tagName() == QLatin1String("message") ||
                nodeRecv.tagName() == QLatin1String("presence") ||
                nodeRecv.tagName() == QLatin1String("iq"))
                ++d->lastIncomingSequenceNumber;
        }
        nodeRecv = nodeRecv.nextSiblingElement();
    }

    // process stream end
    if (streamEnd)
        disconnectFromHost();
}

///
/// Enables Stream Management acks / reqs (\xep{0198}).
///
/// \param resetSequenceNumber Indicates if the sequence numbers should be
/// reset. This must be done if the stream is not resumed.
///
/// \since QXmpp 1.0
///
void QXmppStream::enableStreamManagement(bool resetSequenceNumber)
{
    d->streamManagementEnabled = true;

    if (resetSequenceNumber) {
        d->lastOutgoingSequenceNumber = 0;
        d->lastIncomingSequenceNumber = 0;

        // resend unacked stanzas
        if (!d->unacknowledgedStanzas.empty()) {
            QMap<unsigned, QByteArray> oldUnackedStanzas = d->unacknowledgedStanzas;
            d->unacknowledgedStanzas.clear();
            for (QMap<unsigned, QByteArray>::iterator it = oldUnackedStanzas.begin(); it != oldUnackedStanzas.end(); ++it) {
                d->unacknowledgedStanzas[++d->lastOutgoingSequenceNumber] = it.value();
                sendData(it.value());
            }
            sendAcknowledgementRequest();
        }
    } else {
        // resend unacked stanzas
        if (!d->unacknowledgedStanzas.empty()) {
            for (QMap<unsigned, QByteArray>::iterator it = d->unacknowledgedStanzas.begin(); it != d->unacknowledgedStanzas.end(); ++it)
                sendData(it.value());
            sendAcknowledgementRequest();
        }
    }
}

///
/// Returns the sequence number of the last incoming stanza (\xep{0198}).
///
/// \since QXmpp 1.0
///
unsigned QXmppStream::lastIncomingSequenceNumber() const
{
    return d->lastIncomingSequenceNumber;
}

///
/// Sets the last acknowledged sequence number for outgoing stanzas
/// (\xep{0198}).
///
/// \since QXmpp 1.0
///
void QXmppStream::setAcknowledgedSequenceNumber(unsigned sequenceNumber)
{
    for (QMap<unsigned, QByteArray>::iterator it = d->unacknowledgedStanzas.begin(); it != d->unacknowledgedStanzas.end();) {
        if (it.key() <= sequenceNumber)
            it = d->unacknowledgedStanzas.erase(it);
        else
            ++it;
    }
}

///
/// Handles an incoming acknowledgement from \xep{0198}.
///
/// \param element
///
/// \since QXmpp 1.0
///
void QXmppStream::handleAcknowledgement(QDomElement &element)
{
    if (!d->streamManagementEnabled)
        return;

    QXmppStreamManagementAck ack;
    ack.parse(element);
    setAcknowledgedSequenceNumber(ack.seqNo());
}

///
/// Sends an acknowledgement as defined in \xep{0198}.
///
/// \since QXmpp 1.0
///
void QXmppStream::sendAcknowledgement()
{
    if (!d->streamManagementEnabled)
        return;

    // prepare packet
    QByteArray data;
    QXmlStreamWriter xmlStream(&data);
    QXmppStreamManagementAck ack(d->lastIncomingSequenceNumber);
    ack.toXml(&xmlStream);

    // send packet
    sendData(data);
}

///
/// Sends an acknowledgement request as defined in \xep{0198}.
///
/// \since QXmpp 1.0
///
void QXmppStream::sendAcknowledgementRequest()
{
    if (!d->streamManagementEnabled)
        return;

    // prepare packet
    QByteArray data;
    QXmlStreamWriter xmlStream(&data);
    QXmppStreamManagementReq::toXml(&xmlStream);

    // send packet
    sendData(data);
}
<commit_msg>QXmppStream: Refactor XML parsing, Replace deprecated QRegExp<commit_after>/*
 * Copyright (C) 2008-2020 The QXmpp developers
 *
 * Authors:
 *  Manjeet Dahiya
 *  Jeremy Lainé
 *
 * Source:
 *  https://github.com/qxmpp-project/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppStream.h"

#include "QXmppConstants_p.h"
#include "QXmppLogger.h"
#include "QXmppStanza.h"
#include "QXmppStreamManagement_p.h"
#include "QXmppUtils.h"

#include <QBuffer>
#include <QDomDocument>
#include <QHostAddress>
#include <QMap>
#include <QRegularExpression>
#include <QSslSocket>
#include <QStringList>
#include <QTime>
#include <QXmlStreamWriter>

#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
static bool randomSeeded = false;
#endif

class QXmppStreamPrivate
{
public:
    QXmppStreamPrivate();

    QString dataBuffer;
    QSslSocket *socket;

    // incoming stream state
    QString streamOpenElement;

    bool streamManagementEnabled;
    QMap<unsigned, QByteArray> unacknowledgedStanzas;
    unsigned lastOutgoingSequenceNumber;
    unsigned lastIncomingSequenceNumber;
};

QXmppStreamPrivate::QXmppStreamPrivate()
    : socket(nullptr), streamManagementEnabled(false), lastOutgoingSequenceNumber(0), lastIncomingSequenceNumber(0)
{
}

///
/// Constructs a base XMPP stream.
///
/// \param parent
///
QXmppStream::QXmppStream(QObject *parent)
    : QXmppLoggable(parent),
      d(new QXmppStreamPrivate)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
    // Make sure the random number generator is seeded
    if (!randomSeeded) {
        qsrand(QTime(0, 0, 0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
        randomSeeded = true;
    }
#endif
}

///
/// Destroys a base XMPP stream.
///
QXmppStream::~QXmppStream()
{
    delete d;
}

///
/// Disconnects from the remote host.
///
void QXmppStream::disconnectFromHost()
{
    d->streamManagementEnabled = false;
    if (d->socket) {
        if (d->socket->state() == QAbstractSocket::ConnectedState) {
            sendData(QByteArrayLiteral("</stream:stream>"));
            d->socket->flush();
        }
        // FIXME: according to RFC 6120 section 4.4, we should wait for
        // the incoming stream to end before closing the socket
        d->socket->disconnectFromHost();
    }
}

///
/// Handles a stream start event, which occurs when the underlying transport
/// becomes ready (socket connected, encryption started).
///
/// If you redefine handleStart(), make sure to call the base class's method.
///
void QXmppStream::handleStart()
{
    d->streamManagementEnabled = false;
    d->dataBuffer.clear();
    d->streamOpenElement.clear();
}

///
/// Returns true if the stream is connected.
///
bool QXmppStream::isConnected() const
{
    return d->socket &&
        d->socket->state() == QAbstractSocket::ConnectedState;
}

///
/// Sends raw data to the peer.
///
/// \param data
///
bool QXmppStream::sendData(const QByteArray &data)
{
    logSent(QString::fromUtf8(data));
    if (!d->socket || d->socket->state() != QAbstractSocket::ConnectedState)
        return false;
    return d->socket->write(data) == data.size();
}

///
/// Sends an XMPP packet to the peer.
///
/// \param packet
///
bool QXmppStream::sendPacket(const QXmppStanza &packet)
{
    // prepare packet
    QByteArray data;
    QXmlStreamWriter xmlStream(&data);
    packet.toXml(&xmlStream);

    bool isXmppStanza = packet.isXmppStanza();
    if (isXmppStanza && d->streamManagementEnabled)
        d->unacknowledgedStanzas[++d->lastOutgoingSequenceNumber] = data;

    // send packet
    bool success = sendData(data);
    if (isXmppStanza)
        sendAcknowledgementRequest();
    return success;
}

///
/// Returns the QSslSocket used for this stream.
///
QSslSocket *QXmppStream::socket() const
{
    return d->socket;
}

///
/// Sets the QSslSocket used for this stream.
///
void QXmppStream::setSocket(QSslSocket *socket)
{
    d->socket = socket;
    if (!d->socket)
        return;

    // socket events
    connect(socket, &QAbstractSocket::connected, this, &QXmppStream::_q_socketConnected);
    connect(socket, &QSslSocket::encrypted, this, &QXmppStream::_q_socketEncrypted);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
    connect(socket, &QSslSocket::errorOccurred, this, &QXmppStream::_q_socketError);
#else
    connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error), this, &QXmppStream::_q_socketError);
#endif
    connect(socket, &QIODevice::readyRead, this, &QXmppStream::_q_socketReadyRead);
}

void QXmppStream::_q_socketConnected()
{
    info(QStringLiteral("Socket connected to %1 %2").arg(d->socket->peerAddress().toString(), QString::number(d->socket->peerPort())));
    handleStart();
}

void QXmppStream::_q_socketEncrypted()
{
    debug("Socket encrypted");
    handleStart();
}

void QXmppStream::_q_socketError(QAbstractSocket::SocketError socketError)
{
    Q_UNUSED(socketError);
    warning(QStringLiteral("Socket error: ") + socket()->errorString());
}

void QXmppStream::_q_socketReadyRead()
{
    // As we may only have partial XML content, we need to cache the received
    // data until it has been successfully parsed. In case it can't be parsed,
    //
    // There are only two small problems with the current strategy:
    //  * When we receive a full stanza + a partial one, we can't parse the
    //    first stanza until another stanza arrives that is complete.
    //  * We don't know when we received invalid XML (would cause a growing
    //    cache and a timeout after some time).
    // However, both issues could only be solved using an XML stream reader
    // which would cause many other problems since we don't actually use it for
    // parsing the content.
    d->dataBuffer.append(QString::fromUtf8(d->socket->readAll()));

    //
    // Check for whitespace pings
    //
    if (d->dataBuffer.isEmpty() || d->dataBuffer.trimmed().isEmpty()) {
        d->dataBuffer.clear();

        logReceived({});
        handleStanza({});
        return;
    }

    //
    // Check whether we received a stream open or closing tag
    //
    static const QRegularExpression streamStartRegex(R"(^(<\?xml.*\?>)?\s*<stream:stream[^>]*>)");
    static const QRegularExpression streamEndRegex("</stream:stream>$");

    QRegularExpressionMatch streamOpenMatch;
    bool hasStreamOpen = d->streamOpenElement.isEmpty() &&
        (streamOpenMatch = streamStartRegex.match(d->dataBuffer)).hasMatch();

    bool hasStreamClose = streamEndRegex.match(d->dataBuffer).hasMatch();

    //
    // The stream start/end and stanza packets can't be parsed without any
    // modifications with QDomDocument. This is because of multiple reasons:
    //  * The <stream:stream> open element is not considered valid without the
    //    closing tag.
    //  * Only the closing tag is of course not valid too.
    //  * Stanzas/Nonzas need to have the correct stream namespaces set:
    //     * For being able to parse <stream:features/>
    //     * For having the correct namespace (e.g. 'jabber:client') set to
    //       stanzas and their child elements (e.g. <body/> of a message).
    //
    // The wrapping strategy looks like this:
    //  * The stream open tag is cached once it arrives, for later access
    //  * Incoming XML that has no <stream> open tag will be prepended by the
    //    cached <stream> tag.
    //  * Incoming XML that has no <stream> close tag will be appended by a
    //    generic string "</stream:stream>"
    //
    // The result is parsed by QDomDocument and the child elements of the stream
    // are processed. In case the received data contained a stream open tag,
    // the stream is processed (before the stanzas are processed). In case we
    // received a </stream> closing tag, the connection is closed.
    //
    auto wrappedStanzas = d->dataBuffer;
    if (!hasStreamOpen) {
        wrappedStanzas.prepend(d->streamOpenElement);
    }
    if (!hasStreamClose) {
        wrappedStanzas.append(QStringLiteral("</stream:stream>"));
    }

    //
    // Try to parse the wrapped XML
    //
    QDomDocument doc;
    if (!doc.setContent(wrappedStanzas, true))
        return;

    //
    // Success: We can clear the buffer and send a 'received' log message
    //
    d->dataBuffer.clear();
    logReceived(d->dataBuffer);

    // process stream start
    if (hasStreamOpen) {
        d->streamOpenElement = streamOpenMatch.captured();
        handleStream(doc.documentElement());
    }

    // process stanzas
    QDomElement nodeRecv = doc.documentElement().firstChildElement();
    while (!nodeRecv.isNull()) {
        if (QXmppStreamManagementAck::isStreamManagementAck(nodeRecv))
            handleAcknowledgement(nodeRecv);
        else if (QXmppStreamManagementReq::isStreamManagementReq(nodeRecv))
            sendAcknowledgement();
        else {
            handleStanza(nodeRecv);
            if (nodeRecv.tagName() == QLatin1String("message") ||
                nodeRecv.tagName() == QLatin1String("presence") ||
                nodeRecv.tagName() == QLatin1String("iq"))
                ++d->lastIncomingSequenceNumber;
        }
        nodeRecv = nodeRecv.nextSiblingElement();
    }

    // process stream end
    if (hasStreamClose) {
        disconnectFromHost();
    }
}

///
/// Enables Stream Management acks / reqs (\xep{0198}).
///
/// \param resetSequenceNumber Indicates if the sequence numbers should be
/// reset. This must be done if the stream is not resumed.
///
/// \since QXmpp 1.0
///
void QXmppStream::enableStreamManagement(bool resetSequenceNumber)
{
    d->streamManagementEnabled = true;

    if (resetSequenceNumber) {
        d->lastOutgoingSequenceNumber = 0;
        d->lastIncomingSequenceNumber = 0;

        // resend unacked stanzas
        if (!d->unacknowledgedStanzas.empty()) {
            QMap<unsigned, QByteArray> oldUnackedStanzas = d->unacknowledgedStanzas;
            d->unacknowledgedStanzas.clear();
            for (QMap<unsigned, QByteArray>::iterator it = oldUnackedStanzas.begin(); it != oldUnackedStanzas.end(); ++it) {
                d->unacknowledgedStanzas[++d->lastOutgoingSequenceNumber] = it.value();
                sendData(it.value());
            }
            sendAcknowledgementRequest();
        }
    } else {
        // resend unacked stanzas
        if (!d->unacknowledgedStanzas.empty()) {
            for (QMap<unsigned, QByteArray>::iterator it = d->unacknowledgedStanzas.begin(); it != d->unacknowledgedStanzas.end(); ++it)
                sendData(it.value());
            sendAcknowledgementRequest();
        }
    }
}

///
/// Returns the sequence number of the last incoming stanza (\xep{0198}).
///
/// \since QXmpp 1.0
///
unsigned QXmppStream::lastIncomingSequenceNumber() const
{
    return d->lastIncomingSequenceNumber;
}

///
/// Sets the last acknowledged sequence number for outgoing stanzas
/// (\xep{0198}).
///
/// \since QXmpp 1.0
///
void QXmppStream::setAcknowledgedSequenceNumber(unsigned sequenceNumber)
{
    for (QMap<unsigned, QByteArray>::iterator it = d->unacknowledgedStanzas.begin(); it != d->unacknowledgedStanzas.end();) {
        if (it.key() <= sequenceNumber)
            it = d->unacknowledgedStanzas.erase(it);
        else
            ++it;
    }
}

///
/// Handles an incoming acknowledgement from \xep{0198}.
///
/// \param element
///
/// \since QXmpp 1.0
///
void QXmppStream::handleAcknowledgement(QDomElement &element)
{
    if (!d->streamManagementEnabled)
        return;

    QXmppStreamManagementAck ack;
    ack.parse(element);
    setAcknowledgedSequenceNumber(ack.seqNo());
}

///
/// Sends an acknowledgement as defined in \xep{0198}.
///
/// \since QXmpp 1.0
///
void QXmppStream::sendAcknowledgement()
{
    if (!d->streamManagementEnabled)
        return;

    // prepare packet
    QByteArray data;
    QXmlStreamWriter xmlStream(&data);
    QXmppStreamManagementAck ack(d->lastIncomingSequenceNumber);
    ack.toXml(&xmlStream);

    // send packet
    sendData(data);
}

///
/// Sends an acknowledgement request as defined in \xep{0198}.
///
/// \since QXmpp 1.0
///
void QXmppStream::sendAcknowledgementRequest()
{
    if (!d->streamManagementEnabled)
        return;

    // prepare packet
    QByteArray data;
    QXmlStreamWriter xmlStream(&data);
    QXmppStreamManagementReq::toXml(&xmlStream);

    // send packet
    sendData(data);
}
<|endoftext|>