<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: detailpages.hxx,v $
 *
 *  $Revision: 1.25 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-13 16:50:58 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _DBAUI_DETAILPAGES_HXX_
#define _DBAUI_DETAILPAGES_HXX_

#ifndef _DBAUI_ADMINPAGES_HXX_
#include "adminpages.hxx"
#endif
#ifndef _DBAUI_CHARSETS_HXX_
#include "charsets.hxx"
#endif
#ifndef _SV_FIELD_HXX
#include <vcl/field.hxx>
#endif
#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#ifndef _SV_LSTBOX_HXX
#include <vcl/lstbox.hxx>
#endif
#ifndef _SV_EDIT_HXX
#include <vcl/edit.hxx>
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef DBAUI_TEXTCONNECTIONHELPER_HXX
#include "TextConnectionHelper.hxx"
#endif

#include <svtools/dialogcontrolling.hxx>

//.........................................................................
namespace dbaui
{
//.........................................................................
    //=========================================================================
    //= OCommonBehaviourTabPage
    //=========================================================================
    #define     CBTP_NONE                           0x00000000
    #define     CBTP_USE_APPENDTABLEALIAS           0x00000001
    #define     CBTP_USE_CHARSET                    0x00000002
    #define     CBTP_USE_OPTIONS                    0x00000004
    #define     CBTP_USE_SQL92CHECK                 0x00000010
    #define     CBTP_USE_AUTOINCREMENT              0x00000020
    #define     CBTP_USE_PARAMETERNAMESUBST         0x00000040
    #define     CBTP_USE_IGNOREDRIVER_PRIV          0x00000100
    #define     CBTP_USE_SUPPRESS_VERSION_COLUMN    0x00000200
    #define     CBTP_USE_BOOLEANCOMPARISON          0x00000400
    #define     CBTP_USE_ENABLEOUTERJOIN            0x00001000
    #define     CBTP_USE_CATALOG                    0x00002000
    #define     CBTP_USE_SCHEMA                     0x00004000
    #define     CBTP_USE_INDEXAPPENDIX              0x00010000
    #define     CBTP_USE_DOSLINEENDS                0x00020000
    #define     CBTP_AS_BEFORE_CORRELATION_NAME     0x00040000

    /** eases the implementation of tab pages handling user/password and/or character
        set and/or generic options input

        The controls to be used habe to be defined within the resource, as usual, but
        this class does all the handling necessary.
    */
    class OCommonBehaviourTabPage : public OGenericAdministrationPage
    {
    protected:

        FixedText*          m_pOptionsLabel;
        Edit*               m_pOptions;

        FixedLine*          m_pDataConvertFixedLine;
        FixedText*          m_pCharsetLabel;
        ListBox*            m_pCharset;

        FixedLine*          m_pDSFixedLine;
        CheckBox*           m_pIsSQL92Check;
        CheckBox*           m_pAppendTableAlias;
        CheckBox*           m_pAsBeforeCorrelationName;
        CheckBox*           m_pParameterSubstitution;
        CheckBox*           m_pIgnoreDriverPrivileges;
        CheckBox*           m_pSuppressVersionColumn;
        CheckBox*           m_pEnableOuterJoin;
        CheckBox*           m_pCatalog;
        CheckBox*           m_pSchema;
        CheckBox*           m_pIndexAppendix;
        CheckBox*           m_pDosLineEnds;

        FixedText*          m_pBooleanComprisonModeLabel;
        ListBox*            m_pBooleanComprisonMode;

        FixedLine*          m_pAutoFixedLine;
        CheckBox*           m_pAutoRetrievingEnabled;
        FixedText*          m_pAutoIncrementLabel;
        Edit*               m_pAutoIncrement;
        FixedText*          m_pAutoRetrievingLabel;
        Edit*               m_pAutoRetrieving;

        OCharsetDisplay     m_aCharsets;

        sal_uInt32          m_nControlFlags;
        ::svt::ControlDependencyManager
                            m_aControlDependencies;

        DECL_LINK( OnCheckBoxClick, CheckBox * );

    public:
        virtual BOOL        FillItemSet (SfxItemSet& _rCoreAttrs);

        OCommonBehaviourTabPage(Window* pParent, USHORT nResId, const SfxItemSet& _rCoreAttrs, sal_uInt32 nControlFlags,bool _bFreeResource = true);
    protected:

            // nControlFlags ist eine Kombination der CBTP_xxx-Konstanten
        virtual ~OCommonBehaviourTabPage();

        // must be overloaded by subclasses, but it isn't pure virtual
        virtual void        implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);

        // <method>OGenericAdministrationPage::fillControls</method>
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);

        // <method>OGenericAdministrationPage::fillWindows</method>
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        /// creates the fixed line before the autoincrement controls
        void createBehaviourFixedLine();
    };

    //========================================================================
    //= ODbaseDetailsPage
    //========================================================================
    class ODbaseDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        ODbaseDetailsPage(Window* pParent, const SfxItemSet& _rCoreAttrs);
    private:
        // please add new controls also to <method>fillControls</method> or <method>fillWindows</method>
        CheckBox            m_aShowDeleted;
        FixedLine           m_aFL_1;
        FixedText           m_aFT_Message;
        PushButton          m_aIndexes;

        String              m_sDsn;

    protected:

        virtual ~ODbaseDetailsPage();

    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

    private:
        DECL_LINK( OnButtonClicked, Button * );
    };

    //========================================================================
    //= OAdoDetailsPage
    //========================================================================
    class OAdoDetailsPage : public OCommonBehaviourTabPage
    {
    protected:
        virtual ~OAdoDetailsPage();
    public:

        OAdoDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    };

    //========================================================================
    //= OOdbcDetailsPage
    //========================================================================
    class OOdbcDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OOdbcDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        FixedLine           m_aFL_1;
        CheckBox            m_aUseCatalog;
    };

    //========================================================================
    //= OUserDriverDetailsPage
    //========================================================================
    class OUserDriverDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OUserDriverDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        FixedText           m_aFTHostname;
        Edit                m_aEDHostname;
        FixedText           m_aPortNumber;
        NumericField        m_aNFPortNumber;
        FixedLine           m_aSeparator2;
        CheckBox            m_aUseCatalog;
    };

    //========================================================================
    //= OMySQLODBCDetailsPage
    //========================================================================
    class OMySQLODBCDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        OMySQLODBCDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    };

    //========================================================================
    //= OGeneralSpecialJDBCDetailsPage
    //========================================================================
    class OGeneralSpecialJDBCDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        OGeneralSpecialJDBCDetailsPage(   Window* pParent
                                        , USHORT _nResId
                                        , const SfxItemSet& _rCoreAttrs
                                        , USHORT _nPortId
                                        , const char* _pDriverName);

    protected:

        virtual BOOL FillItemSet( SfxItemSet& _rCoreAttrs );
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

        DECL_LINK(OnTestJavaClickHdl,PushButton*);
        DECL_LINK(OnEditModified,Edit*);

        FixedLine           m_aFL_1;
        FixedText           m_aFTHostname;
        Edit                m_aEDHostname;
        FixedText           m_aPortNumber;
        NumericField        m_aNFPortNumber;

        FixedText           m_aFTDriverClass;
        Edit                m_aEDDriverClass;
        PushButton          m_aTestJavaDriver;

        String              m_sDefaultJdbcDriverName;
        USHORT              m_nPortId;
    };

    //========================================================================
    //= OAdabasDetailsPage
    //========================================================================
    class OAdabasDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet (SfxItemSet& _rCoreAttrs);

        OAdabasDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

    private:
        FixedText           m_aFTHostname;
        Edit                m_aEDHostname;
        FixedLine           m_aFL_1;
        FixedText           m_FT_CACHE_SIZE;
        NumericField        m_NF_CACHE_SIZE;

        FixedText           m_FT_DATA_INCREMENT;
        NumericField        m_NF_DATA_INCREMENT;

        FixedLine           m_aFL_2;
        FixedText           m_FT_CTRLUSERNAME;
        Edit                m_ET_CTRLUSERNAME;
        FixedText           m_FT_CTRLPASSWORD;
        Edit                m_ET_CTRLPASSWORD;

        CheckBox            m_CB_SHUTDB;
        PushButton          m_PB_STAT;
        String              m_sUser;
        BOOL                bAttrsChanged;

        DECL_LINK( AttributesChangedHdl,    void * );
        DECL_LINK( UserSettingsHdl,         void * );
        DECL_LINK( LoseFocusHdl,            Edit * );
        DECL_LINK( PBClickHdl,              Button *);
    };

    //========================================================================
    //= OOdbcDetailsPage
    //========================================================================
    class OLDAPDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OLDAPDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        FixedLine           m_aFL_1;
        FixedText           m_aBaseDN;
        Edit                m_aETBaseDN;
        CheckBox            m_aCBUseSSL;
        FixedText           m_aPortNumber;
        NumericField        m_aNFPortNumber;
        FixedText           m_aFTRowCount;
        NumericField        m_aNFRowCount;

        sal_Int32           m_iSSLPort;
        sal_Int32           m_iNormalPort;
        DECL_LINK( OnCheckBoxClick, CheckBox * );
    };

    //========================================================================
    //= OMozillaDetailsPage Detail page for Mozilla and Thunderbird addressbook
    //========================================================================
    class OMozillaDetailsPage : public OCommonBehaviourTabPage
    {
    protected:
        virtual ~OMozillaDetailsPage();
    public:

        OMozillaDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    };

    //========================================================================
    //= OTextDetailsPage
    //========================================================================
    class OTextDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OTextDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
        OTextConnectionHelper*  m_pTextConnectionHelper;

    private:

        String      m_aFieldSeparatorList;
        String      m_aTextSeparatorList;
        String      m_aTextNone;
    protected:
        virtual ~OTextDetailsPage();
        virtual sal_Bool checkItems();

        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

    private:
    };

//.........................................................................
}   // namespace dbaui
//.........................................................................

#endif // _DBAUI_DETAILPAGES_HXX_
<commit_msg>INTEGRATION: CWS dba23a (1.25.30); FILE MERGED 2007/03/13 08:42:14 fs 1.25.30.1: some slight re-factoring (class/method renaming), plus some rudimentary fix for #b6532894#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: detailpages.hxx,v $
 *
 *  $Revision: 1.26 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-10 10:25:36 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _DBAUI_DETAILPAGES_HXX_
#define _DBAUI_DETAILPAGES_HXX_

#ifndef _DBAUI_ADMINPAGES_HXX_
#include "adminpages.hxx"
#endif
#ifndef _DBAUI_CHARSETS_HXX_
#include "charsets.hxx"
#endif
#ifndef _SV_FIELD_HXX
#include <vcl/field.hxx>
#endif
#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#ifndef _SV_LSTBOX_HXX
#include <vcl/lstbox.hxx>
#endif
#ifndef _SV_EDIT_HXX
#include <vcl/edit.hxx>
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef DBAUI_TEXTCONNECTIONHELPER_HXX
#include "TextConnectionHelper.hxx"
#endif

#include <svtools/dialogcontrolling.hxx>

//.........................................................................
namespace dbaui
{
//.........................................................................
    //=========================================================================
    //= OCommonBehaviourTabPage
    //=========================================================================
    #define     CBTP_NONE                           0x00000000
    #define     CBTP_USE_APPENDTABLEALIAS           0x00000001
    #define     CBTP_USE_CHARSET                    0x00000002
    #define     CBTP_USE_OPTIONS                    0x00000004
    #define     CBTP_USE_SQL92CHECK                 0x00000010
    #define     CBTP_USE_AUTOINCREMENT              0x00000020
    #define     CBTP_USE_PARAMETERNAMESUBST         0x00000040
    #define     CBTP_USE_IGNOREDRIVER_PRIV          0x00000100
    #define     CBTP_USE_SUPPRESS_VERSION_COLUMN    0x00000200
    #define     CBTP_USE_BOOLEANCOMPARISON          0x00000400
    #define     CBTP_USE_ENABLEOUTERJOIN            0x00001000
    #define     CBTP_USE_CATALOG                    0x00002000
    #define     CBTP_USE_SCHEMA                     0x00004000
    #define     CBTP_USE_INDEXAPPENDIX              0x00010000
    #define     CBTP_USE_DOSLINEENDS                0x00020000
    #define     CBTP_AS_BEFORE_CORRELATION_NAME     0x00040000

    /** eases the implementation of tab pages handling user/password and/or character
        set and/or generic options input

        The controls to be used habe to be defined within the resource, as usual, but
        this class does all the handling necessary.
    */
    class OCommonBehaviourTabPage : public OGenericAdministrationPage
    {
    protected:

        FixedText*          m_pOptionsLabel;
        Edit*               m_pOptions;

        FixedLine*          m_pDataConvertFixedLine;
        FixedText*          m_pCharsetLabel;
        ListBox*            m_pCharset;

        FixedLine*          m_pDSFixedLine;
        CheckBox*           m_pIsSQL92Check;
        CheckBox*           m_pAppendTableAlias;
        CheckBox*           m_pAsBeforeCorrelationName;
        CheckBox*           m_pParameterSubstitution;
        CheckBox*           m_pIgnoreDriverPrivileges;
        CheckBox*           m_pSuppressVersionColumn;
        CheckBox*           m_pEnableOuterJoin;
        CheckBox*           m_pCatalog;
        CheckBox*           m_pSchema;
        CheckBox*           m_pIndexAppendix;
        CheckBox*           m_pDosLineEnds;

        FixedText*          m_pBooleanComprisonModeLabel;
        ListBox*            m_pBooleanComprisonMode;

        FixedLine*          m_pAutoFixedLine;
        CheckBox*           m_pAutoRetrievingEnabled;
        FixedText*          m_pAutoIncrementLabel;
        Edit*               m_pAutoIncrement;
        FixedText*          m_pAutoRetrievingLabel;
        Edit*               m_pAutoRetrieving;

        OCharsetDisplay     m_aCharsets;

        sal_uInt32          m_nControlFlags;
        ::svt::ControlDependencyManager
                            m_aControlDependencies;

        DECL_LINK( OnCheckBoxClick, CheckBox * );

    public:
        virtual BOOL        FillItemSet (SfxItemSet& _rCoreAttrs);

        OCommonBehaviourTabPage(Window* pParent, USHORT nResId, const SfxItemSet& _rCoreAttrs, sal_uInt32 nControlFlags,bool _bFreeResource = true);
    protected:

            // nControlFlags ist eine Kombination der CBTP_xxx-Konstanten
        virtual ~OCommonBehaviourTabPage();

        // must be overloaded by subclasses, but it isn't pure virtual
        virtual void        implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);

        // <method>OGenericAdministrationPage::fillControls</method>
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);

        // <method>OGenericAdministrationPage::fillWindows</method>
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        /// creates the fixed line before the autoincrement controls
        void createBehaviourFixedLine();
    };

    //========================================================================
    //= ODbaseDetailsPage
    //========================================================================
    class ODbaseDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        ODbaseDetailsPage(Window* pParent, const SfxItemSet& _rCoreAttrs);
    private:
        // please add new controls also to <method>fillControls</method> or <method>fillWindows</method>
        CheckBox            m_aShowDeleted;
        FixedLine           m_aFL_1;
        FixedText           m_aFT_Message;
        PushButton          m_aIndexes;

        String              m_sDsn;

    protected:

        virtual ~ODbaseDetailsPage();

    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

    private:
        DECL_LINK( OnButtonClicked, Button * );
    };

    //========================================================================
    //= OAdoDetailsPage
    //========================================================================
    class OAdoDetailsPage : public OCommonBehaviourTabPage
    {
    protected:
        virtual ~OAdoDetailsPage();
    public:

        OAdoDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    };

    //========================================================================
    //= OOdbcDetailsPage
    //========================================================================
    class OOdbcDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OOdbcDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        FixedLine           m_aFL_1;
        CheckBox            m_aUseCatalog;
    };

    //========================================================================
    //= OUserDriverDetailsPage
    //========================================================================
    class OUserDriverDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OUserDriverDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        FixedText           m_aFTHostname;
        Edit                m_aEDHostname;
        FixedText           m_aPortNumber;
        NumericField        m_aNFPortNumber;
        FixedLine           m_aSeparator2;
        CheckBox            m_aUseCatalog;
    };

    //========================================================================
    //= OMySQLODBCDetailsPage
    //========================================================================
    class OMySQLODBCDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        OMySQLODBCDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    };

    //========================================================================
    //= OGeneralSpecialJDBCDetailsPage
    //========================================================================
    class OGeneralSpecialJDBCDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        OGeneralSpecialJDBCDetailsPage(   Window* pParent
                                        , USHORT _nResId
                                        , const SfxItemSet& _rCoreAttrs
                                        , USHORT _nPortId
                                        , const char* _pDriverName);

    protected:

        virtual BOOL FillItemSet( SfxItemSet& _rCoreAttrs );
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

        DECL_LINK(OnTestJavaClickHdl,PushButton*);
        DECL_LINK(OnEditModified,Edit*);

        FixedLine           m_aFL_1;
        FixedText           m_aFTHostname;
        Edit                m_aEDHostname;
        FixedText           m_aPortNumber;
        NumericField        m_aNFPortNumber;

        FixedText           m_aFTDriverClass;
        Edit                m_aEDDriverClass;
        PushButton          m_aTestJavaDriver;

        String              m_sDefaultJdbcDriverName;
        USHORT              m_nPortId;
    };

    //========================================================================
    //= OAdabasDetailsPage
    //========================================================================
    class OAdabasDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet (SfxItemSet& _rCoreAttrs);

        OAdabasDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

    private:
        FixedText           m_aFTHostname;
        Edit                m_aEDHostname;
        FixedLine           m_aFL_1;
        FixedText           m_FT_CACHE_SIZE;
        NumericField        m_NF_CACHE_SIZE;

        FixedText           m_FT_DATA_INCREMENT;
        NumericField        m_NF_DATA_INCREMENT;

        FixedLine           m_aFL_2;
        FixedText           m_FT_CTRLUSERNAME;
        Edit                m_ET_CTRLUSERNAME;
        FixedText           m_FT_CTRLPASSWORD;
        Edit                m_ET_CTRLPASSWORD;

        CheckBox            m_CB_SHUTDB;
        PushButton          m_PB_STAT;
        String              m_sUser;
        BOOL                bAttrsChanged;

        DECL_LINK( AttributesChangedHdl,    void * );
        DECL_LINK( UserSettingsHdl,         void * );
        DECL_LINK( LoseFocusHdl,            Edit * );
        DECL_LINK( PBClickHdl,              Button *);
    };

    //========================================================================
    //= OOdbcDetailsPage
    //========================================================================
    class OLDAPDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OLDAPDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    protected:
        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);
    private:
        FixedLine           m_aFL_1;
        FixedText           m_aBaseDN;
        Edit                m_aETBaseDN;
        CheckBox            m_aCBUseSSL;
        FixedText           m_aPortNumber;
        NumericField        m_aNFPortNumber;
        FixedText           m_aFTRowCount;
        NumericField        m_aNFRowCount;

        sal_Int32           m_iSSLPort;
        sal_Int32           m_iNormalPort;
        DECL_LINK( OnCheckBoxClick, CheckBox * );
    };

    //========================================================================
    //= OMozillaDetailsPage Detail page for Mozilla and Thunderbird addressbook
    //========================================================================
    class OMozillaDetailsPage : public OCommonBehaviourTabPage
    {
    protected:
        virtual ~OMozillaDetailsPage();
    public:

        OMozillaDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
    };

    //========================================================================
    //= OTextDetailsPage
    //========================================================================
    class OTextDetailsPage : public OCommonBehaviourTabPage
    {
    public:
        virtual BOOL        FillItemSet ( SfxItemSet& _rCoreAttrs );

        OTextDetailsPage( Window* pParent, const SfxItemSet& _rCoreAttrs );
        OTextConnectionHelper*  m_pTextConnectionHelper;

    private:

        String      m_aFieldSeparatorList;
        String      m_aTextSeparatorList;
        String      m_aTextNone;
    protected:
        virtual ~OTextDetailsPage();
        virtual sal_Bool prepareLeave();

        virtual void implInitControls(const SfxItemSet& _rSet, sal_Bool _bSaveValue);
        virtual void fillControls(::std::vector< ISaveValueWrapper* >& _rControlList);
        virtual void fillWindows(::std::vector< ISaveValueWrapper* >& _rControlList);

    private:
    };

//.........................................................................
}   // namespace dbaui
//.........................................................................

#endif // _DBAUI_DETAILPAGES_HXX_
<|endoftext|>


<commit_before>
// -todo: make push and push_back
// -todo: make pop() and pop_back()

// todo: fix realloc to be resize based on element count
// todo: operator >> for concatenation with left keys as priority
// todo: operator << for concatenation with right keys as priority
// todo: make emplace and emplace_back()
// todo: make resize()
// todo: make shrink_to_fit()
// todo: make reserve()
// todo: keep track of capacity and make capacity() const function
// todo: make front() and back()
// todo: make variant structure
// todo: make hash union
// todo: make key value pair be 4 bytes for hash, 18 + 1 for c_str(), and 8 + 1 for variant + type
// todo: make operator~ return just the vector
// todo: make different unary operator return just the map?
// todo: try template constructor that returns a tbl<type> with a default value set?
// todo: use binary bit operators to make tbl act like a set
// todo: make operator-- be shrink_to_fit() and ++ be resize() ?
// todo: robin hood hashing

#ifndef __TBL_HEADERGUARD_H__
#define __TBL_HEADERGUARD_H__

#include <cstdlib>
#include "../no_rt_util.h"

class tbl
{
private:
  static ui64 memberBytes()
  {
    return sizeof(ui64) * 2;
  }

  void   set_sizeBytes(ui64 bytes) const // -> ui64
  {
    *( (ui64*)memStart() ) = bytes;
  }
  void        set_size(ui64  size)
  {
    *( ((ui64*)memStart()) + 1 ) = size;
  }
  void*       memStart()
  {
    return (void*)(m_mem - memberBytes());
  }
  void              cp(tbl const& l)
  {
  }
  void              mv(tbl&& r)
  {
  }

public:
  static ui64 sizeBytes(ui64 count)                                  // returns the bytes needed to store the data structure if the same arguments were given to the constructor
  {
    return memberBytes() + sizeof(T)*count;
  }
  static tbl     concat(tbl const& a, tbl const& b)                                  // returns the bytes needed to store the data structure if the same arguments were given to the constructor
  {
    auto sz = a.size();
    tbl ret(sz + b.size());

    TO(sz,i) ret[i]    = a[i];
    TO(b, i) ret[sz+i] = b[i];

    return ret;
  }

  union  hsh
  {
    struct { ui32 type : 4; ui32 : 28; };
    ui32 as_ui32;
  };
  struct Var{};        // todo: future variant type

  using T    =  int;
  using var  =  Var;

  i8*     m_mem;

  tbl() :
    m_mem(nullptr)
  {
  }
  tbl(ui64 count)
  {
    //m_size(count),
    //ui64  cntBytes  =  count*sizeof(T);
    //ui64   szBytes  =  cntBytes + memberBytes();             // sizeof(ui64)*2;

    ui64   szBytes  =  tbl::sizeBytes(count);
    i8*      memst  =  (i8*)malloc(szBytes);                 // memst is memory start
    m_mem           =  memst + memberBytes();
    set_sizeBytes(szBytes);
    set_size(count);
  }

  operator    ui64() const
  {
    return size();
  }
  T&    operator[](ui64 i)
  {
    return ((T*)m_mem)[i];
  }
  auto  operator[](ui64 i) const -> T const&
  {
    return ((T*)m_mem)[i];
  }
  var&  operator()(const char*)                             // todo: future hash map interface
  {
    Var nonsense;
    return nonsense;
  }
  tbl   operator>>(tbl const& l)
  {
    return tbl::concat(*this, l);
  }
  tbl   operator<<(tbl const& l)
  {
    return tbl::concat(*this, l);
  }

  bool        push(T const& value)
  {
    if( !(capacity()>size()) )
      if(!expand()) return false;

    (*this)[size()] = value;

    set_size(size()+1);

    return true;
  }
  bool   push_back(T const& value){ return push(value); }
  void         pop(){ set_size(size()-1); }
  void    pop_back(){ pop(); }
  T&         front(){ return (*this)[0]; }
  T&          back(){ return (*this)[size()-1]; }

  ui64        size() const
  {
    if(!m_mem) return 0;

    return *( ((ui64*)memStart()) + 1 );
  }
  T*          data() const
  {
    return (T*)m_mem;
  }
  void*   memStart() const
  {
    return (void*)(m_mem - memberBytes());
  }
  ui64   sizeBytes() const // -> ui64
  {
    if(!m_mem) return 0;

    return *( (ui64 const*)memStart() );
  }
  ui64    capacity() const
  {
    if(!m_mem) return 0;

    return (sizeBytes() - memberBytes()) / sizeof(T);  // - size()*sizeof(T)
  }
  ui64       count() const
  {
    // todo: make this the number of elements in the map
    //return *( ((ui64*)memStart()) - 1 );
  }
  void*    reserve(ui64 size)
  {
    auto  nxtBytes  =  memberBytes() + sizeof(T)*size;
    void*       re;
    bool     fresh  = !m_mem;
    if(fresh) re = malloc(nxtBytes);
    else      re = realloc(memStart(), nxtBytes);

    if(re){
      m_mem = ((i8*)re) + memberBytes();
      set_sizeBytes(nxtBytes);
    }

    if(fresh) set_size(0);

    return re;

    //set_sizeBytes(nxtBytes);
  }
  void*     expand()
  {
    ui64    sz = size();
    ui64 nxtSz = (sz/2)? sz+sz/2 : sz+1;
    return reserve(nxtSz);
  }
};

#endif

//if(m_mem==nullptr){                            // can just use realloc here
//  auto szBytes  =  tbl::sizeBytes(1);
//  i8*    memst  =  (i8*)malloc(szBytes);                 // memst is memory start
//  m_mem         =  memst + memberBytes();
//  //m_mem         = (i8*)malloc( szBytes );
//  set_sizeBytes( szBytes );
//  set_size(0);
//  //if(mem) m_mem = mem;
//  //new (this) tbl(1);
//  return m_mem;
//}
//
//auto szBytes  =  sizeBytes();
//auto   extra  =    szBytes/2;
//extra         =  extra>sizeof(T)? extra : sizeof(T);
//auto    nxtSz =  szBytes + extra;
//void*     re  =  realloc(memStart(), nxtSz);
//if(re){
//  m_mem = ((i8*)re) + memberBytes();
//  set_sizeBytes(nxtSz);
//}
//
//return re;

//auto sz = size();
//tbl ret(sz + l.size());
//
//TO(sz,i) ret[i]    = (*this)[i];
//TO(l, i) ret[sz+i] = l[i];
//
//return ret;
<commit_msg>concatenation operaor>> and type enum for variants<commit_after>
// -todo: make push and push_back
// -todo: make pop() and pop_back()
// -todo: fix realloc to be resize based on element count
// -todo: operator >> for concatenation with left keys as priority
// -todo: operator << for concatenation with right keys as priority
// -todo: make reserve()
// -todo: keep track of capacity and make capacity() const function
// -todo: make front() and back()

// todo: make enum with number types and table-number types
// todo: make a table hold any type, but a map hold only numbers and table-number types
// todo: make variant structure
// todo: make hash union
// todo: make emplace and emplace_back()
// todo: make resize()
// todo: make shrink_to_fit()
// todo: make key value pair be 4 bytes for hash, 18 + 1 for c_str(), and 8 + 1 for variant + type
// todo: make operator~ return just the vector
// todo: make different unary operator return just the map?
// todo: try template constructor that returns a tbl<type> with a default value set?
// todo: use binary bit operators to make tbl act like a set
// todo: make operator-- be shrink_to_fit() and ++ be resize() ?
// todo: robin hood hashing

#ifndef __TBL_HEADERGUARD_H__
#define __TBL_HEADERGUARD_H__

#include <cstdlib>
#include "../no_rt_util.h"

class tbl
{
private:
  static ui64 memberBytes()
  {
    return sizeof(ui64) * 2;
  }

  void   set_sizeBytes(ui64 bytes) const // -> ui64
  {
    *( (ui64*)memStart() ) = bytes;
  }
  void        set_size(ui64  size)
  {
    *( ((ui64*)memStart()) + 1 ) = size;
  }
  void*       memStart()
  {
    return (void*)(m_mem - memberBytes());
  }
  void              cp(tbl const& l)
  {
  }
  void              mv(tbl&& r)
  {
  }

public:
  enum class type {
    EMPTY = 0,
    ui8, i8, ui16, i16, ui32, i32, ui64, i64, f32, f64,
    ui8t,i8t,ui16t,i16t,ui32t,i32t,ui64t,i64t,f32t,f64t
  };
  union       hsh
  {
    struct { ui32 type : 4; ui32 : 28; };
    ui32 as_ui32;
  };
  struct      Var{};        // todo: future variant type

  using T    =  int;
  using var  =  Var;

  i8*     m_mem;

  tbl() :
    m_mem(nullptr)
  {
  }
  tbl(ui64 count)
  {
    //m_size(count),
    //ui64  cntBytes  =  count*sizeof(T);
    //ui64   szBytes  =  cntBytes + memberBytes();             // sizeof(ui64)*2;

    ui64   szBytes  =  tbl::sizeBytes(count);
    i8*      memst  =  (i8*)malloc(szBytes);                 // memst is memory start
    m_mem           =  memst + memberBytes();
    set_sizeBytes(szBytes);
    set_size(count);
  }

  operator    ui64() const
  {
    return size();
  }
  T&    operator[](ui64 i)
  {
    return ((T*)m_mem)[i];
  }
  auto  operator[](ui64 i) const -> T const&
  {
    return ((T*)m_mem)[i];
  }
  var&  operator()(const char*)                             // todo: future hash map interface
  {
    Var nonsense;
    return nonsense;
  }
  tbl   operator>>(tbl const& l)
  {
    return tbl::concat(*this, l);
  }
  tbl   operator<<(tbl const& l)
  {
    return tbl::concat(*this, l);
  }

  bool        push(T const& value)
  {
    if( !(capacity()>size()) )
      if(!expand()) return false;

    (*this)[size()] = value;

    set_size(size()+1);

    return true;
  }
  bool   push_back(T const& value){ return push(value); }
  void         pop(){ set_size(size()-1); }
  void    pop_back(){ pop(); }
  T&         front(){ return (*this)[0]; }
  T&          back(){ return (*this)[size()-1]; }

  ui64        size() const
  {
    if(!m_mem) return 0;

    return *( ((ui64*)memStart()) + 1 );
  }
  T*          data() const
  {
    return (T*)m_mem;
  }
  void*   memStart() const
  {
    return (void*)(m_mem - memberBytes());
  }
  ui64   sizeBytes() const // -> ui64
  {
    if(!m_mem) return 0;

    return *( (ui64 const*)memStart() );
  }
  ui64    capacity() const
  {
    if(!m_mem) return 0;

    return (sizeBytes() - memberBytes()) / sizeof(T);  // - size()*sizeof(T)
  }
  ui64       count() const
  {
    // todo: make this the number of elements in the map
    //return *( ((ui64*)memStart()) - 1 );
  }
  void*    reserve(ui64 size)
  {
    auto  nxtBytes  =  memberBytes() + sizeof(T)*size;
    void*       re;
    bool     fresh  = !m_mem;
    if(fresh) re = malloc(nxtBytes);
    else      re = realloc(memStart(), nxtBytes);

    if(re){
      m_mem = ((i8*)re) + memberBytes();
      set_sizeBytes(nxtBytes);
    }

    if(fresh) set_size(0);

    return re;

    //set_sizeBytes(nxtBytes);
  }
  void*     expand()
  {
    ui64    sz = size();
    ui64 nxtSz = (sz/2)? sz+sz/2 : sz+1;
    return reserve(nxtSz);
  }

  static ui64 sizeBytes(ui64 count)                                  // returns the bytes needed to store the data structure if the same arguments were given to the constructor
  {
    return memberBytes() + sizeof(T)*count;
  }
  static tbl     concat(tbl const& a, tbl const& b)                                  // returns the bytes needed to store the data structure if the same arguments were given to the constructor
  {
    auto sz = a.size();
    tbl ret(sz + b.size());

    TO(sz,i) ret[i]    = a[i];
    TO(b, i) ret[sz+i] = b[i];

    return ret;
  }
};

#endif

//if(m_mem==nullptr){                            // can just use realloc here
//  auto szBytes  =  tbl::sizeBytes(1);
//  i8*    memst  =  (i8*)malloc(szBytes);                 // memst is memory start
//  m_mem         =  memst + memberBytes();
//  //m_mem         = (i8*)malloc( szBytes );
//  set_sizeBytes( szBytes );
//  set_size(0);
//  //if(mem) m_mem = mem;
//  //new (this) tbl(1);
//  return m_mem;
//}
//
//auto szBytes  =  sizeBytes();
//auto   extra  =    szBytes/2;
//extra         =  extra>sizeof(T)? extra : sizeof(T);
//auto    nxtSz =  szBytes + extra;
//void*     re  =  realloc(memStart(), nxtSz);
//if(re){
//  m_mem = ((i8*)re) + memberBytes();
//  set_sizeBytes(nxtSz);
//}
//
//return re;

//auto sz = size();
//tbl ret(sz + l.size());
//
//TO(sz,i) ret[i]    = (*this)[i];
//TO(l, i) ret[sz+i] = l[i];
//
//return ret;
<|endoftext|>


<commit_before>/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
 * Copyright (C) 2013 Regents of the University of California.
 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
 * See COPYING for copyright and distribution information.
 */

#if 1 // TODO: Remove this when we don't throw "not implemented".
#include <stdexcept>
#endif
#include "der-exception.hpp"
#include "../../util/logging.hpp"
#include "der.hpp"

INIT_LOGGER("ndn.der.DER");

using namespace std;
using namespace ndn::ptr_lib;

namespace ndn {

namespace der {

/*
 * DerNode
 */
DerNode::DerNode()
  :parent_(0)
{}

DerNode::DerNode(DerType type)
  :type_(type),
   parent_(0)
{}

DerNode::DerNode(std::istream& start)
  :parent_(0)
{
  decode(start);
}

DerNode::~DerNode()
{}

void
DerNode::encodeHeader(int size)
{
  header_.push_back((char)type_);

  if(size >= 127)
    {
      int val = size;
      char buf[sizeof(val) + 1];
      char *p = &(buf[sizeof(buf)-1]);
      int n = 0;
      int mask = (1 << 8) - 1;

      while(val != 0)
        {
          p[0] = (char)(val & mask);
          p--;
          n++;
          val >>= 8;
        }

      p[0] = (char)((1<<7) | n);
      n++;

      header_.insert(header_.end(), p, p+n);
    }
  else if(size >= 0)
    {
      header_.push_back((char)size);
    }
  else
    throw NegativeLengthException("Negative length");
}

int
DerNode::decodeHeader(istream& start)
{
  uint8_t type = start.get();
  // char type = start.get();
  header_.push_back(type);
  type_ = static_cast<DerType>((int)type);

  uint8_t sizeLen = start.get();
  // char sizeLen = start.get();
  header_.push_back(sizeLen);

  bool longFormat = sizeLen & (1 << 7);

  if(!longFormat)
    {
      // _LOG_DEBUG("Short Format");
      // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
      return (int)sizeLen;
    }
  else
    {
      // _LOG_DEBUG("Long Format");
      uint8_t byte;
      // char byte;
      int lenCount = sizeLen & ((1<<7) - 1);
      // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
      // _LOG_DEBUG("mask: " << (int)((1<<7) - 1));
      // _LOG_DEBUG("lenCount: " << (int)lenCount);
      int size = 0;
      do
        {
          byte = start.get();
          header_.push_back(byte);
          size = size * 256 + (int)byte;
          // _LOG_DEBUG("byte: " << (int)byte);
          // _LOG_DEBUG("size: " << size);
          lenCount--;
        }
      while(lenCount > 0);

      return size;
    }
}

void
DerNode::encode(ostream& start)
{
  start.write((const char*)&header_[0], header_.size());
  start.write((const char*)&payload_[0], payload_.size());
}

void
DerNode::decode(istream& start)
{
  int payloadSize = decodeHeader(start);
  // _LOG_DEBUG("payloadSize: " << payloadSize);
  if(payloadSize > 0 )
    {
      char buf[payloadSize];
      start.read(buf, payloadSize);
      payload_.insert(payload_.end(), buf, buf + payloadSize);
    }
}

shared_ptr<DerNode>
DerNode::parse(istream& start)
{
  int type = ((uint8_t)start.peek());

  // _LOG_DEBUG("Type: " << hex << setw(2) << setfill('0') << type);
  switch(type) {
    case DER_BOOLEAN:
      return shared_ptr<DerBool>(new DerBool(start));
    case DER_INTEGER:
      return shared_ptr<DerInteger>(new DerInteger(start));
    case DER_BIT_STRING:
      return shared_ptr<DerBitString>(new DerBitString(start));
    case DER_OCTET_STRING:
      return shared_ptr<DerOctetString>(new DerOctetString(start));
    case DER_NULL:
      return shared_ptr<DerNull>(new DerNull(start));
    case DER_OBJECT_IDENTIFIER:
      return shared_ptr<DerOid>(new DerOid(start));
    case DER_SEQUENCE:
      return shared_ptr<DerSequence>(new DerSequence(start));
    case DER_PRINTABLE_STRING:
      return shared_ptr<DerPrintableString>(new DerPrintableString(start));
    case DER_GENERALIZED_TIME:
      return shared_ptr<DerGtime>(new DerGtime(start));
    default:
      throw DerDecodingException("Unimplemented DER types");
    }
}

/*
 * DerComplex
 */
DerComplex::DerComplex()
  :DerNode(),
   childChanged_(false),
   size_(0)
{}

DerComplex::DerComplex(DerType type)
  :DerNode(type),
   childChanged_(false),
   size_(0)
{}

DerComplex::DerComplex(istream& start)
  :DerNode(),
   childChanged_(false),
   size_(0)
{
  size_ = DerNode::decodeHeader(start);
  // _LOG_DEBUG("Size: " << size_);

  int accSize = 0;

  while(accSize < size_)
    {
      // _LOG_DEBUG("accSize: " << accSize);
      shared_ptr<DerNode> nodePtr = DerNode::parse(start);
      accSize += nodePtr->getSize();
      addChild(nodePtr, false);
    }
}

DerComplex::~DerComplex()
{}

int
DerComplex::getSize()
{
  if(childChanged_)
    {
	updateSize();
	childChanged_ = false;
    }

  header_.clear();
  DerNode::encodeHeader(size_);
  return size_ + header_.size();
}

shared_ptr<vector<uint8_t> >
DerComplex::getRaw()
{
  shared_ptr<vector<uint8_t> > blob(new vector<uint8_t>());
  blob->insert(blob->end(), header_.begin(), header_.end());

  DerNodePtrList::iterator it = nodeList_.begin();
  for(; it != nodeList_.end(); it++)
    {
      shared_ptr<vector<uint8_t> > childBlob = (*it)->getRaw();
      blob->insert(blob->end(), childBlob->begin(), childBlob->end());
    }
  return blob;
}

void
DerComplex::updateSize()
{
  int newSize = 0;

  DerNodePtrList::iterator it = nodeList_.begin();
  for(; it != nodeList_.end(); it++)
    {
	newSize += (*it)->getSize();
    }

  size_ = newSize;
  childChanged_ = false;
}

void
DerComplex::addChild(shared_ptr<DerNode> nodePtr, bool notifyParent)
{
  nodePtr->setParent(this);

  nodeList_.push_back(nodePtr);

  if(!notifyParent)
    return;

  if(childChanged_)
    return;
  else
    childChanged_ = true;

  if(0 != parent_)
    parent_->setChildChanged();
}

void
DerComplex::setChildChanged()
{
  if(0 != parent_ && !childChanged_)
    {
      parent_->setChildChanged();
      childChanged_ = true;
    }
  else
    childChanged_ = true;
}

void
DerComplex::encode(ostream& start)
{
  updateSize();
  header_.clear();

  DerNode::encodeHeader(size_);

  start.write((const char*)&header_[0], header_.size());

  DerNodePtrList::iterator it = nodeList_.begin();
  for(; it != nodeList_.end(); it++)
    (*it)->encode(start);
}

/*
 * DerByteString
 */
DerByteString::DerByteString(const string& str, DerType type)
  :DerNode(type)
{
  payload_.insert(payload_.end(), str.begin(), str.end());

  DerNode::encodeHeader(payload_.size());
}

DerByteString::DerByteString(const std::vector<uint8_t>& blob, DerType type)
  :DerNode(type)
{
  payload_.insert(payload_.end(), blob.begin(), blob.end());

  DerNode::encodeHeader(payload_.size());
}

DerByteString::DerByteString(istream& start)
  :DerNode(start)
{}

DerByteString::~DerByteString()
{}

/*
 * DerBool
 */
DerBool::DerBool(bool value)
  :DerNode(DER_BOOLEAN)

{
  char payload = (value ? 0xFF : 0x00);
  payload_.push_back(payload);

  DerNode::encodeHeader(payload_.size());
}

DerBool::DerBool(istream& start)
  :DerNode(start)
{}

DerBool::~DerBool()
{}

/*
 * DerInteger
 */
DerInteger::DerInteger(const vector<uint8_t>& blob)
  :DerNode(DER_INTEGER)
{
  payload_.insert(payload_.end(), blob.begin(), blob.end());

  DerNode::encodeHeader(payload_.size());
}

DerInteger::DerInteger(istream& start)
  :DerNode(start)
{}

DerInteger::~DerInteger()
{}

/*
 * DerBitString
 */
DerBitString::DerBitString(const vector<uint8_t>& blob, uint8_t paddingLen)
  :DerNode(DER_BIT_STRING)
{
  payload_.push_back((char)paddingLen);
  payload_.insert(payload_.end(), blob.begin(), blob.end());

  DerNode::encodeHeader(payload_.size());
}

DerBitString::DerBitString(istream& start)
  :DerNode(start)
{}

DerBitString::~DerBitString()
{}

/*
 * DerOctetString
 */
DerOctetString::DerOctetString(const string& str)
  :DerByteString(str, DER_OCTET_STRING)
{}

DerOctetString::DerOctetString(const vector<uint8_t>& blob)
  :DerByteString(blob, DER_OCTET_STRING)
{}

DerOctetString::DerOctetString(istream& start)
  :DerByteString(start)
{}

DerOctetString::~DerOctetString()
{}

/*
 * DerNull
 */
DerNull::DerNull()
  :DerNode(DER_NULL)
{
  DerNode::encodeHeader(0);
}

DerNull::DerNull(istream& start)
  :DerNode(start)
{}

DerNull::~DerNull()
{}

/*
 * DerOid
 */
DerOid::DerOid(const OID& oid)
  :DerNode(DER_OBJECT_IDENTIFIER)
{
  prepareEncoding(oid.getIntegerList());
}

DerOid::DerOid(const string& oidStr)
  :DerNode(DER_OBJECT_IDENTIFIER)
{
  vector<int> value;

  string str = oidStr + ".";

  size_t pos = 0;
  size_t ppos = 0;

  while(string::npos != pos){
    ppos = pos;

    pos = str.find_first_of('.', pos);
    if(string::npos == pos)
	break;

    value.push_back(atoi(str.substr(ppos, pos - ppos).c_str()));

    pos++;
  }

  prepareEncoding(value);
}

DerOid::DerOid(const vector<int>& value)
  :DerNode(DER_OBJECT_IDENTIFIER)
{
  prepareEncoding(value);
}

DerOid::DerOid(istream& start)
  :DerNode(start)
{}

DerOid::~DerOid()
{}

void
DerOid::prepareEncoding(const vector<int>& value)
{
  ostringstream os;

  int firstNumber = 0;

  if(value.size() >= 1){
    if(0 <= value[0] && 2 >= value[0])
	firstNumber = value[0] * 40;
    else
	throw DerEncodingException("first integer of oid is out of range");
  }
  else
    throw DerEncodingException("no integer in oid");

  if(value.size() >= 2){
    if(0 <= value[1] && 39 >= value[1])
	firstNumber += value[1];
    else
	throw DerEncodingException("second integer of oid is out of range");
  }

  encode128(firstNumber, os);

  if(value.size() > 2){
    int i = 2;
    for(; i < value.size(); i++)
	encode128(value[i], os);
  }

  string output = os.str();
  DerNode::encodeHeader(output.size());

  payload_.insert(payload_.end(), output.begin(), output.end());
}

void
DerOid::encode128(int value, ostringstream& os)
{
  int mask = (1 << 7) - 1;

  if(128 > value)
    {
	uint8_t singleByte = (uint8_t) mask & value;
	os.write((char *)&singleByte, 1);
    }
  else{
    uint8_t buf[(sizeof(value)*8 + 6)/7 + 1];
    uint8_t *p = &(buf[sizeof(buf)-1]);
    int n = 1;

    p[0] = (uint8_t)(value & mask);
    value >>= 7;

    while(value != 0)
	{
	  (--p)[0] = (uint8_t)((value & mask) | (1 << 7));
	  n++;
	  value >>= 7;
	}

    os.write((char *)p, n);
  }
}

int
DerOid::decode128(int & offset)
{
  uint8_t flagMask = 0x80;
  int result = 0;
  while(payload_[offset] & flagMask){
    result = 128 * result + (uint8_t) payload_[offset] - 128;
    offset++;
  }

  result = result * 128 + payload_[offset];
  offset++;

  return result;
}

/*
 * DerSequence
 */
DerSequence::DerSequence()
  :DerComplex(DER_SEQUENCE)
{}

DerSequence::DerSequence(istream& start)
  :DerComplex(start)
{}

DerSequence::~DerSequence()
{}

/*
 * DerPrintableString
 */
DerPrintableString::DerPrintableString(const string& str)
  :DerByteString(str, DER_PRINTABLE_STRING)
{}

DerPrintableString::DerPrintableString(const vector<uint8_t>& blob)
  :DerByteString(blob, DER_PRINTABLE_STRING)
{}

DerPrintableString::DerPrintableString(istream& start)
  :DerByteString(start)
{}

DerPrintableString::~DerPrintableString()
{}

/*
 * DerGtime
 */
DerGtime::DerGtime(const Time& time)
  :DerNode(DER_GENERALIZED_TIME)
{
  string pTimeStr = toIsoString(time);
  int index = pTimeStr.find_first_of('T');
  string derTime = pTimeStr.substr(0, index) + pTimeStr.substr(index+1, pTimeStr.size() - index -1) + "Z";
  payload_.insert(payload_.end(), derTime.begin(), derTime.end());

  DerNode::encodeHeader(payload_.size());
}

DerGtime::DerGtime(istream& start)
  :DerNode(start)
{}

DerGtime::~DerGtime()
{}

string DerGtime::toIsoString(const Time& time)
{
#if 1
  throw std::runtime_error("not implemented");
#endif
}

Time DerGtime::fromIsoString(const string& isoString)
{
#if 1
  throw std::runtime_error("not implemented");
#endif
}

} // der

}
<commit_msg>code style: der.cpp: replace tab with space.<commit_after>/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
 * Copyright (C) 2013 Regents of the University of California.
 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
 * See COPYING for copyright and distribution information.
 */

#if 1 // TODO: Remove this when we don't throw "not implemented".
#include <stdexcept>
#endif
#include "der-exception.hpp"
#include "../../util/logging.hpp"
#include "der.hpp"

INIT_LOGGER("ndn.der.DER");

using namespace std;
using namespace ndn::ptr_lib;

namespace ndn {

namespace der {

/*
 * DerNode
 */
DerNode::DerNode()
  :parent_(0)
{}

DerNode::DerNode(DerType type)
  :type_(type),
   parent_(0)
{}

DerNode::DerNode(std::istream& start)
  :parent_(0)
{
  decode(start);
}

DerNode::~DerNode()
{}

void
DerNode::encodeHeader(int size)
{
  header_.push_back((char)type_);

  if(size >= 127)
    {
      int val = size;
      char buf[sizeof(val) + 1];
      char *p = &(buf[sizeof(buf)-1]);
      int n = 0;
      int mask = (1 << 8) - 1;

      while(val != 0)
        {
          p[0] = (char)(val & mask);
          p--;
          n++;
          val >>= 8;
        }

      p[0] = (char)((1<<7) | n);
      n++;

      header_.insert(header_.end(), p, p+n);
    }
  else if(size >= 0)
    {
      header_.push_back((char)size);
    }
  else
    throw NegativeLengthException("Negative length");
}

int
DerNode::decodeHeader(istream& start)
{
  uint8_t type = start.get();
  // char type = start.get();
  header_.push_back(type);
  type_ = static_cast<DerType>((int)type);

  uint8_t sizeLen = start.get();
  // char sizeLen = start.get();
  header_.push_back(sizeLen);

  bool longFormat = sizeLen & (1 << 7);

  if(!longFormat)
    {
      // _LOG_DEBUG("Short Format");
      // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
      return (int)sizeLen;
    }
  else
    {
      // _LOG_DEBUG("Long Format");
      uint8_t byte;
      // char byte;
      int lenCount = sizeLen & ((1<<7) - 1);
      // _LOG_DEBUG("sizeLen: " << (int)sizeLen);
      // _LOG_DEBUG("mask: " << (int)((1<<7) - 1));
      // _LOG_DEBUG("lenCount: " << (int)lenCount);
      int size = 0;
      do
        {
          byte = start.get();
          header_.push_back(byte);
          size = size * 256 + (int)byte;
          // _LOG_DEBUG("byte: " << (int)byte);
          // _LOG_DEBUG("size: " << size);
          lenCount--;
        }
      while(lenCount > 0);

      return size;
    }
}

void
DerNode::encode(ostream& start)
{
  start.write((const char*)&header_[0], header_.size());
  start.write((const char*)&payload_[0], payload_.size());
}

void
DerNode::decode(istream& start)
{
  int payloadSize = decodeHeader(start);
  // _LOG_DEBUG("payloadSize: " << payloadSize);
  if(payloadSize > 0 )
    {
      char buf[payloadSize];
      start.read(buf, payloadSize);
      payload_.insert(payload_.end(), buf, buf + payloadSize);
    }
}

shared_ptr<DerNode>
DerNode::parse(istream& start)
{
  int type = ((uint8_t)start.peek());

  // _LOG_DEBUG("Type: " << hex << setw(2) << setfill('0') << type);
  switch(type) {
    case DER_BOOLEAN:
      return shared_ptr<DerBool>(new DerBool(start));
    case DER_INTEGER:
      return shared_ptr<DerInteger>(new DerInteger(start));
    case DER_BIT_STRING:
      return shared_ptr<DerBitString>(new DerBitString(start));
    case DER_OCTET_STRING:
      return shared_ptr<DerOctetString>(new DerOctetString(start));
    case DER_NULL:
      return shared_ptr<DerNull>(new DerNull(start));
    case DER_OBJECT_IDENTIFIER:
      return shared_ptr<DerOid>(new DerOid(start));
    case DER_SEQUENCE:
      return shared_ptr<DerSequence>(new DerSequence(start));
    case DER_PRINTABLE_STRING:
      return shared_ptr<DerPrintableString>(new DerPrintableString(start));
    case DER_GENERALIZED_TIME:
      return shared_ptr<DerGtime>(new DerGtime(start));
    default:
      throw DerDecodingException("Unimplemented DER types");
    }
}

/*
 * DerComplex
 */
DerComplex::DerComplex()
  :DerNode(),
   childChanged_(false),
   size_(0)
{}

DerComplex::DerComplex(DerType type)
  :DerNode(type),
   childChanged_(false),
   size_(0)
{}

DerComplex::DerComplex(istream& start)
  :DerNode(),
   childChanged_(false),
   size_(0)
{
  size_ = DerNode::decodeHeader(start);
  // _LOG_DEBUG("Size: " << size_);

  int accSize = 0;

  while(accSize < size_)
    {
      // _LOG_DEBUG("accSize: " << accSize);
      shared_ptr<DerNode> nodePtr = DerNode::parse(start);
      accSize += nodePtr->getSize();
      addChild(nodePtr, false);
    }
}

DerComplex::~DerComplex()
{}

int
DerComplex::getSize()
{
  if(childChanged_)
    {
  updateSize();
  childChanged_ = false;
    }

  header_.clear();
  DerNode::encodeHeader(size_);
  return size_ + header_.size();
}

shared_ptr<vector<uint8_t> >
DerComplex::getRaw()
{
  shared_ptr<vector<uint8_t> > blob(new vector<uint8_t>());
  blob->insert(blob->end(), header_.begin(), header_.end());

  DerNodePtrList::iterator it = nodeList_.begin();
  for(; it != nodeList_.end(); it++)
    {
      shared_ptr<vector<uint8_t> > childBlob = (*it)->getRaw();
      blob->insert(blob->end(), childBlob->begin(), childBlob->end());
    }
  return blob;
}

void
DerComplex::updateSize()
{
  int newSize = 0;

  DerNodePtrList::iterator it = nodeList_.begin();
  for(; it != nodeList_.end(); it++)
    {
  newSize += (*it)->getSize();
    }

  size_ = newSize;
  childChanged_ = false;
}

void
DerComplex::addChild(shared_ptr<DerNode> nodePtr, bool notifyParent)
{
  nodePtr->setParent(this);

  nodeList_.push_back(nodePtr);

  if(!notifyParent)
    return;

  if(childChanged_)
    return;
  else
    childChanged_ = true;

  if(0 != parent_)
    parent_->setChildChanged();
}

void
DerComplex::setChildChanged()
{
  if(0 != parent_ && !childChanged_)
    {
      parent_->setChildChanged();
      childChanged_ = true;
    }
  else
    childChanged_ = true;
}

void
DerComplex::encode(ostream& start)
{
  updateSize();
  header_.clear();

  DerNode::encodeHeader(size_);

  start.write((const char*)&header_[0], header_.size());

  DerNodePtrList::iterator it = nodeList_.begin();
  for(; it != nodeList_.end(); it++)
    (*it)->encode(start);
}

/*
 * DerByteString
 */
DerByteString::DerByteString(const string& str, DerType type)
  :DerNode(type)
{
  payload_.insert(payload_.end(), str.begin(), str.end());

  DerNode::encodeHeader(payload_.size());
}

DerByteString::DerByteString(const std::vector<uint8_t>& blob, DerType type)
  :DerNode(type)
{
  payload_.insert(payload_.end(), blob.begin(), blob.end());

  DerNode::encodeHeader(payload_.size());
}

DerByteString::DerByteString(istream& start)
  :DerNode(start)
{}

DerByteString::~DerByteString()
{}

/*
 * DerBool
 */
DerBool::DerBool(bool value)
  :DerNode(DER_BOOLEAN)

{
  char payload = (value ? 0xFF : 0x00);
  payload_.push_back(payload);

  DerNode::encodeHeader(payload_.size());
}

DerBool::DerBool(istream& start)
  :DerNode(start)
{}

DerBool::~DerBool()
{}

/*
 * DerInteger
 */
DerInteger::DerInteger(const vector<uint8_t>& blob)
  :DerNode(DER_INTEGER)
{
  payload_.insert(payload_.end(), blob.begin(), blob.end());

  DerNode::encodeHeader(payload_.size());
}

DerInteger::DerInteger(istream& start)
  :DerNode(start)
{}

DerInteger::~DerInteger()
{}

/*
 * DerBitString
 */
DerBitString::DerBitString(const vector<uint8_t>& blob, uint8_t paddingLen)
  :DerNode(DER_BIT_STRING)
{
  payload_.push_back((char)paddingLen);
  payload_.insert(payload_.end(), blob.begin(), blob.end());

  DerNode::encodeHeader(payload_.size());
}

DerBitString::DerBitString(istream& start)
  :DerNode(start)
{}

DerBitString::~DerBitString()
{}

/*
 * DerOctetString
 */
DerOctetString::DerOctetString(const string& str)
  :DerByteString(str, DER_OCTET_STRING)
{}

DerOctetString::DerOctetString(const vector<uint8_t>& blob)
  :DerByteString(blob, DER_OCTET_STRING)
{}

DerOctetString::DerOctetString(istream& start)
  :DerByteString(start)
{}

DerOctetString::~DerOctetString()
{}

/*
 * DerNull
 */
DerNull::DerNull()
  :DerNode(DER_NULL)
{
  DerNode::encodeHeader(0);
}

DerNull::DerNull(istream& start)
  :DerNode(start)
{}

DerNull::~DerNull()
{}

/*
 * DerOid
 */
DerOid::DerOid(const OID& oid)
  :DerNode(DER_OBJECT_IDENTIFIER)
{
  prepareEncoding(oid.getIntegerList());
}

DerOid::DerOid(const string& oidStr)
  :DerNode(DER_OBJECT_IDENTIFIER)
{
  vector<int> value;

  string str = oidStr + ".";

  size_t pos = 0;
  size_t ppos = 0;

  while(string::npos != pos){
    ppos = pos;

    pos = str.find_first_of('.', pos);
    if(string::npos == pos)
  break;

    value.push_back(atoi(str.substr(ppos, pos - ppos).c_str()));

    pos++;
  }

  prepareEncoding(value);
}

DerOid::DerOid(const vector<int>& value)
  :DerNode(DER_OBJECT_IDENTIFIER)
{
  prepareEncoding(value);
}

DerOid::DerOid(istream& start)
  :DerNode(start)
{}

DerOid::~DerOid()
{}

void
DerOid::prepareEncoding(const vector<int>& value)
{
  ostringstream os;

  int firstNumber = 0;

  if(value.size() >= 1){
    if(0 <= value[0] && 2 >= value[0])
  firstNumber = value[0] * 40;
    else
  throw DerEncodingException("first integer of oid is out of range");
  }
  else
    throw DerEncodingException("no integer in oid");

  if(value.size() >= 2){
    if(0 <= value[1] && 39 >= value[1])
  firstNumber += value[1];
    else
  throw DerEncodingException("second integer of oid is out of range");
  }

  encode128(firstNumber, os);

  if(value.size() > 2){
    int i = 2;
    for(; i < value.size(); i++)
  encode128(value[i], os);
  }

  string output = os.str();
  DerNode::encodeHeader(output.size());

  payload_.insert(payload_.end(), output.begin(), output.end());
}

void
DerOid::encode128(int value, ostringstream& os)
{
  int mask = (1 << 7) - 1;

  if(128 > value)
    {
  uint8_t singleByte = (uint8_t) mask & value;
  os.write((char *)&singleByte, 1);
    }
  else{
    uint8_t buf[(sizeof(value)*8 + 6)/7 + 1];
    uint8_t *p = &(buf[sizeof(buf)-1]);
    int n = 1;

    p[0] = (uint8_t)(value & mask);
    value >>= 7;

    while(value != 0)
  {
    (--p)[0] = (uint8_t)((value & mask) | (1 << 7));
    n++;
    value >>= 7;
  }

    os.write((char *)p, n);
  }
}

int
DerOid::decode128(int & offset)
{
  uint8_t flagMask = 0x80;
  int result = 0;
  while(payload_[offset] & flagMask){
    result = 128 * result + (uint8_t) payload_[offset] - 128;
    offset++;
  }

  result = result * 128 + payload_[offset];
  offset++;

  return result;
}

/*
 * DerSequence
 */
DerSequence::DerSequence()
  :DerComplex(DER_SEQUENCE)
{}

DerSequence::DerSequence(istream& start)
  :DerComplex(start)
{}

DerSequence::~DerSequence()
{}

/*
 * DerPrintableString
 */
DerPrintableString::DerPrintableString(const string& str)
  :DerByteString(str, DER_PRINTABLE_STRING)
{}

DerPrintableString::DerPrintableString(const vector<uint8_t>& blob)
  :DerByteString(blob, DER_PRINTABLE_STRING)
{}

DerPrintableString::DerPrintableString(istream& start)
  :DerByteString(start)
{}

DerPrintableString::~DerPrintableString()
{}

/*
 * DerGtime
 */
DerGtime::DerGtime(const Time& time)
  :DerNode(DER_GENERALIZED_TIME)
{
  string pTimeStr = toIsoString(time);
  int index = pTimeStr.find_first_of('T');
  string derTime = pTimeStr.substr(0, index) + pTimeStr.substr(index+1, pTimeStr.size() - index -1) + "Z";
  payload_.insert(payload_.end(), derTime.begin(), derTime.end());

  DerNode::encodeHeader(payload_.size());
}

DerGtime::DerGtime(istream& start)
  :DerNode(start)
{}

DerGtime::~DerGtime()
{}

string DerGtime::toIsoString(const Time& time)
{
#if 1
  throw std::runtime_error("not implemented");
#endif
}

Time DerGtime::fromIsoString(const string& isoString)
{
#if 1
  throw std::runtime_error("not implemented");
#endif
}

} // der

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/net/SslSocket.h"

#include "db/logging/Logging.h"
#include "db/io/PeekInputStream.h"
#include "db/net/SocketDefinitions.h"
#include "db/net/SocketInputStream.h"
#include "db/net/SocketOutputStream.h"
#include "db/rt/DynamicObject.h"

#include <openssl/err.h>

using namespace db::io;
using namespace db::net;
using namespace db::rt;

/**
 * Certificate verification callback. Called whenever a handshake is performed
 * to check the certificate's common name against the host or against a
 * provided alternatives list. This method will be called regardless of whether
 * or not peer verification is on.
 *
 * @param preverifyOk 1 if the current certificate passed, 0 if not.
 * @param ctx the X.509 certificate store context for certificate verification.
 *
 * @return 0 to stop certificate chain verification immediately and fail the
 *         current handshake (but the connection will only fail if peer
 *         verification is on), 1 to continue -- if 1 is always returned, then
 *         the SSL connection will not be terminated due to any certificate
 *         verification failures, but any errors that were set will be
 *         available in X509_STORE_CTX.
 */
static int verifyCallback(int preverifyOk, X509_STORE_CTX *ctx)
{
   // only check common name for peer certificate, which is at depth level 0
   // and only check if the certificate was properly signed/verified
   int depth = X509_STORE_CTX_get_error_depth(ctx);
   if(depth == 0 && preverifyOk)
   {
      // get associated SSL socket
      SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(
         ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
      SslSocket* self = (SslSocket*)SSL_get_ex_data(ssl, 0);

      // get subject name
      X509* x509 = X509_STORE_CTX_get_current_cert(ctx);
      X509_NAME* name = X509_get_subject_name(x509);

      // find a common name that matches
      bool commonNameFound = false;
      X509_NAME_ENTRY* entry;
      ASN1_STRING* str;
      unsigned char* value;
      int i = -1;
      do
      {
         i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
         if(i != -1)
         {
            entry = X509_NAME_get_entry(name, i);
            str = X509_NAME_ENTRY_get_data(entry);
            if(ASN1_STRING_to_UTF8(&value, str) != -1)
            {
               if(self->verifyCommonName((const char*)value))
               {
                  commonNameFound = true;
               }
               else
               {
                  // log error
                  DB_CAT_DEBUG(DB_NET_CAT,
                     "X.509 certificate verification failure, "
                     "no match found for common name '%s'", value);
               }
               OPENSSL_free(value);
            }
         }
      }
      while(i != -1 && !commonNameFound);

      // if common name not found then certificate verification failure
      if(!commonNameFound)
      {
         // the certificate is signed and valid, but is being used
         // for a common name different from what was requested
         X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE);
         preverifyOk = 0;
      }
   }

   return preverifyOk;
}

SslSocket::SslSocket(
   SslContext* context, TcpSocket* socket, bool client, bool cleanup) :
   SocketWrapper(socket, cleanup)
{
   // create ssl object
   mSSL = context->createSSL(socket, client);

   // associate this socket with the SSL instance
   SSL_set_ex_data(mSSL, 0, this);

   // allocate bio pair using default sizes (large enough for SSL records)
   BIO_new_bio_pair(&mSSLBio, 0, &mSocketBio, 0);

   // assign SSL BIO to SSL
   SSL_set_bio(mSSL, mSSLBio, mSSLBio);

   // no ssl session negotiated yet
   mSessionNegotiated = false;

   // create input and output streams
   mInputStream = new PeekInputStream(new SocketInputStream(this), true);
   mOutputStream = new SocketOutputStream(this);
}

SslSocket::~SslSocket()
{
   // free SSL object (implicitly frees SSL BIO)
   SSL_free(mSSL);

   // free Socket BIO
   BIO_free(mSocketBio);

   // destruct input and output streams
   delete mInputStream;
   delete mOutputStream;

   // free verify common names
   for(VerifyCommonNameList::iterator i = mVerifyCommonNames.begin();
       i != mVerifyCommonNames.end(); i++)
   {
      if(*i != NULL)
      {
         free((char*)*i);
      }
   }
}

void SslSocket::setSession(SslSession* session)
{
   if(session != NULL && (*session) != NULL && (*session)->session != NULL)
   {
      SSL_set_session(mSSL, (*session)->session);
   }
}

SslSession SslSocket::getSession()
{
   // get SSL_SESSION and increment reference count
   SSL_SESSION* s = SSL_get1_session(mSSL);
   SslSession rval(new SslSessionImpl(s));
   return rval;
}

void SslSocket::addVerifyCommonName(const char* commonName)
{
   // add common name to list
   mVerifyCommonNames.push_back(
      (commonName != NULL) ? strdup(commonName) : NULL);

   // set verify callback (retain verify mode) if adding first common name
   if(mVerifyCommonNames.size() == 1)
   {
      SSL_set_verify(mSSL, mSSL->verify_mode, verifyCallback);
   }
}

std::vector<const char*>& SslSocket::getVerifyCommonNames()
{
   return mVerifyCommonNames;
}

bool SslSocket::verifyCommonName(const char* commonName)
{
   bool rval = false;

   for(VerifyCommonNameList::iterator i = mVerifyCommonNames.begin();
       !rval && i != mVerifyCommonNames.end(); i++)
   {
      if(strcmp(*i, commonName) == 0)
      {
         // common name matches
         rval = true;
      }
   }

   return rval;
}

bool SslSocket::performHandshake()
{
   bool rval = true;

   // do SSL_do_handshake()
   int ret = 0;
   while(rval && (ret = SSL_do_handshake(mSSL)) <= 0)
   {
      // get the last error
      int error = SSL_get_error(mSSL, ret);
      switch(error)
      {
         case SSL_ERROR_ZERO_RETURN:
         {
            ExceptionRef e = new Exception(
               "Could not perform SSL handshake. Socket closed.",
               SOCKET_EXCEPTION_TYPE ".SslHandshakeError");
            Exception::setLast(e, false);
            rval = false;
            break;
         }
         case SSL_ERROR_WANT_READ:
         {
            // more data is required from the socket
            ret = tcpRead();
            if(ret <= 0)
            {
               ExceptionRef e = new Exception(
                  "Could not perform SSL handshake. Socket closed.",
                  SOCKET_EXCEPTION_TYPE ".SslHandshakeError");
               Exception::setLast(e, (ret < 0));
               rval = false;
            }
            break;
         }
         case SSL_ERROR_WANT_WRITE:
            // data must be flushed to the socket
            rval = tcpWrite();
            break;
         default:
         {
            // an error occurred
            ExceptionRef e = new Exception(
               "Could not perform SSL handshake.",
               SOCKET_EXCEPTION_TYPE ".SslHandshakeError");
            e->getDetails()["error"] = SslContext::getSslErrorStrings();
            Exception::setLast(e, false);
            rval = false;
            break;
         }
      }
   }

   if(rval)
   {
      // session negotiated
      mSessionNegotiated = true;
   }

   return mSessionNegotiated;
}

void SslSocket::close()
{
   if(isConnected())
   {
      // shutdown SSL
      SSL_shutdown(mSSL);
   }

   // close connection
   getSocket()->close();
}

bool SslSocket::send(const char* b, int length)
{
   bool rval = true;

   if(!isConnected())
   {
      ExceptionRef e = new Exception(
         "Cannot write to unconnected socket.",
         SOCKET_EXCEPTION_TYPE ".WriteError");
      Exception::setLast(e, false);
      rval = false;
   }
   else
   {
      // perform a handshake as necessary
      if(!mSessionNegotiated)
      {
         rval = performHandshake();
      }

      // do SSL_write() (implicit handshake performed as necessary)
      int ret = 0;
      bool closed = false;
      while(rval && !closed && (ret <= SSL_write(mSSL, b, length)) <= 0)
      {
         // get the last error
         int error = SSL_get_error(mSSL, ret);
         switch(error)
         {
            case SSL_ERROR_ZERO_RETURN:
            {
               // the connection was shutdown
               ExceptionRef e = new Exception(
                  "Could not write to socket. Socket closed.",
                  SOCKET_EXCEPTION_TYPE ".WriteError");
               e->getDetails()["error"] = SslContext::getSslErrorStrings();
               Exception::setLast(e, false);
               rval = false;
               break;
            }
            case SSL_ERROR_WANT_READ:
               // more data is required from the socket
               ret = tcpRead();
               if(ret <= 0)
               {
                  // the connection was shutdown
                  ExceptionRef e = new Exception(
                     "Could not write to socket. Socket closed.",
                     SOCKET_EXCEPTION_TYPE ".WriteError");
                  e->getDetails()["error"] = strerror(errno);
                  Exception::setLast(e, (ret < 0));
                  rval = false;
               }
               break;
            case SSL_ERROR_WANT_WRITE:
               // data must be flushed to the socket
               rval = tcpWrite();
               break;
            default:
            {
               // an error occurred
               ExceptionRef e = new Exception(
                  "Could not write to socket.",
                  SOCKET_EXCEPTION_TYPE ".WriteError");
               e->getDetails()["error"] = SslContext::getSslErrorStrings();
               Exception::setLast(e, false);
               rval = false;
               break;
            }
         }
      }

      // flush all data to the socket
      rval = rval && tcpWrite();
   }

   return rval;
}

int SslSocket::receive(char* b, int length)
{
   int rval = 0;

   if(!isConnected())
   {
      ExceptionRef e = new Exception(
         "Cannot read from unconnected socket.",
         SOCKET_EXCEPTION_TYPE ".ReadError");
      Exception::setLast(e, false);
      rval = -1;
   }
   else
   {
      // perform a handshake as necessary
      if(!mSessionNegotiated)
      {
         if(!performHandshake())
         {
            rval = -1;
         }
      }

      // do SSL_read() (implicit handshake performed as necessary)
      int ret = 0;
      bool closed = false;
      while(rval != -1 && !closed && (ret = SSL_read(mSSL, b, length)) <= 0)
      {
         // get the last error
         int error = SSL_get_error(mSSL, ret);
         switch(error)
         {
            case SSL_ERROR_ZERO_RETURN:
               // the connection was shutdown
               closed = true;
               break;
            case SSL_ERROR_WANT_READ:
               // more data is required from the socket
               ret = tcpRead();
               if(ret == 0)
               {
                  // the connection was shutdown properly
                  closed = true;
               }
               else if(ret == -1)
               {
                  // error in writing to socket
                  ExceptionRef e = new Exception(
                     "Could not read from socket.",
                     SOCKET_EXCEPTION_TYPE ".ReadError");
                  Exception::setLast(e, true);
                  rval = -1;
               }
               break;
            case SSL_ERROR_WANT_WRITE:
               // data must be flushed to the socket
               if(!tcpWrite())
               {
                  rval = -1;
               }
               break;
            default:
            {
               // an error occurred
               ExceptionRef e = new Exception(
                  "Could not read from socket.",
                  SOCKET_EXCEPTION_TYPE ".ReadError");
               e->getDetails()["error"] = SslContext::getSslErrorStrings();
               Exception::setLast(e, false);
               rval = -1;
               break;
            }
         }
      }

      // set number of bytes read
      if(rval != -1)
      {
         rval = (closed) ? 0 : ret;
      }
   }

   return rval;
}

InputStream* SslSocket::getInputStream()
{
   return mInputStream;
}

OutputStream* SslSocket::getOutputStream()
{
   return mOutputStream;
}

int SslSocket::tcpRead()
{
   int rval = 0;

   // flush the Socket BIO
   if(tcpWrite())
   {
      // determine how many bytes are required from the Socket BIO
      size_t length = BIO_ctrl_get_read_request(mSocketBio);
      if(length > 0)
      {
         // read from the underlying socket
         InputStream* is = mSocket->getInputStream();
         char b[length];
         int numBytes = 0;
         while(length > 0 && (numBytes = is->read(b, length)) > 0)
         {
            // write to Socket BIO
            BIO_write(mSocketBio, b, numBytes);

            // decrement remaining bytes to read
            length -= numBytes;

            // update bytes read
            rval = (rval == -1) ? numBytes : rval + numBytes;
         }

         if(numBytes < 0)
         {
            // exception reading from input stream
            rval = -1;
         }
      }
   }
   else
   {
      // exception during tcpWrite()
      rval = -1;
   }

   return rval;
}

bool SslSocket::tcpWrite()
{
   bool rval = true;

   // determine how many bytes can be read from the Socket BIO
   size_t length = BIO_ctrl_pending(mSocketBio);
   if(length > 0)
   {
      // read from the Socket BIO
      char b[length];
      int numBytes = 0;
      while(rval && length > 0 &&
            (numBytes = BIO_read(mSocketBio, b, length)) > 0)
      {
         // write to underlying socket, decrement length left to read
         rval = mSocket->getOutputStream()->write(b, numBytes);
         length -= numBytes;
      }
   }

   return rval;
}
<commit_msg>Added more logging information for when SSL common name failures arise.<commit_after>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/net/SslSocket.h"

#include "db/logging/Logging.h"
#include "db/io/PeekInputStream.h"
#include "db/net/SocketDefinitions.h"
#include "db/net/SocketInputStream.h"
#include "db/net/SocketOutputStream.h"
#include "db/rt/DynamicObject.h"

#include <openssl/err.h>

using namespace db::io;
using namespace db::net;
using namespace db::rt;

/**
 * Certificate verification callback. Called whenever a handshake is performed
 * to check the certificate's common name against the host or against a
 * provided alternatives list. This method will be called regardless of whether
 * or not peer verification is on.
 *
 * @param preverifyOk 1 if the current certificate passed, 0 if not.
 * @param ctx the X.509 certificate store context for certificate verification.
 *
 * @return 0 to stop certificate chain verification immediately and fail the
 *         current handshake (but the connection will only fail if peer
 *         verification is on), 1 to continue -- if 1 is always returned, then
 *         the SSL connection will not be terminated due to any certificate
 *         verification failures, but any errors that were set will be
 *         available in X509_STORE_CTX.
 */
static int verifyCallback(int preverifyOk, X509_STORE_CTX *ctx)
{
   // only check common name for peer certificate, which is at depth level 0
   // and only check if the certificate was properly signed/verified
   int depth = X509_STORE_CTX_get_error_depth(ctx);
   if(depth == 0 && preverifyOk)
   {
      // get associated SSL socket
      SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(
         ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
      SslSocket* self = (SslSocket*)SSL_get_ex_data(ssl, 0);

      // get subject name
      X509* x509 = X509_STORE_CTX_get_current_cert(ctx);
      X509_NAME* name = X509_get_subject_name(x509);

      // find a common name that matches
      bool commonNameFound = false;
      X509_NAME_ENTRY* entry;
      ASN1_STRING* str;
      unsigned char* value;
      int i = -1;
      do
      {
         i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
         if(i != -1)
         {
            entry = X509_NAME_get_entry(name, i);
            str = X509_NAME_ENTRY_get_data(entry);
            if(ASN1_STRING_to_UTF8(&value, str) != -1)
            {
               if(self->verifyCommonName((const char*)value))
               {
                  commonNameFound = true;
               }
               OPENSSL_free(value);
            }
         }
      }
      while(i != -1 && !commonNameFound);

      // if common name not found then certificate verification failure
      if(!commonNameFound)
      {
         // the certificate is signed and valid, but is being used
         // for a common name different from what was requested
         X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE);
         preverifyOk = 0;
      }
   }

   return preverifyOk;
}

SslSocket::SslSocket(
   SslContext* context, TcpSocket* socket, bool client, bool cleanup) :
   SocketWrapper(socket, cleanup)
{
   // create ssl object
   mSSL = context->createSSL(socket, client);

   // associate this socket with the SSL instance
   SSL_set_ex_data(mSSL, 0, this);

   // allocate bio pair using default sizes (large enough for SSL records)
   BIO_new_bio_pair(&mSSLBio, 0, &mSocketBio, 0);

   // assign SSL BIO to SSL
   SSL_set_bio(mSSL, mSSLBio, mSSLBio);

   // no ssl session negotiated yet
   mSessionNegotiated = false;

   // create input and output streams
   mInputStream = new PeekInputStream(new SocketInputStream(this), true);
   mOutputStream = new SocketOutputStream(this);
}

SslSocket::~SslSocket()
{
   // free SSL object (implicitly frees SSL BIO)
   SSL_free(mSSL);

   // free Socket BIO
   BIO_free(mSocketBio);

   // destruct input and output streams
   delete mInputStream;
   delete mOutputStream;

   // free verify common names
   for(VerifyCommonNameList::iterator i = mVerifyCommonNames.begin();
       i != mVerifyCommonNames.end(); i++)
   {
      if(*i != NULL)
      {
         free((char*)*i);
      }
   }
}

void SslSocket::setSession(SslSession* session)
{
   if(session != NULL && (*session) != NULL && (*session)->session != NULL)
   {
      SSL_set_session(mSSL, (*session)->session);
   }
}

SslSession SslSocket::getSession()
{
   // get SSL_SESSION and increment reference count
   SSL_SESSION* s = SSL_get1_session(mSSL);
   SslSession rval(new SslSessionImpl(s));
   return rval;
}

void SslSocket::addVerifyCommonName(const char* commonName)
{
   // add common name to list
   mVerifyCommonNames.push_back(
      (commonName != NULL) ? strdup(commonName) : NULL);

   // set verify callback (retain verify mode) if adding first common name
   if(mVerifyCommonNames.size() == 1)
   {
      SSL_set_verify(mSSL, mSSL->verify_mode, verifyCallback);
   }
}

std::vector<const char*>& SslSocket::getVerifyCommonNames()
{
   return mVerifyCommonNames;
}

bool SslSocket::verifyCommonName(const char* commonName)
{
   bool rval = false;

   for(VerifyCommonNameList::iterator i = mVerifyCommonNames.begin();
       !rval && i != mVerifyCommonNames.end(); i++)
   {
      if(strcmp(*i, commonName) == 0)
      {
         // common name matches
         rval = true;
      }
   }

   // add useful logging output
   if(!rval)
   {
      std::string str;
      for(VerifyCommonNameList::iterator i = mVerifyCommonNames.begin();
          i != mVerifyCommonNames.end(); i++)
      {
         if(str.length() > 0)
         {
            str.push_back(',');
         }
         str.push_back('\'');
         str.append(*i);
         str.push_back('\'');
      }

      // log error
      DB_CAT_DEBUG(DB_NET_CAT,
         "X.509 certificate verification failure, "
         "no match found for common name '%s', permitted common names: %s",
         commonName, str.c_str());
   }

   return rval;
}

bool SslSocket::performHandshake()
{
   bool rval = true;

   // do SSL_do_handshake()
   int ret = 0;
   while(rval && (ret = SSL_do_handshake(mSSL)) <= 0)
   {
      // get the last error
      int error = SSL_get_error(mSSL, ret);
      switch(error)
      {
         case SSL_ERROR_ZERO_RETURN:
         {
            ExceptionRef e = new Exception(
               "Could not perform SSL handshake. Socket closed.",
               SOCKET_EXCEPTION_TYPE ".SslHandshakeError");
            Exception::setLast(e, false);
            rval = false;
            break;
         }
         case SSL_ERROR_WANT_READ:
         {
            // more data is required from the socket
            ret = tcpRead();
            if(ret <= 0)
            {
               ExceptionRef e = new Exception(
                  "Could not perform SSL handshake. Socket closed.",
                  SOCKET_EXCEPTION_TYPE ".SslHandshakeError");
               Exception::setLast(e, (ret < 0));
               rval = false;
            }
            break;
         }
         case SSL_ERROR_WANT_WRITE:
            // data must be flushed to the socket
            rval = tcpWrite();
            break;
         default:
         {
            // an error occurred
            ExceptionRef e = new Exception(
               "Could not perform SSL handshake.",
               SOCKET_EXCEPTION_TYPE ".SslHandshakeError");
            e->getDetails()["error"] = SslContext::getSslErrorStrings();
            Exception::setLast(e, false);
            rval = false;
            break;
         }
      }
   }

   if(rval)
   {
      // session negotiated
      mSessionNegotiated = true;
   }

   return mSessionNegotiated;
}

void SslSocket::close()
{
   if(isConnected())
   {
      // shutdown SSL
      SSL_shutdown(mSSL);
   }

   // close connection
   getSocket()->close();
}

bool SslSocket::send(const char* b, int length)
{
   bool rval = true;

   if(!isConnected())
   {
      ExceptionRef e = new Exception(
         "Cannot write to unconnected socket.",
         SOCKET_EXCEPTION_TYPE ".WriteError");
      Exception::setLast(e, false);
      rval = false;
   }
   else
   {
      // perform a handshake as necessary
      if(!mSessionNegotiated)
      {
         rval = performHandshake();
      }

      // do SSL_write() (implicit handshake performed as necessary)
      int ret = 0;
      bool closed = false;
      while(rval && !closed && (ret <= SSL_write(mSSL, b, length)) <= 0)
      {
         // get the last error
         int error = SSL_get_error(mSSL, ret);
         switch(error)
         {
            case SSL_ERROR_ZERO_RETURN:
            {
               // the connection was shutdown
               ExceptionRef e = new Exception(
                  "Could not write to socket. Socket closed.",
                  SOCKET_EXCEPTION_TYPE ".WriteError");
               e->getDetails()["error"] = SslContext::getSslErrorStrings();
               Exception::setLast(e, false);
               rval = false;
               break;
            }
            case SSL_ERROR_WANT_READ:
               // more data is required from the socket
               ret = tcpRead();
               if(ret <= 0)
               {
                  // the connection was shutdown
                  ExceptionRef e = new Exception(
                     "Could not write to socket. Socket closed.",
                     SOCKET_EXCEPTION_TYPE ".WriteError");
                  e->getDetails()["error"] = strerror(errno);
                  Exception::setLast(e, (ret < 0));
                  rval = false;
               }
               break;
            case SSL_ERROR_WANT_WRITE:
               // data must be flushed to the socket
               rval = tcpWrite();
               break;
            default:
            {
               // an error occurred
               ExceptionRef e = new Exception(
                  "Could not write to socket.",
                  SOCKET_EXCEPTION_TYPE ".WriteError");
               e->getDetails()["error"] = SslContext::getSslErrorStrings();
               Exception::setLast(e, false);
               rval = false;
               break;
            }
         }
      }

      // flush all data to the socket
      rval = rval && tcpWrite();
   }

   return rval;
}

int SslSocket::receive(char* b, int length)
{
   int rval = 0;

   if(!isConnected())
   {
      ExceptionRef e = new Exception(
         "Cannot read from unconnected socket.",
         SOCKET_EXCEPTION_TYPE ".ReadError");
      Exception::setLast(e, false);
      rval = -1;
   }
   else
   {
      // perform a handshake as necessary
      if(!mSessionNegotiated)
      {
         if(!performHandshake())
         {
            rval = -1;
         }
      }

      // do SSL_read() (implicit handshake performed as necessary)
      int ret = 0;
      bool closed = false;
      while(rval != -1 && !closed && (ret = SSL_read(mSSL, b, length)) <= 0)
      {
         // get the last error
         int error = SSL_get_error(mSSL, ret);
         switch(error)
         {
            case SSL_ERROR_ZERO_RETURN:
               // the connection was shutdown
               closed = true;
               break;
            case SSL_ERROR_WANT_READ:
               // more data is required from the socket
               ret = tcpRead();
               if(ret == 0)
               {
                  // the connection was shutdown properly
                  closed = true;
               }
               else if(ret == -1)
               {
                  // error in writing to socket
                  ExceptionRef e = new Exception(
                     "Could not read from socket.",
                     SOCKET_EXCEPTION_TYPE ".ReadError");
                  Exception::setLast(e, true);
                  rval = -1;
               }
               break;
            case SSL_ERROR_WANT_WRITE:
               // data must be flushed to the socket
               if(!tcpWrite())
               {
                  rval = -1;
               }
               break;
            default:
            {
               // an error occurred
               ExceptionRef e = new Exception(
                  "Could not read from socket.",
                  SOCKET_EXCEPTION_TYPE ".ReadError");
               e->getDetails()["error"] = SslContext::getSslErrorStrings();
               Exception::setLast(e, false);
               rval = -1;
               break;
            }
         }
      }

      // set number of bytes read
      if(rval != -1)
      {
         rval = (closed) ? 0 : ret;
      }
   }

   return rval;
}

InputStream* SslSocket::getInputStream()
{
   return mInputStream;
}

OutputStream* SslSocket::getOutputStream()
{
   return mOutputStream;
}

int SslSocket::tcpRead()
{
   int rval = 0;

   // flush the Socket BIO
   if(tcpWrite())
   {
      // determine how many bytes are required from the Socket BIO
      size_t length = BIO_ctrl_get_read_request(mSocketBio);
      if(length > 0)
      {
         // read from the underlying socket
         InputStream* is = mSocket->getInputStream();
         char b[length];
         int numBytes = 0;
         while(length > 0 && (numBytes = is->read(b, length)) > 0)
         {
            // write to Socket BIO
            BIO_write(mSocketBio, b, numBytes);

            // decrement remaining bytes to read
            length -= numBytes;

            // update bytes read
            rval = (rval == -1) ? numBytes : rval + numBytes;
         }

         if(numBytes < 0)
         {
            // exception reading from input stream
            rval = -1;
         }
      }
   }
   else
   {
      // exception during tcpWrite()
      rval = -1;
   }

   return rval;
}

bool SslSocket::tcpWrite()
{
   bool rval = true;

   // determine how many bytes can be read from the Socket BIO
   size_t length = BIO_ctrl_pending(mSocketBio);
   if(length > 0)
   {
      // read from the Socket BIO
      char b[length];
      int numBytes = 0;
      while(rval && length > 0 &&
            (numBytes = BIO_read(mSocketBio, b, length)) > 0)
      {
         // write to underlying socket, decrement length left to read
         rval = mSocket->getOutputStream()->write(b, numBytes);
         length -= numBytes;
      }
   }

   return rval;
}
<|endoftext|>