<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: LineChartType.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: vg $ $Date: 2007-05-22 18:49:07 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "LineChartType.hxx"
#include "PropertyHelper.hxx"
#include "macros.hxx"
#include "servicenames_charttypes.hxx"
#include "ContainerHelper.hxx"

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART2_CURVESTYLE_HPP_
#include <com/sun/star/chart2/CurveStyle.hpp>
#endif

using namespace ::com::sun::star;

using ::rtl::OUString;
using ::com::sun::star::beans::Property;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Any;
using ::osl::MutexGuard;

namespace
{

enum
{
    PROP_LINECHARTTYPE_CURVE_STYLE,
    PROP_LINECHARTTYPE_CURVE_RESOLUTION,
    PROP_LINECHARTTYPE_SPLINE_ORDER
};

void lcl_AddPropertiesToVector(
    ::std::vector< Property > & rOutProperties )
{
    rOutProperties.push_back(
        Property( C2U( "CurveStyle" ),
                  PROP_LINECHARTTYPE_CURVE_STYLE,
                  ::getCppuType( reinterpret_cast< const chart2::CurveStyle * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "CurveResolution" ),
                  PROP_LINECHARTTYPE_CURVE_RESOLUTION,
                  ::getCppuType( reinterpret_cast< const sal_Int32 * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
    rOutProperties.push_back(
        Property( C2U( "SplineOrder" ),
                  PROP_LINECHARTTYPE_SPLINE_ORDER,
                  ::getCppuType( reinterpret_cast< const sal_Int32 * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
}

void lcl_AddDefaultsToMap(
    ::chart::tPropertyValueMap & rOutMap )
{
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_LINECHARTTYPE_CURVE_STYLE ));
    rOutMap[ PROP_LINECHARTTYPE_CURVE_STYLE ] =
        uno::makeAny( chart2::CurveStyle_LINES );

    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_LINECHARTTYPE_CURVE_RESOLUTION ));
    rOutMap[ PROP_LINECHARTTYPE_CURVE_RESOLUTION ] =
        uno::makeAny( sal_Int32( 20 ) );

    // todo: check whether order 3 means polygons of order 3 or 2. (see
    // http://www.people.nnov.ru/fractal/Splines/Basis.htm )
    OSL_ASSERT( rOutMap.end() == rOutMap.find( PROP_LINECHARTTYPE_SPLINE_ORDER ));
    rOutMap[ PROP_LINECHARTTYPE_SPLINE_ORDER ] =
        uno::makeAny( sal_Int32( 3 ) );
}

const Sequence< Property > & lcl_GetPropertySequence()
{
    static Sequence< Property > aPropSeq;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aPropSeq.getLength() )
    {
        // get properties
        ::std::vector< ::com::sun::star::beans::Property > aProperties;
        lcl_AddPropertiesToVector( aProperties );

        // and sort them for access via bsearch
        ::std::sort( aProperties.begin(), aProperties.end(),
                     ::chart::PropertyNameLess() );

        // transfer result to static Sequence
        aPropSeq = ::chart::ContainerHelper::ContainerToSequence( aProperties );
    }

    return aPropSeq;
}

} // anonymous namespace

namespace chart
{

LineChartType::LineChartType(
    const uno::Reference< uno::XComponentContext > & xContext ) :
        ChartType( xContext )
{
}

LineChartType::LineChartType( const LineChartType & rOther ) :
        ChartType( rOther )
{
}

LineChartType::~LineChartType()
{}

// ____ XCloneable ____
uno::Reference< util::XCloneable > SAL_CALL LineChartType::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new LineChartType( *this ));
}

// ____ XChartType ____
::rtl::OUString SAL_CALL LineChartType::getChartType()
    throw (uno::RuntimeException)
{
    return CHART2_SERVICE_NAME_CHARTTYPE_LINE;
}

// ____ OPropertySet ____
uno::Any LineChartType::GetDefaultValue( sal_Int32 nHandle ) const
    throw(beans::UnknownPropertyException)
{
    static tPropertyValueMap aStaticDefaults;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aStaticDefaults.size() )
    {
        // initialize defaults
        lcl_AddDefaultsToMap( aStaticDefaults );
    }

    tPropertyValueMap::const_iterator aFound(
        aStaticDefaults.find( nHandle ));

    if( aFound == aStaticDefaults.end())
        return uno::Any();

    return (*aFound).second;
    // \--
}

::cppu::IPropertyArrayHelper & SAL_CALL LineChartType::getInfoHelper()
{
    static ::cppu::OPropertyArrayHelper aArrayHelper( lcl_GetPropertySequence(),
                                                      /* bSorted = */ sal_True );

    return aArrayHelper;
}

// ____ XPropertySet ____
uno::Reference< beans::XPropertySetInfo > SAL_CALL
    LineChartType::getPropertySetInfo()
    throw (uno::RuntimeException)
{
    static uno::Reference< beans::XPropertySetInfo > xInfo;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( !xInfo.is())
    {
        xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo(
            getInfoHelper());
    }

    return xInfo;
    // \--
}

uno::Sequence< ::rtl::OUString > LineChartType::getSupportedServiceNames_Static()
{
    uno::Sequence< ::rtl::OUString > aServices( 3 );
    aServices[ 0 ] = CHART2_SERVICE_NAME_CHARTTYPE_LINE;
    aServices[ 1 ] = C2U( "com.sun.star.chart2.ChartType" );
    aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" );
    return aServices;
}

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( LineChartType,
                             C2U( "com.sun.star.comp.chart.LineChartType" ));

} //  namespace chart
<commit_msg>INTEGRATION: CWS chart11 (1.9.38); FILE MERGED 2007/07/31 12:56:45 bm 1.9.38.1: #i80084# avoid usage of map operator[] with enums as keys, simplify initialization of default property values<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: LineChartType.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: vg $ $Date: 2007-09-18 15:05:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "LineChartType.hxx"
#include "PropertyHelper.hxx"
#include "macros.hxx"
#include "servicenames_charttypes.hxx"
#include "ContainerHelper.hxx"

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART2_CURVESTYLE_HPP_
#include <com/sun/star/chart2/CurveStyle.hpp>
#endif

using namespace ::com::sun::star;

using ::rtl::OUString;
using ::com::sun::star::beans::Property;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Any;
using ::osl::MutexGuard;

namespace
{

enum
{
    PROP_LINECHARTTYPE_CURVE_STYLE,
    PROP_LINECHARTTYPE_CURVE_RESOLUTION,
    PROP_LINECHARTTYPE_SPLINE_ORDER
};

void lcl_AddPropertiesToVector(
    ::std::vector< Property > & rOutProperties )
{
    rOutProperties.push_back(
        Property( C2U( "CurveStyle" ),
                  PROP_LINECHARTTYPE_CURVE_STYLE,
                  ::getCppuType( reinterpret_cast< const chart2::CurveStyle * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));

    rOutProperties.push_back(
        Property( C2U( "CurveResolution" ),
                  PROP_LINECHARTTYPE_CURVE_RESOLUTION,
                  ::getCppuType( reinterpret_cast< const sal_Int32 * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
    rOutProperties.push_back(
        Property( C2U( "SplineOrder" ),
                  PROP_LINECHARTTYPE_SPLINE_ORDER,
                  ::getCppuType( reinterpret_cast< const sal_Int32 * >(0)),
                  beans::PropertyAttribute::BOUND
                  | beans::PropertyAttribute::MAYBEDEFAULT ));
}

void lcl_AddDefaultsToMap(
    ::chart::tPropertyValueMap & rOutMap )
{
    ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LINECHARTTYPE_CURVE_STYLE, ::chart2::CurveStyle_LINES );
    ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_LINECHARTTYPE_CURVE_RESOLUTION, 20 );

    // todo: check whether order 3 means polygons of order 3 or 2. (see
    // http://www.people.nnov.ru/fractal/Splines/Basis.htm )
    ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_LINECHARTTYPE_SPLINE_ORDER, 3 );
}

const Sequence< Property > & lcl_GetPropertySequence()
{
    static Sequence< Property > aPropSeq;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aPropSeq.getLength() )
    {
        // get properties
        ::std::vector< ::com::sun::star::beans::Property > aProperties;
        lcl_AddPropertiesToVector( aProperties );

        // and sort them for access via bsearch
        ::std::sort( aProperties.begin(), aProperties.end(),
                     ::chart::PropertyNameLess() );

        // transfer result to static Sequence
        aPropSeq = ::chart::ContainerHelper::ContainerToSequence( aProperties );
    }

    return aPropSeq;
}

} // anonymous namespace

namespace chart
{

LineChartType::LineChartType(
    const uno::Reference< uno::XComponentContext > & xContext ) :
        ChartType( xContext )
{
}

LineChartType::LineChartType( const LineChartType & rOther ) :
        ChartType( rOther )
{
}

LineChartType::~LineChartType()
{}

// ____ XCloneable ____
uno::Reference< util::XCloneable > SAL_CALL LineChartType::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new LineChartType( *this ));
}

// ____ XChartType ____
::rtl::OUString SAL_CALL LineChartType::getChartType()
    throw (uno::RuntimeException)
{
    return CHART2_SERVICE_NAME_CHARTTYPE_LINE;
}

// ____ OPropertySet ____
uno::Any LineChartType::GetDefaultValue( sal_Int32 nHandle ) const
    throw(beans::UnknownPropertyException)
{
    static tPropertyValueMap aStaticDefaults;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aStaticDefaults.size() )
    {
        // initialize defaults
        lcl_AddDefaultsToMap( aStaticDefaults );
    }

    tPropertyValueMap::const_iterator aFound(
        aStaticDefaults.find( nHandle ));

    if( aFound == aStaticDefaults.end())
        return uno::Any();

    return (*aFound).second;
    // \--
}

::cppu::IPropertyArrayHelper & SAL_CALL LineChartType::getInfoHelper()
{
    static ::cppu::OPropertyArrayHelper aArrayHelper( lcl_GetPropertySequence(),
                                                      /* bSorted = */ sal_True );

    return aArrayHelper;
}

// ____ XPropertySet ____
uno::Reference< beans::XPropertySetInfo > SAL_CALL
    LineChartType::getPropertySetInfo()
    throw (uno::RuntimeException)
{
    static uno::Reference< beans::XPropertySetInfo > xInfo;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( !xInfo.is())
    {
        xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo(
            getInfoHelper());
    }

    return xInfo;
    // \--
}

uno::Sequence< ::rtl::OUString > LineChartType::getSupportedServiceNames_Static()
{
    uno::Sequence< ::rtl::OUString > aServices( 3 );
    aServices[ 0 ] = CHART2_SERVICE_NAME_CHARTTYPE_LINE;
    aServices[ 1 ] = C2U( "com.sun.star.chart2.ChartType" );
    aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" );
    return aServices;
}

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( LineChartType,
                             C2U( "com.sun.star.comp.chart.LineChartType" ));

} //  namespace chart
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/chromeos/login/web_page_view.h"

#include "base/callback.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/webui/web_ui.h"
#include "content/common/bindings_policy.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ipc/ipc_message.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "views/background.h"
#include "views/border.h"
#include "views/controls/label.h"
#include "views/controls/throbber.h"

using base::TimeDelta;
using views::Label;
using views::View;
using webkit_glue::FormData;

namespace chromeos {

namespace {

// Spacing (vertical/horizontal) between controls.
const int kSpacing = 10;

// Time in ms after that waiting controls are shown on Start.
const int kStartDelayMs = 500;

// Time in ms after that waiting controls are hidden on Stop.
const int kStopDelayMs = 500;

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// WizardWebPageViewTabContents, public:

WizardWebPageViewTabContents::WizardWebPageViewTabContents(
    Profile* profile,
    SiteInstance* site_instance,
    WebPageDelegate* page_delegate)
      : TabContents(profile, site_instance, MSG_ROUTING_NONE, NULL, NULL),
        page_delegate_(page_delegate) {
  }

void WizardWebPageViewTabContents::DidFailProvisionalLoadWithError(
      RenderViewHost* render_view_host,
      bool is_main_frame,
      int error_code,
      const GURL& url,
      bool showing_repost_interstitial) {
  LOG(ERROR) << "Page load failed. URL = " << url << ", error: " << error_code;
  page_delegate_->OnPageLoadFailed(url.spec());
}

void WizardWebPageViewTabContents::DidDisplayInsecureContent() {
  LOG(ERROR) << "Page load failed: did display insecure content";
  page_delegate_->OnPageLoadFailed("Displayed insecure content");
}

void WizardWebPageViewTabContents::DidRunInsecureContent(
    const std::string& security_origin) {
  LOG(ERROR) << "Page load failed: did run insecure content";
  page_delegate_->OnPageLoadFailed(security_origin);
}

void WizardWebPageViewTabContents::DocumentLoadedInFrame(
    long long /*frame_id*/) {
  page_delegate_->OnPageLoaded();
}

void WizardWebPageViewTabContents::DidFinishLoad(
    long long /*frame_id*/) {
}

///////////////////////////////////////////////////////////////////////////////
// WebPageDomView, public:

void WebPageDomView::SetTabContentsDelegate(
    TabContentsDelegate* delegate) {
  tab_contents_->set_delegate(delegate);
}

///////////////////////////////////////////////////////////////////////////////
// WebPageView, public:

WebPageView::WebPageView() : throbber_(NULL), connecting_label_(NULL) {}

WebPageView::~WebPageView() {}

void WebPageView::Init() {
  views::Painter* painter = CreateWizardPainter(
      &BorderDefinition::kScreenBorder);
  set_background(
      views::Background::CreateBackgroundPainter(true, painter));
  set_border(CreateWizardBorder(&BorderDefinition::kScreenBorder));
  dom_view()->SetVisible(false);
  AddChildView(dom_view());

  throbber_ = CreateDefaultThrobber();
  AddChildView(throbber_);

  connecting_label_ = new views::Label();
  connecting_label_->SetText(
      UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING)));
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  connecting_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
  connecting_label_->SetVisible(false);
  AddChildView(connecting_label_ );

  start_timer_.Start(TimeDelta::FromMilliseconds(kStartDelayMs),
                     this,
                     &WebPageView::ShowWaitingControls);
}

void WebPageView::InitDOM(Profile* profile,
                          SiteInstance* site_instance) {
  dom_view()->Init(profile, site_instance);
}

void WebPageView::LoadURL(const GURL& url) {
  dom_view()->LoadURL(url);
}

void WebPageView::SetTabContentsDelegate(
    TabContentsDelegate* delegate) {
  dom_view()->SetTabContentsDelegate(delegate);
}

void WebPageView::SetWebPageDelegate(WebPageDelegate* delegate) {
  dom_view()->set_web_page_delegate(delegate);
}

void WebPageView::ShowPageContent() {
  // TODO(nkostylev): Show throbber as an overlay until page has been rendered.
  start_timer_.Stop();
  if (!stop_timer_.IsRunning()) {
    stop_timer_.Start(TimeDelta::FromMilliseconds(kStopDelayMs),
                      this,
                      &WebPageView::ShowRenderedPage);
  }
}

///////////////////////////////////////////////////////////////////////////////
// WebPageView, private:

void WebPageView::ShowRenderedPage() {
  throbber_->Stop();
  connecting_label_->SetVisible(false);
  dom_view()->SetVisible(true);
}

void WebPageView::ShowWaitingControls() {
  throbber_->Start();
  connecting_label_->SetVisible(true);
}

///////////////////////////////////////////////////////////////////////////////
// WebPageView, views::View implementation:

void WebPageView::Layout() {
  dom_view()->SetBoundsRect(GetContentsBounds());
  int y = height() / 2  - throbber_->GetPreferredSize().height() / 2;
  throbber_->SetBounds(
      width() / 2 - throbber_->GetPreferredSize().width() / 2,
      y,
      throbber_->GetPreferredSize().width(),
      throbber_->GetPreferredSize().height());
  connecting_label_->SetBounds(
      width() / 2 - connecting_label_->GetPreferredSize().width() / 2,
      y + throbber_->GetPreferredSize().height() + kSpacing,
      connecting_label_->GetPreferredSize().width(),
      connecting_label_->GetPreferredSize().height());
}

}  // namespace chromeos
<commit_msg>fix compile error that just started happening on linux views builders, not sure why<commit_after>// Copyright (c) 2011 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/chromeos/login/web_page_view.h"

#include "base/callback.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/webui/web_ui.h"
#include "content/common/bindings_policy.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ipc/ipc_message.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "views/background.h"
#include "views/border.h"
#include "views/controls/label.h"
#include "views/controls/throbber.h"

using base::TimeDelta;
using views::Label;
using views::View;

namespace chromeos {

namespace {

// Spacing (vertical/horizontal) between controls.
const int kSpacing = 10;

// Time in ms after that waiting controls are shown on Start.
const int kStartDelayMs = 500;

// Time in ms after that waiting controls are hidden on Stop.
const int kStopDelayMs = 500;

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// WizardWebPageViewTabContents, public:

WizardWebPageViewTabContents::WizardWebPageViewTabContents(
    Profile* profile,
    SiteInstance* site_instance,
    WebPageDelegate* page_delegate)
      : TabContents(profile, site_instance, MSG_ROUTING_NONE, NULL, NULL),
        page_delegate_(page_delegate) {
  }

void WizardWebPageViewTabContents::DidFailProvisionalLoadWithError(
      RenderViewHost* render_view_host,
      bool is_main_frame,
      int error_code,
      const GURL& url,
      bool showing_repost_interstitial) {
  LOG(ERROR) << "Page load failed. URL = " << url << ", error: " << error_code;
  page_delegate_->OnPageLoadFailed(url.spec());
}

void WizardWebPageViewTabContents::DidDisplayInsecureContent() {
  LOG(ERROR) << "Page load failed: did display insecure content";
  page_delegate_->OnPageLoadFailed("Displayed insecure content");
}

void WizardWebPageViewTabContents::DidRunInsecureContent(
    const std::string& security_origin) {
  LOG(ERROR) << "Page load failed: did run insecure content";
  page_delegate_->OnPageLoadFailed(security_origin);
}

void WizardWebPageViewTabContents::DocumentLoadedInFrame(
    long long /*frame_id*/) {
  page_delegate_->OnPageLoaded();
}

void WizardWebPageViewTabContents::DidFinishLoad(
    long long /*frame_id*/) {
}

///////////////////////////////////////////////////////////////////////////////
// WebPageDomView, public:

void WebPageDomView::SetTabContentsDelegate(
    TabContentsDelegate* delegate) {
  tab_contents_->set_delegate(delegate);
}

///////////////////////////////////////////////////////////////////////////////
// WebPageView, public:

WebPageView::WebPageView() : throbber_(NULL), connecting_label_(NULL) {}

WebPageView::~WebPageView() {}

void WebPageView::Init() {
  views::Painter* painter = CreateWizardPainter(
      &BorderDefinition::kScreenBorder);
  set_background(
      views::Background::CreateBackgroundPainter(true, painter));
  set_border(CreateWizardBorder(&BorderDefinition::kScreenBorder));
  dom_view()->SetVisible(false);
  AddChildView(dom_view());

  throbber_ = CreateDefaultThrobber();
  AddChildView(throbber_);

  connecting_label_ = new views::Label();
  connecting_label_->SetText(
      UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOAD_STATE_CONNECTING)));
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  connecting_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
  connecting_label_->SetVisible(false);
  AddChildView(connecting_label_ );

  start_timer_.Start(TimeDelta::FromMilliseconds(kStartDelayMs),
                     this,
                     &WebPageView::ShowWaitingControls);
}

void WebPageView::InitDOM(Profile* profile,
                          SiteInstance* site_instance) {
  dom_view()->Init(profile, site_instance);
}

void WebPageView::LoadURL(const GURL& url) {
  dom_view()->LoadURL(url);
}

void WebPageView::SetTabContentsDelegate(
    TabContentsDelegate* delegate) {
  dom_view()->SetTabContentsDelegate(delegate);
}

void WebPageView::SetWebPageDelegate(WebPageDelegate* delegate) {
  dom_view()->set_web_page_delegate(delegate);
}

void WebPageView::ShowPageContent() {
  // TODO(nkostylev): Show throbber as an overlay until page has been rendered.
  start_timer_.Stop();
  if (!stop_timer_.IsRunning()) {
    stop_timer_.Start(TimeDelta::FromMilliseconds(kStopDelayMs),
                      this,
                      &WebPageView::ShowRenderedPage);
  }
}

///////////////////////////////////////////////////////////////////////////////
// WebPageView, private:

void WebPageView::ShowRenderedPage() {
  throbber_->Stop();
  connecting_label_->SetVisible(false);
  dom_view()->SetVisible(true);
}

void WebPageView::ShowWaitingControls() {
  throbber_->Start();
  connecting_label_->SetVisible(true);
}

///////////////////////////////////////////////////////////////////////////////
// WebPageView, views::View implementation:

void WebPageView::Layout() {
  dom_view()->SetBoundsRect(GetContentsBounds());
  int y = height() / 2  - throbber_->GetPreferredSize().height() / 2;
  throbber_->SetBounds(
      width() / 2 - throbber_->GetPreferredSize().width() / 2,
      y,
      throbber_->GetPreferredSize().width(),
      throbber_->GetPreferredSize().height());
  connecting_label_->SetBounds(
      width() / 2 - connecting_label_->GetPreferredSize().width() / 2,
      y + throbber_->GetPreferredSize().height() + kSpacing,
      connecting_label_->GetPreferredSize().width(),
      connecting_label_->GetPreferredSize().height());
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
***************************************************************************/

#include <QtGui>

#include "mainwindow.h"

//![0]
MainWindow::MainWindow()
{
    audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
    mediaObject = new Phonon::MediaObject(this);
    metaInformationResolver = new Phonon::MediaObject(this);

    mediaObject->setTickInterval(1000);
//![0]
//![2]
    connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
    connect(metaInformationResolver, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
            this, SLOT(metaStateChanged(Phonon::State, Phonon::State)));
    connect(mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)),
            this, SLOT(sourceChanged(const Phonon::MediaSource &)));
    connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
//![2]

//![1]
    Phonon::createPath(mediaObject, audioOutput);
//![1]

    setupActions();
    setupMenus();
    setupUi();
    timeLcd->display("00:00");
}

//![6]
void MainWindow::addFiles()
{
    QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Music Files"),
        QDesktopServices::storageLocation(QDesktopServices::MusicLocation));

    if (files.isEmpty())
        return;

    int index = sources.size();
    foreach (QString string, files) {
            Phonon::MediaSource source(string);

        sources.append(source);
    }
    if (!sources.isEmpty())
        metaInformationResolver->setCurrentSource(sources.at(index));

}
//![6]

void MainWindow::about()
{
    QMessageBox::information(this, tr("About Music Player"),
        tr("The Music Player example shows how to use Phonon - the multimedia"
           " framework that comes with Qt - to create a simple music player."));
}

//![9]
void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */)
{
    switch (newState) {
        case Phonon::ErrorState:
            if (mediaObject->errorType() == Phonon::FatalError) {
                QMessageBox::warning(this, tr("Fatal Error"),
                mediaObject->errorString());
            } else {
                QMessageBox::warning(this, tr("Error"),
                mediaObject->errorString());
            }
            break;
//![9]
//![10]
        case Phonon::PlayingState:
                playAction->setEnabled(false);
                pauseAction->setEnabled(true);
                stopAction->setEnabled(true);
                break;
        case Phonon::StoppedState:
                stopAction->setEnabled(false);
                playAction->setEnabled(true);
                pauseAction->setEnabled(false);
                timeLcd->display("00:00");
                break;
        case Phonon::PausedState:
                pauseAction->setEnabled(false);
                stopAction->setEnabled(true);
                playAction->setEnabled(true);
                break;
//![10]
        case Phonon::BufferingState:
                break;
        default:
            ;
    }
}

//![11]
void MainWindow::tick(qint64 time)
{
    QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);

    timeLcd->display(displayTime.toString("mm:ss"));
}
//![11]

//![12]
void MainWindow::tableClicked(int row, int /* column */)
{
    bool wasPlaying = mediaObject->state() == Phonon::PlayingState;

    mediaObject->stop();
    mediaObject->clearQueue();

    mediaObject->setCurrentSource(sources[row]);

    if (wasPlaying)
        mediaObject->play();
    else
        mediaObject->stop();
}
//![12]

//![13]
void MainWindow::sourceChanged(const Phonon::MediaSource &source)
{
    musicTable->selectRow(sources.indexOf(source));
    timeLcd->display("00:00");
}
//![13]

//![14]
void MainWindow::metaStateChanged(Phonon::State newState, Phonon::State /* oldState */)
{
    if (newState == Phonon::ErrorState) {
        QMessageBox::warning(this, tr("Error opening files"),
            metaInformationResolver->errorString());
        while (!sources.isEmpty() &&
               !(sources.takeLast() == metaInformationResolver->currentSource()));
        return;
    }

    if (newState != Phonon::StoppedState && newState != Phonon::PausedState)
        return;

    if (metaInformationResolver->currentSource().type() == Phonon::MediaSource::Invalid)
            return;

    QMap<QString, QString> metaData = metaInformationResolver->metaData();

    QString title = metaData.value("TITLE");
    if (title == "")
        title = metaInformationResolver->currentSource().fileName();

    QTableWidgetItem *titleItem = new QTableWidgetItem(title);
    titleItem->setFlags(titleItem->flags() ^ Qt::ItemIsEditable);
    QTableWidgetItem *artistItem = new QTableWidgetItem(metaData.value("ARTIST"));
    artistItem->setFlags(artistItem->flags() ^ Qt::ItemIsEditable);
    QTableWidgetItem *albumItem = new QTableWidgetItem(metaData.value("ALBUM"));
    albumItem->setFlags(albumItem->flags() ^ Qt::ItemIsEditable);
    QTableWidgetItem *yearItem = new QTableWidgetItem(metaData.value("DATE"));
    yearItem->setFlags(yearItem->flags() ^ Qt::ItemIsEditable);
//![14]

    int currentRow = musicTable->rowCount();
    musicTable->insertRow(currentRow);
    musicTable->setItem(currentRow, 0, titleItem);
    musicTable->setItem(currentRow, 1, artistItem);
    musicTable->setItem(currentRow, 2, albumItem);
    musicTable->setItem(currentRow, 3, yearItem);

//![15]
    if (musicTable->selectedItems().isEmpty()) {
        musicTable->selectRow(0);
        mediaObject->setCurrentSource(metaInformationResolver->currentSource());
    }

    Phonon::MediaSource source = metaInformationResolver->currentSource();
    int index = sources.indexOf(metaInformationResolver->currentSource()) + 1;
    if (sources.size() > index) {
        metaInformationResolver->setCurrentSource(sources.at(index));
    }
    else {
        musicTable->resizeColumnsToContents();
        if (musicTable->columnWidth(0) > 300)
            musicTable->setColumnWidth(0, 300);
    }
}
//![15]

//![16]
void MainWindow::aboutToFinish()
{
    int index = sources.indexOf(mediaObject->currentSource()) + 1;
    if (sources.size() > index) {
        mediaObject->enqueue(sources.at(index));
    }
}
//![16]

void MainWindow::setupActions()
{
    playAction = new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("Play"), this);
    playAction->setShortcut(tr("Crl+P"));
    playAction->setDisabled(true);
    pauseAction = new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("Pause"), this);
    pauseAction->setShortcut(tr("Ctrl+A"));
    pauseAction->setDisabled(true);
    stopAction = new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("Stop"), this);
    stopAction->setShortcut(tr("Ctrl+S"));
    stopAction->setDisabled(true);
    nextAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipForward), tr("Next"), this);
    nextAction->setShortcut(tr("Ctrl+N"));
    previousAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipBackward), tr("Previous"), this);
    previousAction->setShortcut(tr("Ctrl+R"));
    addFilesAction = new QAction(tr("Add &Files"), this);
    addFilesAction->setShortcut(tr("Ctrl+F"));
    exitAction = new QAction(tr("E&xit"), this);
    exitAction->setShortcuts(QKeySequence::Quit);
    aboutAction = new QAction(tr("A&bout"), this);
    aboutAction->setShortcut(tr("Ctrl+B"));
    aboutQtAction = new QAction(tr("About &Qt"), this);
    aboutQtAction->setShortcut(tr("Ctrl+Q"));

//![5]
    connect(playAction, SIGNAL(triggered()), mediaObject, SLOT(play()));
    connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()) );
    connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop()));
//![5]
    connect(addFilesAction, SIGNAL(triggered()), this, SLOT(addFiles()));
    connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
    connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
    connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void MainWindow::setupMenus()
{
    QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(addFilesAction);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAction);

    QMenu *aboutMenu = menuBar()->addMenu(tr("&Help"));
    aboutMenu->addAction(aboutAction);
    aboutMenu->addAction(aboutQtAction);
}

//![3]
void MainWindow::setupUi()
{
//![3]
    QToolBar *bar = new QToolBar;

    bar->addAction(playAction);
    bar->addAction(pauseAction);
    bar->addAction(stopAction);

//![4]
    seekSlider = new Phonon::SeekSlider(this);
    seekSlider->setMediaObject(mediaObject);

    volumeSlider = new Phonon::VolumeSlider(this);
    volumeSlider->setAudioOutput(audioOutput);
//![4]
    volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);

    QLabel *volumeLabel = new QLabel;
    volumeLabel->setPixmap(QPixmap("images/volume.png"));

    QPalette palette;
    palette.setBrush(QPalette::Light, Qt::darkGray);

    timeLcd = new QLCDNumber;
    timeLcd->setPalette(palette);

    QStringList headers;
    headers << tr("Title") << tr("Artist") << tr("Album") << tr("Year");

    musicTable = new QTableWidget(0, 4);
    musicTable->setHorizontalHeaderLabels(headers);
    musicTable->setSelectionMode(QAbstractItemView::SingleSelection);
    musicTable->setSelectionBehavior(QAbstractItemView::SelectRows);
    connect(musicTable, SIGNAL(cellPressed(int, int)),
            this, SLOT(tableClicked(int, int)));

    QHBoxLayout *seekerLayout = new QHBoxLayout;
    seekerLayout->addWidget(seekSlider);
    seekerLayout->addWidget(timeLcd);

    QHBoxLayout *playbackLayout = new QHBoxLayout;
    playbackLayout->addWidget(bar);
    playbackLayout->addStretch();
    playbackLayout->addWidget(volumeLabel);
    playbackLayout->addWidget(volumeSlider);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(musicTable);
    mainLayout->addLayout(seekerLayout);
    mainLayout->addLayout(playbackLayout);

    QWidget *widget = new QWidget;
    widget->setLayout(mainLayout);

    setCentralWidget(widget);
    setWindowTitle("Phonon Music Player");
}

<commit_msg>unwarn<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
***************************************************************************/

#include <QtGui>

#include "mainwindow.h"

//![0]
MainWindow::MainWindow()
{
    audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
    mediaObject = new Phonon::MediaObject(this);
    metaInformationResolver = new Phonon::MediaObject(this);

    mediaObject->setTickInterval(1000);
//![0]
//![2]
    connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
    connect(metaInformationResolver, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
            this, SLOT(metaStateChanged(Phonon::State, Phonon::State)));
    connect(mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)),
            this, SLOT(sourceChanged(const Phonon::MediaSource &)));
    connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
//![2]

//![1]
    Phonon::createPath(mediaObject, audioOutput);
//![1]

    setupActions();
    setupMenus();
    setupUi();
    timeLcd->display("00:00");
}

//![6]
void MainWindow::addFiles()
{
    QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Music Files"),
        QDesktopServices::storageLocation(QDesktopServices::MusicLocation));

    if (files.isEmpty())
        return;

    int index = sources.size();
    foreach (QString string, files) {
            Phonon::MediaSource source(string);

        sources.append(source);
    }
    if (!sources.isEmpty())
        metaInformationResolver->setCurrentSource(sources.at(index));

}
//![6]

void MainWindow::about()
{
    QMessageBox::information(this, tr("About Music Player"),
        tr("The Music Player example shows how to use Phonon - the multimedia"
           " framework that comes with Qt - to create a simple music player."));
}

//![9]
void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */)
{
    switch (newState) {
        case Phonon::ErrorState:
            if (mediaObject->errorType() == Phonon::FatalError) {
                QMessageBox::warning(this, tr("Fatal Error"),
                mediaObject->errorString());
            } else {
                QMessageBox::warning(this, tr("Error"),
                mediaObject->errorString());
            }
            break;
//![9]
//![10]
        case Phonon::PlayingState:
                playAction->setEnabled(false);
                pauseAction->setEnabled(true);
                stopAction->setEnabled(true);
                break;
        case Phonon::StoppedState:
                stopAction->setEnabled(false);
                playAction->setEnabled(true);
                pauseAction->setEnabled(false);
                timeLcd->display("00:00");
                break;
        case Phonon::PausedState:
                pauseAction->setEnabled(false);
                stopAction->setEnabled(true);
                playAction->setEnabled(true);
                break;
//![10]
        case Phonon::BufferingState:
                break;
        default:
            ;
    }
}

//![11]
void MainWindow::tick(qint64 time)
{
    QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);

    timeLcd->display(displayTime.toString("mm:ss"));
}
//![11]

//![12]
void MainWindow::tableClicked(int row, int /* column */)
{
    bool wasPlaying = mediaObject->state() == Phonon::PlayingState;

    mediaObject->stop();
    mediaObject->clearQueue();

    mediaObject->setCurrentSource(sources[row]);

    if (wasPlaying)
        mediaObject->play();
    else
        mediaObject->stop();
}
//![12]

//![13]
void MainWindow::sourceChanged(const Phonon::MediaSource &source)
{
    musicTable->selectRow(sources.indexOf(source));
    timeLcd->display("00:00");
}
//![13]

//![14]
void MainWindow::metaStateChanged(Phonon::State newState, Phonon::State /* oldState */)
{
    if (newState == Phonon::ErrorState) {
        QMessageBox::warning(this, tr("Error opening files"),
            metaInformationResolver->errorString());
        while (!sources.isEmpty() &&
               !(sources.takeLast() == metaInformationResolver->currentSource())) /* loop */;
        return;
    }

    if (newState != Phonon::StoppedState && newState != Phonon::PausedState)
        return;

    if (metaInformationResolver->currentSource().type() == Phonon::MediaSource::Invalid)
            return;

    QMap<QString, QString> metaData = metaInformationResolver->metaData();

    QString title = metaData.value("TITLE");
    if (title == "")
        title = metaInformationResolver->currentSource().fileName();

    QTableWidgetItem *titleItem = new QTableWidgetItem(title);
    titleItem->setFlags(titleItem->flags() ^ Qt::ItemIsEditable);
    QTableWidgetItem *artistItem = new QTableWidgetItem(metaData.value("ARTIST"));
    artistItem->setFlags(artistItem->flags() ^ Qt::ItemIsEditable);
    QTableWidgetItem *albumItem = new QTableWidgetItem(metaData.value("ALBUM"));
    albumItem->setFlags(albumItem->flags() ^ Qt::ItemIsEditable);
    QTableWidgetItem *yearItem = new QTableWidgetItem(metaData.value("DATE"));
    yearItem->setFlags(yearItem->flags() ^ Qt::ItemIsEditable);
//![14]

    int currentRow = musicTable->rowCount();
    musicTable->insertRow(currentRow);
    musicTable->setItem(currentRow, 0, titleItem);
    musicTable->setItem(currentRow, 1, artistItem);
    musicTable->setItem(currentRow, 2, albumItem);
    musicTable->setItem(currentRow, 3, yearItem);

//![15]
    if (musicTable->selectedItems().isEmpty()) {
        musicTable->selectRow(0);
        mediaObject->setCurrentSource(metaInformationResolver->currentSource());
    }

    Phonon::MediaSource source = metaInformationResolver->currentSource();
    int index = sources.indexOf(metaInformationResolver->currentSource()) + 1;
    if (sources.size() > index) {
        metaInformationResolver->setCurrentSource(sources.at(index));
    }
    else {
        musicTable->resizeColumnsToContents();
        if (musicTable->columnWidth(0) > 300)
            musicTable->setColumnWidth(0, 300);
    }
}
//![15]

//![16]
void MainWindow::aboutToFinish()
{
    int index = sources.indexOf(mediaObject->currentSource()) + 1;
    if (sources.size() > index) {
        mediaObject->enqueue(sources.at(index));
    }
}
//![16]

void MainWindow::setupActions()
{
    playAction = new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("Play"), this);
    playAction->setShortcut(tr("Crl+P"));
    playAction->setDisabled(true);
    pauseAction = new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("Pause"), this);
    pauseAction->setShortcut(tr("Ctrl+A"));
    pauseAction->setDisabled(true);
    stopAction = new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("Stop"), this);
    stopAction->setShortcut(tr("Ctrl+S"));
    stopAction->setDisabled(true);
    nextAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipForward), tr("Next"), this);
    nextAction->setShortcut(tr("Ctrl+N"));
    previousAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipBackward), tr("Previous"), this);
    previousAction->setShortcut(tr("Ctrl+R"));
    addFilesAction = new QAction(tr("Add &Files"), this);
    addFilesAction->setShortcut(tr("Ctrl+F"));
    exitAction = new QAction(tr("E&xit"), this);
    exitAction->setShortcuts(QKeySequence::Quit);
    aboutAction = new QAction(tr("A&bout"), this);
    aboutAction->setShortcut(tr("Ctrl+B"));
    aboutQtAction = new QAction(tr("About &Qt"), this);
    aboutQtAction->setShortcut(tr("Ctrl+Q"));

//![5]
    connect(playAction, SIGNAL(triggered()), mediaObject, SLOT(play()));
    connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()) );
    connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop()));
//![5]
    connect(addFilesAction, SIGNAL(triggered()), this, SLOT(addFiles()));
    connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
    connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
    connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void MainWindow::setupMenus()
{
    QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(addFilesAction);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAction);

    QMenu *aboutMenu = menuBar()->addMenu(tr("&Help"));
    aboutMenu->addAction(aboutAction);
    aboutMenu->addAction(aboutQtAction);
}

//![3]
void MainWindow::setupUi()
{
//![3]
    QToolBar *bar = new QToolBar;

    bar->addAction(playAction);
    bar->addAction(pauseAction);
    bar->addAction(stopAction);

//![4]
    seekSlider = new Phonon::SeekSlider(this);
    seekSlider->setMediaObject(mediaObject);

    volumeSlider = new Phonon::VolumeSlider(this);
    volumeSlider->setAudioOutput(audioOutput);
//![4]
    volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);

    QLabel *volumeLabel = new QLabel;
    volumeLabel->setPixmap(QPixmap("images/volume.png"));

    QPalette palette;
    palette.setBrush(QPalette::Light, Qt::darkGray);

    timeLcd = new QLCDNumber;
    timeLcd->setPalette(palette);

    QStringList headers;
    headers << tr("Title") << tr("Artist") << tr("Album") << tr("Year");

    musicTable = new QTableWidget(0, 4);
    musicTable->setHorizontalHeaderLabels(headers);
    musicTable->setSelectionMode(QAbstractItemView::SingleSelection);
    musicTable->setSelectionBehavior(QAbstractItemView::SelectRows);
    connect(musicTable, SIGNAL(cellPressed(int, int)),
            this, SLOT(tableClicked(int, int)));

    QHBoxLayout *seekerLayout = new QHBoxLayout;
    seekerLayout->addWidget(seekSlider);
    seekerLayout->addWidget(timeLcd);

    QHBoxLayout *playbackLayout = new QHBoxLayout;
    playbackLayout->addWidget(bar);
    playbackLayout->addStretch();
    playbackLayout->addWidget(volumeLabel);
    playbackLayout->addWidget(volumeSlider);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(musicTable);
    mainLayout->addLayout(seekerLayout);
    mainLayout->addLayout(playbackLayout);

    QWidget *widget = new QWidget;
    widget->setLayout(mainLayout);

    setCentralWidget(widget);
    setWindowTitle("Phonon Music Player");
}

<|endoftext|>


<commit_before>// Copyright (c) 2010 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/dom_ui/dom_ui_favicon_source.h"

#include "app/resource_bundle.h"
#include "base/callback.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/common/url_constants.h"
#include "grit/app_resources.h"

DOMUIFavIconSource::DOMUIFavIconSource(Profile* profile)
    : DataSource(chrome::kChromeUIFavIconHost, MessageLoop::current()),
      profile_(profile) {
}

DOMUIFavIconSource::~DOMUIFavIconSource() {
}

void DOMUIFavIconSource::StartDataRequest(const std::string& path,
                                          bool is_off_the_record,
                                          int request_id) {
  FaviconService* favicon_service =
      profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
  if (favicon_service) {
    FaviconService::Handle handle;
    if (path.empty()) {
      SendDefaultResponse(request_id);
      return;
    }

    if (path.size() > 8 && path.substr(0, 8) == "iconurl/") {
      handle = favicon_service->GetFavicon(
          GURL(path.substr(8)),
          &cancelable_consumer_,
          NewCallback(this, &DOMUIFavIconSource::OnFavIconDataAvailable));
    } else {
      handle = favicon_service->GetFaviconForURL(
          GURL(path),
          &cancelable_consumer_,
          NewCallback(this, &DOMUIFavIconSource::OnFavIconDataAvailable));
    }
    // Attach the ChromeURLDataManager request ID to the history request.
    cancelable_consumer_.SetClientData(favicon_service, handle, request_id);
  } else {
    SendResponse(request_id, NULL);
  }
}

std::string DOMUIFavIconSource::GetMimeType(const std::string&) const {
  // We need to explicitly return a mime type, otherwise if the user tries to
  // drag the image they get no extension.
  return "image/png";
}

void DOMUIFavIconSource::OnFavIconDataAvailable(
    FaviconService::Handle request_handle,
    bool know_favicon,
    scoped_refptr<RefCountedMemory> data,
    bool expired,
    GURL icon_url) {
  FaviconService* favicon_service =
      profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
  int request_id = cancelable_consumer_.GetClientData(favicon_service,
                                                      request_handle);

  if (know_favicon && data.get() && data->size()) {
    // Forward the data along to the networking system.
    SendResponse(request_id, data);
  } else {
    SendDefaultResponse(request_id);
  }
}

void DOMUIFavIconSource::SendDefaultResponse(int request_id) {
  if (!default_favicon_.get()) {
    default_favicon_ =
        ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
            IDR_DEFAULT_FAVICON);
  }

  SendResponse(request_id, default_favicon_);
}
<commit_msg>DOMUIFavIconSource should use original profile since the incognito profile might go away.<commit_after>// Copyright (c) 2010 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/dom_ui/dom_ui_favicon_source.h"

#include "app/resource_bundle.h"
#include "base/callback.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/common/url_constants.h"
#include "grit/app_resources.h"

DOMUIFavIconSource::DOMUIFavIconSource(Profile* profile)
    : DataSource(chrome::kChromeUIFavIconHost, MessageLoop::current()),
      profile_(profile->GetOriginalProfile()) {
}

DOMUIFavIconSource::~DOMUIFavIconSource() {
}

void DOMUIFavIconSource::StartDataRequest(const std::string& path,
                                          bool is_off_the_record,
                                          int request_id) {
  FaviconService* favicon_service =
      profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
  if (favicon_service) {
    FaviconService::Handle handle;
    if (path.empty()) {
      SendDefaultResponse(request_id);
      return;
    }

    if (path.size() > 8 && path.substr(0, 8) == "iconurl/") {
      handle = favicon_service->GetFavicon(
          GURL(path.substr(8)),
          &cancelable_consumer_,
          NewCallback(this, &DOMUIFavIconSource::OnFavIconDataAvailable));
    } else {
      handle = favicon_service->GetFaviconForURL(
          GURL(path),
          &cancelable_consumer_,
          NewCallback(this, &DOMUIFavIconSource::OnFavIconDataAvailable));
    }
    // Attach the ChromeURLDataManager request ID to the history request.
    cancelable_consumer_.SetClientData(favicon_service, handle, request_id);
  } else {
    SendResponse(request_id, NULL);
  }
}

std::string DOMUIFavIconSource::GetMimeType(const std::string&) const {
  // We need to explicitly return a mime type, otherwise if the user tries to
  // drag the image they get no extension.
  return "image/png";
}

void DOMUIFavIconSource::OnFavIconDataAvailable(
    FaviconService::Handle request_handle,
    bool know_favicon,
    scoped_refptr<RefCountedMemory> data,
    bool expired,
    GURL icon_url) {
  FaviconService* favicon_service =
      profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
  int request_id = cancelable_consumer_.GetClientData(favicon_service,
                                                      request_handle);

  if (know_favicon && data.get() && data->size()) {
    // Forward the data along to the networking system.
    SendResponse(request_id, data);
  } else {
    SendDefaultResponse(request_id);
  }
}

void DOMUIFavIconSource::SendDefaultResponse(int request_id) {
  if (!default_favicon_.get()) {
    default_favicon_ =
        ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
            IDR_DEFAULT_FAVICON);
  }

  SendResponse(request_id, default_favicon_);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/ui/webui/constrained_html_ui.h"

#include "base/lazy_instance.h"
#include "base/values.h"
#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/bindings_policy.h"

static base::LazyInstance<PropertyAccessor<ConstrainedHtmlUIDelegate*> >
    g_constrained_html_ui_property_accessor(base::LINKER_INITIALIZED);

ConstrainedHtmlUI::ConstrainedHtmlUI(TabContents* contents)
    : ChromeWebUI(contents) {
}

ConstrainedHtmlUI::~ConstrainedHtmlUI() {
}

void ConstrainedHtmlUI::RenderViewCreated(
    RenderViewHost* render_view_host) {
  ConstrainedHtmlUIDelegate* delegate = GetConstrainedDelegate();
  if (!delegate)
    return;

  HtmlDialogUIDelegate* dialog_delegate = delegate->GetHtmlDialogUIDelegate();
  std::vector<WebUIMessageHandler*> handlers;
  dialog_delegate->GetWebUIMessageHandlers(&handlers);
  render_view_host->SetWebUIProperty("dialogArguments",
                                     dialog_delegate->GetDialogArgs());
  for (std::vector<WebUIMessageHandler*>::iterator it = handlers.begin();
       it != handlers.end(); ++it) {
    (*it)->Attach(this);
    AddMessageHandler(*it);
  }

  // Add a "DialogClose" callback which matches HTMLDialogUI behavior.
  RegisterMessageCallback("DialogClose",
      NewCallback(this, &ConstrainedHtmlUI::OnDialogCloseMessage));
}

void ConstrainedHtmlUI::OnDialogCloseMessage(const ListValue* args) {
  ConstrainedHtmlUIDelegate* delegate = GetConstrainedDelegate();
  if (!delegate)
    return;

  std::string json_retval;
  if (!args->GetString(0, &json_retval))
    NOTREACHED() << "Could not read JSON argument";
  delegate->GetHtmlDialogUIDelegate()->OnDialogClosed(json_retval);
  delegate->OnDialogCloseFromWebUI();
}

ConstrainedHtmlUIDelegate*
    ConstrainedHtmlUI::GetConstrainedDelegate() {
  ConstrainedHtmlUIDelegate** property =
      GetPropertyAccessor().GetProperty(tab_contents()->property_bag());
  return property ? *property : NULL;
}

// static
PropertyAccessor<ConstrainedHtmlUIDelegate*>&
    ConstrainedHtmlUI::GetPropertyAccessor() {
  return g_constrained_html_ui_property_accessor.Get();
}
<commit_msg>Allow no arguments in ConstrainedHtmlUI::OnDialogClose().<commit_after>// Copyright (c) 2011 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/ui/webui/constrained_html_ui.h"

#include "base/lazy_instance.h"
#include "base/values.h"
#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/bindings_policy.h"

static base::LazyInstance<PropertyAccessor<ConstrainedHtmlUIDelegate*> >
    g_constrained_html_ui_property_accessor(base::LINKER_INITIALIZED);

ConstrainedHtmlUI::ConstrainedHtmlUI(TabContents* contents)
    : ChromeWebUI(contents) {
}

ConstrainedHtmlUI::~ConstrainedHtmlUI() {
}

void ConstrainedHtmlUI::RenderViewCreated(
    RenderViewHost* render_view_host) {
  ConstrainedHtmlUIDelegate* delegate = GetConstrainedDelegate();
  if (!delegate)
    return;

  HtmlDialogUIDelegate* dialog_delegate = delegate->GetHtmlDialogUIDelegate();
  std::vector<WebUIMessageHandler*> handlers;
  dialog_delegate->GetWebUIMessageHandlers(&handlers);
  render_view_host->SetWebUIProperty("dialogArguments",
                                     dialog_delegate->GetDialogArgs());
  for (std::vector<WebUIMessageHandler*>::iterator it = handlers.begin();
       it != handlers.end(); ++it) {
    (*it)->Attach(this);
    AddMessageHandler(*it);
  }

  // Add a "DialogClose" callback which matches HTMLDialogUI behavior.
  RegisterMessageCallback("DialogClose",
      NewCallback(this, &ConstrainedHtmlUI::OnDialogCloseMessage));
}

void ConstrainedHtmlUI::OnDialogCloseMessage(const ListValue* args) {
  ConstrainedHtmlUIDelegate* delegate = GetConstrainedDelegate();
  if (!delegate)
    return;

  std::string json_retval;
  if (!args->empty() && !args->GetString(0, &json_retval))
    NOTREACHED() << "Could not read JSON argument";
  delegate->GetHtmlDialogUIDelegate()->OnDialogClosed(json_retval);
  delegate->OnDialogCloseFromWebUI();
}

ConstrainedHtmlUIDelegate*
    ConstrainedHtmlUI::GetConstrainedDelegate() {
  ConstrainedHtmlUIDelegate** property =
      GetPropertyAccessor().GetProperty(tab_contents()->property_bag());
  return property ? *property : NULL;
}

// static
PropertyAccessor<ConstrainedHtmlUIDelegate*>&
    ConstrainedHtmlUI::GetPropertyAccessor() {
  return g_constrained_html_ui_property_accessor.Get();
}
<|endoftext|>


<commit_before>#include "calc.h"
#include "sevensegment.h"
#include "pocketcalculator.h"

#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

#include <string>
#include <sstream>
#include <limits>
#include <algorithm>

namespace calc_tests {
	constexpr int max { std::numeric_limits<int>::max() },
				  min { std::numeric_limits<int>::min() };
	void multiplies_positive_numbers() {
		ASSERT_EQUAL(20, calc(4, 5, '*'));
	}
	void multiplies_negative_with_positive_number() {
		ASSERT_EQUAL(-30, calc(-6, 5, '*'));
	}
	void multiplies_negative_numbers() {
		ASSERT_EQUAL(20, calc(-4, -5, '*'));
	}
	void recognizes_overflows_when_multiplying() {
		calc(1, max, '*');
		calc(1, min, '*');
		calc(-1, max, '*');
		calc(-1, min+1, '*');
		calc(2, max/2, '*');
		calc(2, min/2, '*');
		calc(-2, max/2, '*');
		calc(-2, min/2+1, '*');

		ASSERT_THROWS(calc(4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(4, min/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, min/3, '*'), std::overflow_error);
	}
	void divides() {
		ASSERT_EQUAL(5, calc(60, 12, '/'));
		ASSERT_EQUAL(-3, calc(9, -3, '/'));
	}
	void throws_when_dividing_by_zero() {
		ASSERT_THROWS(calc(1, 0, '/'), std::domain_error);
	}
	void adds() {
		ASSERT_EQUAL(5, calc(2, 3, '+'));
		ASSERT_EQUAL(-10, calc(-6, -4, '+'));
	}
	void recognizes_overflows_when_adding() {
		calc(max, 0, '+'); // must not throw
		ASSERT_THROWS(calc(max, 1, '+'), std::overflow_error);
		calc(min, 0, '+'); // must not throw
		ASSERT_THROWS(calc(min, -1, '+'), std::overflow_error);
	}
	void subtracts() {
		ASSERT_EQUAL(17, calc(20, 3, '-'));
		ASSERT_EQUAL(-5, calc(-2, 3, '-'));
	}
	void recognizes_overflows_when_subtracting() {
		calc(max, 0, '-'); // must not throw
		ASSERT_THROWS(calc(max, -1, '-'), std::overflow_error);
		calc(min, 0, '-'); // must not throw
		ASSERT_THROWS(calc(min, 1, '-'), std::overflow_error);
	}
	void knows_modulo() {
		ASSERT_EQUAL(5, calc(15, 10, '%'));
		ASSERT_EQUAL(-5, calc(-15, 10, '%'));
	}
	void throws_when_modulo_zero() {
		ASSERT_THROWS(calc(10, 0, '%'), std::domain_error);
	}
	void throws_when_given_invalid_operator() {
		ASSERT_THROWS(calc(1, 1, '^'), std::runtime_error);
	}

	void takes_term_from_istream() {
		std::istringstream term_stream { "1+1" };
		int result = calc(term_stream);
		ASSERT_EQUAL(2, result);
	}

	const std::vector<std::string> invalid_terms {
        "foobar",
        "3+2-",
        "1",
        "8--",
        "*",
        "4%%6",
        "3//7",
	};

    void throws_when_given_invalid_term() {
		for(auto const term : invalid_terms) {
			std::istringstream term_stream { term };
			ASSERT_THROWS(calc(term_stream), std::exception); // TODO: more specific?
		}
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(multiplies_positive_numbers));
		s.push_back(CUTE(multiplies_negative_with_positive_number));
		s.push_back(CUTE(multiplies_negative_numbers));
		s.push_back(CUTE(recognizes_overflows_when_multiplying));
		s.push_back(CUTE(divides));
		s.push_back(CUTE(throws_when_dividing_by_zero));
		s.push_back(CUTE(adds));
		s.push_back(CUTE(recognizes_overflows_when_adding));
		s.push_back(CUTE(subtracts));
		s.push_back(CUTE(recognizes_overflows_when_subtracting));
		s.push_back(CUTE(throws_when_given_invalid_operator));
		s.push_back(CUTE(knows_modulo));
		s.push_back(CUTE(throws_when_modulo_zero));
		s.push_back(CUTE(takes_term_from_istream));
		s.push_back(CUTE(throws_when_given_invalid_term));
	}
}

namespace sevensegment_tests {
	const std::string large_8 {
		" - \n"
		"| |\n"
		" - \n"
		"| |\n"
		" - \n"
	};
	const std::string large_1 {
		"   \n"
		"  |\n"
		"   \n"
		"  |\n"
		"   \n"
	};
	const std::string large_3_scale2 {
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
	};

	void prints_digit() {
		std::ostringstream output {};
		sevensegment::printLargeDigit(8, output);
		ASSERT_EQUAL(large_8, output.str());
		output.str("");
		sevensegment::printLargeDigit(1, output);
		ASSERT_EQUAL(large_1, output.str());
	}
	void prints_scaled_digit() {
		std::ostringstream output {};
		sevensegment::printLargeDigit(3, output, 2);
		ASSERT_EQUAL(large_3_scale2, output.str());
	}
	void throws_when_digit_out_of_range() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeDigit(10,output),
				std::out_of_range);
	}
	void throws_when_scale_out_of_range() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeDigit(5,output, 0),
				std::range_error);
	}

	const std::string large_number {
		" -     -  -    \n"
		"|  | |  |  |  |\n"
		" -  -  -  -    \n"
		"  |  |  ||    |\n"
		" -     -  -    \n"
	};

	const std::string large_negative_number {
	"    -  - \n"
	"     |  |\n"
	" -  -  - \n"
	"     |  |\n"
	"    -  - \n"
	};

	void prints_number() {
		std::ostringstream output {};
		sevensegment::printLargeNumber(54321, output);
		ASSERT_EQUAL(large_number, output.str());
	}

	void prints_negative_number() {
		std::ostringstream output {};
		sevensegment::printLargeNumber(-33, output);
		ASSERT_EQUAL(large_negative_number, output.str());
	}

	const std::string large_error {
		" -             \n"
		"|              \n"
		" -  -  -  -  - \n"
		"|  |  |  | ||  \n"
		" -        -    \n"
	};

	void prints_error() {
		std::ostringstream output {};
		sevensegment::printLargeError(output);
		ASSERT_EQUAL(large_error, output.str());
	}

	void throws_when_too_many_digits_for_display() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeNumber(100000000, output, 1),
				std::overflow_error);
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(prints_digit));
		s.push_back(CUTE(prints_scaled_digit));
		s.push_back(CUTE(throws_when_digit_out_of_range));
		s.push_back(CUTE(throws_when_scale_out_of_range));
		s.push_back(CUTE(prints_number));
		s.push_back(CUTE(prints_negative_number));
		s.push_back(CUTE(prints_error));
		s.push_back(CUTE(throws_when_too_many_digits_for_display));
	}
}

namespace pocketcalculator_tests {
	const std::string large_output {
		" --   -- \n"
		"   |    |\n"
		"   |    |\n"
		" --   -- \n"
		"|    |   \n"
		"|    |   \n"
		" --   -- \n"
	};

	bool includes(const std::string str, const std::string substr) {
		return (str.find(substr) != std::string::npos);
	}

	void gets_term_and_prints_result() {
		std::ostringstream output {};
		std::istringstream input { "2+20" };
		pocketcalculator::start(input, output);
		ASSERT(includes(output.str(), large_output));
	}

	const std::string error_scale2 {
		" --                     \n"
		"|                       \n"
		"|                       \n"
		" --   --   --   --   -- \n"
		"|    |    |    |  | |   \n"
		"|    |    |    |  | |   \n"
		" --             --      \n"
	};

	void prints_error_on_invalid_input() {
		for(auto const term : calc_tests::invalid_terms) {

			std::ostringstream output {};
			std::istringstream input { term };
			pocketcalculator::start(input, output);
			ASSERT(includes(output.str(), error_scale2));
		}
	}

	const std::string large_2_scale4 {
		" ---- \n"
		"     |\n"
		"     |\n"
		"     |\n"
		"     |\n"
		" ---- \n"
		"|     \n"
		"|     \n"
		"|     \n"
		"|     \n"
		" ---- \n"
	};

	void scales() {
		std::ostringstream output {};
		std::istringstream input {"1+1"};
		pocketcalculator::start(input, output, 4);
		ASSERT(includes(output.str(), large_2_scale4));
	}

	const std::string large_2_scale2 {
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
		"|   \n"
		"|   \n"
		" -- \n"
	};

	void uses_default_scale_when_scale_omitted() {
		std::ostringstream output {};
		std::istringstream input {"1+1"};
		pocketcalculator::start(input, output);
		ASSERT(includes(output.str(), large_2_scale2));
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(gets_term_and_prints_result));
		s.push_back(CUTE(prints_error_on_invalid_input));
		s.push_back(CUTE(scales));
		s.push_back(CUTE(uses_default_scale_when_scale_omitted));
	}

	// TODO: add env scale test
}

void runAllTests(int argc, char const *argv[]){
	cute::suite s {};
	calc_tests::add_tests_to_suite(s);
	sevensegment_tests::add_tests_to_suite(s);
	pocketcalculator_tests::add_tests_to_suite(s);

	cute::xml_file_opener xmlfile(argc,argv);
	cute::xml_listener<cute::ide_listener<> >  lis(xmlfile.out);
	cute::makeRunner(lis,argc,argv)(s, "AllTests");
}

int main(int argc, char const *argv[]){
    runAllTests(argc,argv);
    return 0;
}

<commit_msg>add TODO<commit_after>#include "calc.h"
#include "sevensegment.h"
#include "pocketcalculator.h"

#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

#include <string>
#include <sstream>
#include <limits>
#include <algorithm>

namespace calc_tests {
	constexpr int max { std::numeric_limits<int>::max() },
				  min { std::numeric_limits<int>::min() };
	void multiplies_positive_numbers() {
		ASSERT_EQUAL(20, calc(4, 5, '*'));
	}
	void multiplies_negative_with_positive_number() {
		ASSERT_EQUAL(-30, calc(-6, 5, '*'));
	}
	void multiplies_negative_numbers() {
		ASSERT_EQUAL(20, calc(-4, -5, '*'));
	}
	void recognizes_overflows_when_multiplying() {
		calc(1, max, '*');
		calc(1, min, '*');
		calc(-1, max, '*');
		calc(-1, min+1, '*');
		calc(2, max/2, '*');
		calc(2, min/2, '*');
		calc(-2, max/2, '*');
		calc(-2, min/2+1, '*');

		ASSERT_THROWS(calc(4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(4, min/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, min/3, '*'), std::overflow_error);
	}
	void divides() {
		ASSERT_EQUAL(5, calc(60, 12, '/'));
		ASSERT_EQUAL(-3, calc(9, -3, '/'));
	}
	void throws_when_dividing_by_zero() {
		ASSERT_THROWS(calc(1, 0, '/'), std::domain_error);
	}
	void adds() {
		ASSERT_EQUAL(5, calc(2, 3, '+'));
		ASSERT_EQUAL(-10, calc(-6, -4, '+'));
	}
	void recognizes_overflows_when_adding() {
		calc(max, 0, '+'); // must not throw
		ASSERT_THROWS(calc(max, 1, '+'), std::overflow_error);
		calc(min, 0, '+'); // must not throw
		ASSERT_THROWS(calc(min, -1, '+'), std::overflow_error);
	}
	void subtracts() {
		ASSERT_EQUAL(17, calc(20, 3, '-'));
		ASSERT_EQUAL(-5, calc(-2, 3, '-'));
	}
	void recognizes_overflows_when_subtracting() {
		calc(max, 0, '-'); // must not throw
		ASSERT_THROWS(calc(max, -1, '-'), std::overflow_error);
		calc(min, 0, '-'); // must not throw
		ASSERT_THROWS(calc(min, 1, '-'), std::overflow_error);
	}
	void knows_modulo() {
		ASSERT_EQUAL(5, calc(15, 10, '%'));
		ASSERT_EQUAL(-5, calc(-15, 10, '%'));
	}
	void throws_when_modulo_zero() {
		ASSERT_THROWS(calc(10, 0, '%'), std::domain_error);
	}
	void throws_when_given_invalid_operator() {
		ASSERT_THROWS(calc(1, 1, '^'), std::runtime_error);
	}

	void takes_term_from_istream() {
		std::istringstream term_stream { "1+1" };
		int result = calc(term_stream);
		ASSERT_EQUAL(2, result);
	}

	const std::vector<std::string> invalid_terms {
        "foobar",
        "3+2-",
        "1",
        "8--",
        "*",
        "4%%6",
        "3//7",
	};

    void throws_when_given_invalid_term() {
		for(auto const term : invalid_terms) {
			std::istringstream term_stream { term };
			ASSERT_THROWS(calc(term_stream), std::exception); // TODO: more specific?
		}
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(multiplies_positive_numbers));
		s.push_back(CUTE(multiplies_negative_with_positive_number));
		s.push_back(CUTE(multiplies_negative_numbers));
		s.push_back(CUTE(recognizes_overflows_when_multiplying));
		s.push_back(CUTE(divides));
		s.push_back(CUTE(throws_when_dividing_by_zero));
		s.push_back(CUTE(adds));
		s.push_back(CUTE(recognizes_overflows_when_adding));
		s.push_back(CUTE(subtracts));
		s.push_back(CUTE(recognizes_overflows_when_subtracting));
		s.push_back(CUTE(throws_when_given_invalid_operator));
		s.push_back(CUTE(knows_modulo));
		s.push_back(CUTE(throws_when_modulo_zero));
		s.push_back(CUTE(takes_term_from_istream));
		s.push_back(CUTE(throws_when_given_invalid_term));
	}
}

namespace sevensegment_tests {
	const std::string large_8 {
		" - \n"
		"| |\n"
		" - \n"
		"| |\n"
		" - \n"
	};
	const std::string large_1 {
		"   \n"
		"  |\n"
		"   \n"
		"  |\n"
		"   \n"
	};
	const std::string large_3_scale2 {
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
	};

	void prints_digit() {
		std::ostringstream output {};
		sevensegment::printLargeDigit(8, output);
		ASSERT_EQUAL(large_8, output.str());
		output.str("");
		sevensegment::printLargeDigit(1, output);
		ASSERT_EQUAL(large_1, output.str());
	}
	void prints_scaled_digit() {
		std::ostringstream output {};
		sevensegment::printLargeDigit(3, output, 2);
		ASSERT_EQUAL(large_3_scale2, output.str());
	}
	void throws_when_digit_out_of_range() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeDigit(10,output),
				std::out_of_range);
	}
	void throws_when_scale_out_of_range() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeDigit(5,output, 0),
				std::range_error);
	}

	const std::string large_number {
		" -     -  -    \n"
		"|  | |  |  |  |\n"
		" -  -  -  -    \n"
		"  |  |  ||    |\n"
		" -     -  -    \n"
	};

	const std::string large_negative_number {
	"    -  - \n"
	"     |  |\n"
	" -  -  - \n"
	"     |  |\n"
	"    -  - \n"
	};

	void prints_number() {
		std::ostringstream output {};
		sevensegment::printLargeNumber(54321, output);
		ASSERT_EQUAL(large_number, output.str());
	}

	void prints_negative_number() {
		std::ostringstream output {};
		sevensegment::printLargeNumber(-33, output);
		ASSERT_EQUAL(large_negative_number, output.str());
	}

	const std::string large_error {
		" -             \n"
		"|              \n"
		" -  -  -  -  - \n"
		"|  |  |  | ||  \n"
		" -        -    \n"
	};

	void prints_error() {
		std::ostringstream output {};
		sevensegment::printLargeError(output);
		ASSERT_EQUAL(large_error, output.str());
	}

	void throws_when_too_many_digits_for_display() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeNumber(100000000, output, 1),
				std::overflow_error);
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(prints_digit));
		s.push_back(CUTE(prints_scaled_digit));
		s.push_back(CUTE(throws_when_digit_out_of_range));
		s.push_back(CUTE(throws_when_scale_out_of_range));
		s.push_back(CUTE(prints_number));
		s.push_back(CUTE(prints_negative_number));
		s.push_back(CUTE(prints_error));
		s.push_back(CUTE(throws_when_too_many_digits_for_display));
	}
}

namespace pocketcalculator_tests {
	const std::string large_output {
		" --   -- \n"
		"   |    |\n"
		"   |    |\n"
		" --   -- \n"
		"|    |   \n"
		"|    |   \n"
		" --   -- \n"
	};

	// TODO: we don't have a prompt anymore. so maybe this functionality is obsolete anyway
	bool includes(const std::string str, const std::string substr) {
		return (str.find(substr) != std::string::npos);
	}

	void gets_term_and_prints_result() {
		std::ostringstream output {};
		std::istringstream input { "2+20" };
		pocketcalculator::start(input, output);
		ASSERT(includes(output.str(), large_output));
	}

	const std::string error_scale2 {
		" --                     \n"
		"|                       \n"
		"|                       \n"
		" --   --   --   --   -- \n"
		"|    |    |    |  | |   \n"
		"|    |    |    |  | |   \n"
		" --             --      \n"
	};

	void prints_error_on_invalid_input() {
		for(auto const term : calc_tests::invalid_terms) {

			std::ostringstream output {};
			std::istringstream input { term };
			pocketcalculator::start(input, output);
			ASSERT(includes(output.str(), error_scale2));
		}
	}

	const std::string large_2_scale4 {
		" ---- \n"
		"     |\n"
		"     |\n"
		"     |\n"
		"     |\n"
		" ---- \n"
		"|     \n"
		"|     \n"
		"|     \n"
		"|     \n"
		" ---- \n"
	};

	void scales() {
		std::ostringstream output {};
		std::istringstream input {"1+1"};
		pocketcalculator::start(input, output, 4);
		ASSERT(includes(output.str(), large_2_scale4));
	}

	const std::string large_2_scale2 {
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
		"|   \n"
		"|   \n"
		" -- \n"
	};

	void uses_default_scale_when_scale_omitted() {
		std::ostringstream output {};
		std::istringstream input {"1+1"};
		pocketcalculator::start(input, output);
		ASSERT(includes(output.str(), large_2_scale2));
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(gets_term_and_prints_result));
		s.push_back(CUTE(prints_error_on_invalid_input));
		s.push_back(CUTE(scales));
		s.push_back(CUTE(uses_default_scale_when_scale_omitted));
	}

	// TODO: add env scale test
}

void runAllTests(int argc, char const *argv[]){
	cute::suite s {};
	calc_tests::add_tests_to_suite(s);
	sevensegment_tests::add_tests_to_suite(s);
	pocketcalculator_tests::add_tests_to_suite(s);

	cute::xml_file_opener xmlfile(argc,argv);
	cute::xml_listener<cute::ide_listener<> >  lis(xmlfile.out);
	cute::makeRunner(lis,argc,argv)(s, "AllTests");
}

int main(int argc, char const *argv[]){
    runAllTests(argc,argv);
    return 0;
}

<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "module.hh"
#include "agent.hh"
#include "log/logmanager.hh"
#include <sofia-sip/tport.h>
#include <sofia-sip/msg_addr.h>
#include <unordered_map>

using namespace ::std;

typedef struct DosContext {
	uint64_t recv_msg_count_since_last_check;
	double last_check_recv_msg_check_time;
	double packet_count_rate;
} DosContext;

class DoSProtection : public Module, ModuleToolbox {

  private:
	static ModuleInfo<DoSProtection> sInfo;
	int mTimePeriod;
	int mPacketRateLimit;
	int mBanTime;
	unordered_map<string, DosContext> mDosContexts;
	unordered_map<string, DosContext>::iterator mDOSHashtableIterator;

	void onDeclare(GenericStruct *module_config) {
		ConfigItemDescriptor configs[] = {
			{Integer, "time-period", "Number of milliseconds to consider to compute the packet rate", "3000"},
			{Integer, "packet-rate-limit", "Maximum packet rate in packets/seconds,  averaged over [time-period] "
										   "millisecond(s) to consider it as a DoS attack.",
			 "20"},
			{Integer, "ban-time", "Number of minutes to ban the ip/port using iptables (might be less because it justs "
								  "uses the minutes of the clock, not the seconds. So if the unban command is queued "
								  "at 13:11:56 and scheduled and the ban time is 1 minute, it will be executed at "
								  "13:12:00)",
			 "2"},
			config_item_end};
		module_config->get<ConfigBoolean>("enabled")->setDefault("true");
		module_config->addChildrenValues(configs);
	}

	void onLoad(const GenericStruct *mc) {
		mTimePeriod = mc->get<ConfigInt>("time-period")->read();
		mPacketRateLimit = mc->get<ConfigInt>("packet-rate-limit")->read();
		mBanTime = mc->get<ConfigInt>("ban-time")->read();
		mDOSHashtableIterator = mDosContexts.begin();

		tport_t *primaries = tport_primaries(nta_agent_tports(mAgent->getSofiaAgent()));
		if (primaries == NULL)
			LOGF("No sip transport defined.");
		for (tport_t *tport = primaries; tport != NULL; tport = tport_next(tport)) {
			tport_set_params(tport, TPTAG_DOS(mTimePeriod), TAG_END());
		}
		if (getuid() != 0) {
			LOGE("Flexisip not started with root privileges! iptables commands for DoS protection won't work.");
			return;
		}
	}

	void onUnload() {
	}

	void onIdle() {
		struct timeval now;
		double started_time_in_millis, time_elapsed;

		gettimeofday(&now, NULL);
		started_time_in_millis = now.tv_sec * 1000 + (now.tv_usec / 1000);

		if (mDOSHashtableIterator == mDosContexts.end()) {
			mDOSHashtableIterator = mDosContexts.begin();
		}
		for (; mDOSHashtableIterator != mDosContexts.end();) {
			double now_in_millis;
			DosContext dos = mDOSHashtableIterator->second;

			gettimeofday(&now, NULL);
			now_in_millis = now.tv_sec * 1000 + (now.tv_usec / 1000);
			time_elapsed = now_in_millis - dos.last_check_recv_msg_check_time;

			if (time_elapsed >= 3600 * 1000) { // If no message received in the past hour
				mDOSHashtableIterator = mDosContexts.erase(mDOSHashtableIterator);
			} else {
				++mDOSHashtableIterator;
			}

			if (now_in_millis - started_time_in_millis >= 100) { // Do not use more than 100ms to clean the hashtable
				LOGW("Started to clean dos hashtable %fms ago, let's stop for now a continue later",
					 now_in_millis - started_time_in_millis);
				break;
			}
		}
	}

	static void ban_ip_with_iptables(const char *ip, const char *port, const char *protocol, int ban_time) {
		char iptables_cmd[512];
		snprintf(iptables_cmd, sizeof(iptables_cmd), "iptables -A INPUT -p %s -s %s -m multiport --sports %s -j DROP "
													 "&& echo \"iptables -D INPUT -p %s -s %s -m multiport --sports %s "
													 "-j DROP\" | at now +%i minutes",
				 protocol, ip, port, protocol, ip, port, ban_time);
		if (system(iptables_cmd) != 0) {
			LOGW("iptables command failed: %s", strerror(errno));
		}
	}

	void onRequest(shared_ptr<RequestSipEvent> &ev) {
		shared_ptr<tport_t> inTport = ev->getIncomingTport();
		tport_t *tport = inTport.get();

		if (tport == NULL) {
			LOGE("Tport is null, can't check the packet count rate");
			return;
		}

		if (tport_is_udp(tport)) { // Sofia doesn't create a secondary tport for udp, so it will ban the primary and we
								   // don't want that
			shared_ptr<MsgSip> msg = ev->getMsgSip();
			MsgSip *msgSip = msg.get();
			su_sockaddr_t su[1];
			socklen_t len = sizeof su;
			sockaddr *addr = NULL;
			char ip[NI_MAXHOST], port[NI_MAXSERV];
			int err;

			msg_get_address(msgSip->getMsg(), su, &len);
			addr = &(su[0].su_sa);

			if ((err = getnameinfo(addr, len, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV)) ==
				0) {
				string id = string(ip) + ":" + string(port);
				struct timeval now;
				DosContext &dosContext = mDosContexts[id];
				double now_in_millis, time_elapsed;

				dosContext.recv_msg_count_since_last_check++;
				gettimeofday(&now, NULL);
				now_in_millis = now.tv_sec * 1000 + (now.tv_usec / 1000);
				if (dosContext.last_check_recv_msg_check_time == 0) {
					dosContext.last_check_recv_msg_check_time = now_in_millis;
				}

				time_elapsed = now_in_millis - dosContext.last_check_recv_msg_check_time;
				if (time_elapsed < 0) {
					dosContext.packet_count_rate = 0;
					dosContext.recv_msg_count_since_last_check = 0;
					dosContext.last_check_recv_msg_check_time = now_in_millis;
				} else if (time_elapsed >= mTimePeriod) {
					dosContext.packet_count_rate = dosContext.recv_msg_count_since_last_check / time_elapsed * 1000;
					dosContext.recv_msg_count_since_last_check = 0;
					dosContext.last_check_recv_msg_check_time = now_in_millis;
				}

				if (dosContext.packet_count_rate >= mPacketRateLimit) {
					LOGW("Packet count rate (%f) >= limit (%i), blocking ip/port %s/%s on protocol udp for %i minutes",
						 dosContext.packet_count_rate, mPacketRateLimit, ip, port, mBanTime);
					ban_ip_with_iptables(ip, port, "udp", mBanTime);
					dosContext.packet_count_rate = 0; // Reset it to not add the iptables rule twice by mistake
					ev->terminateProcessing(); // the event is discarded
				}
			} else {
				LOGW("getnameinfo() failed: %s", gai_strerror(err));
			}
		} else {
			float packet_count_rate = tport_get_packet_count_rate(tport);
			if (packet_count_rate >= mPacketRateLimit) {
				sockaddr *addr = tport_get_address(tport)->ai_addr;
				socklen_t len = tport_get_address(tport)->ai_addrlen;
				char ip[NI_MAXHOST], port[NI_MAXSERV];
				int err;

				if ((err = getnameinfo(addr, len, ip, sizeof(ip), port, sizeof(port),
									   NI_NUMERICHOST | NI_NUMERICSERV)) == 0) {
					LOGW("Packet count rate (%f) >= limit (%i), blocking ip/port %s/%s on protocol tcp for %i minutes",
						 packet_count_rate, mPacketRateLimit, ip, port, mBanTime);
					ban_ip_with_iptables(ip, port, "tcp", mBanTime);
					tport_reset_packet_count_rate(tport); // Reset it to not add the iptables rule twice by mistake
					ev->terminateProcessing(); // the event is discarded
				} else {
					LOGW("getnameinfo() failed: %s", gai_strerror(err));
				}
			}
		}
	}

	void onResponse(std::shared_ptr<ResponseSipEvent> &ev){

	};

  public:
	DoSProtection(Agent *ag) : Module(ag) {
	}

	~DoSProtection() {
	}
};

ModuleInfo<DoSProtection>
	DoSProtection::sInfo("DoSProtection",
						 "This module bans user when they are sending too much packets on a given timelapse"
						 "To see the list of currently banned ips/ports, use iptables -L"
						 "You can also check the queue of unban commands using atq",
						 ModuleInfoBase::ModuleOid::DoSProtection);
<commit_msg>Fix PR 2837<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "module.hh"
#include "agent.hh"
#include "log/logmanager.hh"
#include <sofia-sip/tport.h>
#include <sofia-sip/msg_addr.h>
#include <unordered_map>

using namespace ::std;

typedef struct DosContext {
	uint64_t recv_msg_count_since_last_check;
	double last_check_recv_msg_check_time;
	double packet_count_rate;
} DosContext;

class DoSProtection : public Module, ModuleToolbox {

  private:
	static ModuleInfo<DoSProtection> sInfo;
	int mTimePeriod;
	int mPacketRateLimit;
	int mBanTime;
	unordered_map<string, DosContext> mDosContexts;
	unordered_map<string, DosContext>::iterator mDOSHashtableIterator;

	void onDeclare(GenericStruct *module_config) {
		ConfigItemDescriptor configs[] = {
			{Integer, "time-period", "Number of milliseconds to consider to compute the packet rate", "3000"},
			{Integer, "packet-rate-limit", "Maximum packet rate in packets/seconds,  averaged over [time-period] "
										   "millisecond(s) to consider it as a DoS attack.",
			 "20"},
			{Integer, "ban-time", "Number of minutes to ban the ip/port using iptables (might be less because it justs "
								  "uses the minutes of the clock, not the seconds. So if the unban command is queued "
								  "at 13:11:56 and scheduled and the ban time is 1 minute, it will be executed at "
								  "13:12:00)",
			 "2"},
			config_item_end};
		module_config->get<ConfigBoolean>("enabled")->setDefault("true");
		module_config->addChildrenValues(configs);
	}

	void onLoad(const GenericStruct *mc) {
		mTimePeriod = mc->get<ConfigInt>("time-period")->read();
		mPacketRateLimit = mc->get<ConfigInt>("packet-rate-limit")->read();
		mBanTime = mc->get<ConfigInt>("ban-time")->read();
		mDOSHashtableIterator = mDosContexts.begin();

		tport_t *primaries = tport_primaries(nta_agent_tports(mAgent->getSofiaAgent()));
		if (primaries == NULL)
			LOGF("No sip transport defined.");
		for (tport_t *tport = primaries; tport != NULL; tport = tport_next(tport)) {
			tport_set_params(tport, TPTAG_DOS(mTimePeriod), TAG_END());
		}
		if (getuid() != 0) {
			LOGE("Flexisip not started with root privileges! iptables commands for DoS protection won't work.");
			return;
		}
	}

	void onUnload() {
	}

	virtual bool isValidNextConfig( const ConfigValue &value ) {
		GenericStruct *module_config = dynamic_cast<GenericStruct *>(value.getParent());
		if (!module_config->get<ConfigBoolean>("enabled")->readNext())
			return true;
		else {

#if __APPLE__
			LOGEN("DosProtection only works on linux hosts. Please disable this module.");
			return false;
#else

			int at_command = system("which at");
			if( WIFEXITED(at_command) && WEXITSTATUS(at_command) == 0 ) {
				// at command was found, we can be sure that iptables rules will be cleaned up after the required time
				return true;
			} else {
				LOGEN("Couldn't find the commant 'at' in your PATH. DosProtection needs it to be used correctly. Please fix this or disable DosProtection.");
				return false;
			}
#endif
		}
	}

	void onIdle() {
		struct timeval now;
		double started_time_in_millis, time_elapsed;

		gettimeofday(&now, NULL);
		started_time_in_millis = now.tv_sec * 1000 + (now.tv_usec / 1000);

		if (mDOSHashtableIterator == mDosContexts.end()) {
			mDOSHashtableIterator = mDosContexts.begin();
		}
		for (; mDOSHashtableIterator != mDosContexts.end();) {
			double now_in_millis;
			DosContext dos = mDOSHashtableIterator->second;

			gettimeofday(&now, NULL);
			now_in_millis = now.tv_sec * 1000 + (now.tv_usec / 1000);
			time_elapsed = now_in_millis - dos.last_check_recv_msg_check_time;

			if (time_elapsed >= 3600 * 1000) { // If no message received in the past hour
				mDOSHashtableIterator = mDosContexts.erase(mDOSHashtableIterator);
			} else {
				++mDOSHashtableIterator;
			}

			if (now_in_millis - started_time_in_millis >= 100) { // Do not use more than 100ms to clean the hashtable
				LOGW("Started to clean dos hashtable %fms ago, let's stop for now a continue later",
					 now_in_millis - started_time_in_millis);
				break;
			}
		}
	}

	static void ban_ip_with_iptables(const char *ip, const char *port, const char *protocol, int ban_time) {
		char iptables_cmd[512];
		snprintf(iptables_cmd, sizeof(iptables_cmd), "iptables -A INPUT -p %s -s %s -m multiport --sports %s -j DROP "
													 "&& echo \"iptables -D INPUT -p %s -s %s -m multiport --sports %s "
													 "-j DROP\" | at now +%i minutes",
				 protocol, ip, port, protocol, ip, port, ban_time);
		if (system(iptables_cmd) != 0) {
			LOGW("iptables command failed: %s", strerror(errno));
		}
	}

	void onRequest(shared_ptr<RequestSipEvent> &ev) {
		shared_ptr<tport_t> inTport = ev->getIncomingTport();
		tport_t *tport = inTport.get();

		if (tport == NULL) {
			LOGE("Tport is null, can't check the packet count rate");
			return;
		}

		if (tport_is_udp(tport)) { // Sofia doesn't create a secondary tport for udp, so it will ban the primary and we
								   // don't want that
			shared_ptr<MsgSip> msg = ev->getMsgSip();
			MsgSip *msgSip = msg.get();
			su_sockaddr_t su[1];
			socklen_t len = sizeof su;
			sockaddr *addr = NULL;
			char ip[NI_MAXHOST], port[NI_MAXSERV];
			int err;

			msg_get_address(msgSip->getMsg(), su, &len);
			addr = &(su[0].su_sa);

			if ((err = getnameinfo(addr, len, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV)) ==
				0) {
				string id = string(ip) + ":" + string(port);
				struct timeval now;
				DosContext &dosContext = mDosContexts[id];
				double now_in_millis, time_elapsed;

				dosContext.recv_msg_count_since_last_check++;
				gettimeofday(&now, NULL);
				now_in_millis = now.tv_sec * 1000 + (now.tv_usec / 1000);
				if (dosContext.last_check_recv_msg_check_time == 0) {
					dosContext.last_check_recv_msg_check_time = now_in_millis;
				}

				time_elapsed = now_in_millis - dosContext.last_check_recv_msg_check_time;
				if (time_elapsed < 0) {
					dosContext.packet_count_rate = 0;
					dosContext.recv_msg_count_since_last_check = 0;
					dosContext.last_check_recv_msg_check_time = now_in_millis;
				} else if (time_elapsed >= mTimePeriod) {
					dosContext.packet_count_rate = dosContext.recv_msg_count_since_last_check / time_elapsed * 1000;
					dosContext.recv_msg_count_since_last_check = 0;
					dosContext.last_check_recv_msg_check_time = now_in_millis;
				}

				if (dosContext.packet_count_rate >= mPacketRateLimit) {
					LOGW("Packet count rate (%f) >= limit (%i), blocking ip/port %s/%s on protocol udp for %i minutes",
						 dosContext.packet_count_rate, mPacketRateLimit, ip, port, mBanTime);
					ban_ip_with_iptables(ip, port, "udp", mBanTime);
					dosContext.packet_count_rate = 0; // Reset it to not add the iptables rule twice by mistake
					ev->terminateProcessing(); // the event is discarded
				}
			} else {
				LOGW("getnameinfo() failed: %s", gai_strerror(err));
			}
		} else {
			float packet_count_rate = tport_get_packet_count_rate(tport);
			if (packet_count_rate >= mPacketRateLimit) {
				sockaddr *addr = tport_get_address(tport)->ai_addr;
				socklen_t len = tport_get_address(tport)->ai_addrlen;
				char ip[NI_MAXHOST], port[NI_MAXSERV];
				int err;

				if ((err = getnameinfo(addr, len, ip, sizeof(ip), port, sizeof(port),
									   NI_NUMERICHOST | NI_NUMERICSERV)) == 0) {
					LOGW("Packet count rate (%f) >= limit (%i), blocking ip/port %s/%s on protocol tcp for %i minutes",
						 packet_count_rate, mPacketRateLimit, ip, port, mBanTime);
					ban_ip_with_iptables(ip, port, "tcp", mBanTime);
					tport_reset_packet_count_rate(tport); // Reset it to not add the iptables rule twice by mistake
					ev->terminateProcessing(); // the event is discarded
				} else {
					LOGW("getnameinfo() failed: %s", gai_strerror(err));
				}
			}
		}
	}

	void onResponse(std::shared_ptr<ResponseSipEvent> &ev){

	};

  public:
	DoSProtection(Agent *ag) : Module(ag) {
	}

	~DoSProtection() {
	}
};

ModuleInfo<DoSProtection>
	DoSProtection::sInfo("DoSProtection",
						 "This module bans user when they are sending too much packets on a given timelapse"
						 "To see the list of currently banned ips/ports, use iptables -L"
						 "You can also check the queue of unban commands using atq",
						 ModuleInfoBase::ModuleOid::DoSProtection);
<|endoftext|>