added more or less resurrected C++ cli client. This will need a lot of

work.

please note, that I would do quite some things differently nowadays. I
home to get those things in via refactoring
This commit is contained in:
Christof Donat 2012-04-24 15:15:42 +00:00
parent 76ea5d21b0
commit c64ab570a1
22 changed files with 5833 additions and 0 deletions

70
hsacppcli/Makefile Normal file
View File

@ -0,0 +1,70 @@
#
# (c) okunah gmbh
#
# name: Makefile
#
# description: description
#
# written by: Christof Donat
#
# changes:
# 05.11.11 (Christof Donat): created this file
#
#
# includes
#
#
# defines
#
#
# rules
#
all: release
debug-test: debug
cd build/Debug; make test
debug: debug-env
cd build/Debug; make
debug-dir:
if [ ! -d build/Debug ]; then mkdir -p build/Debug; fi
debug-env: debug-dir
cd build/Debug; cmake -DCMAKE_BUILD_TYPE="Debug" ../../hsadminc/
test: release
cd build/Release; make test
release: release-env
cd build/Release; make
release-env: release-dir
cd build/Release; cmake -DCMAKE_BUILD_TYPE="Release" ../../hsadminc/
release-dir:
if [ ! -d build/Release ]; then mkdir -p build/Release; fi
small-test: small
cd build/MinSizeRel; make test
small: small-env
cd build/MinSizeRel; make
small-env: small-dir
cd build/MinSizeRel; cmake -DCMAKE_BUILD_TYPE="MinSizeRel" ../../hsadminc/
small-dir:
if [ ! -d build/MinSizeRel ]; then mkdir -p build/MinSizeRel; fi
clean:
rm -rf build
# end Makefile

View File

@ -0,0 +1,129 @@
PROJECT( hsadminc )
CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
#
# look for packages needed for the build to succeed
#
# find boost libraries
SET(Boost_USE_MULTITHREADED ON)
SET(Boost_USE_STATIC_RUNTIME OFF)
FIND_PACKAGE( Boost 1.44 REQUIRED COMPONENTS date_time filesystem iostreams regex system unit_test_framework thread )
# find doxygen
FIND_PACKAGE( Doxygen 1.7.3 )
# find GnuTLS
FIND_PACKAGE( GnuTLS 2.8.6 REQUIRED )
#
# set compiler and linker flags
#
# compiler
SET( CMAKE_CXX_FLAGS_DEBUG "-g3 -O0" )
SET( CMAKE_CXX_FLAGS_RELEASE "-O3" )
SET( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g3 -O3" )
SET( CMAKE_CXX_FLAGS_MINSIZEREL "-Os" )
# gcc specific
IF( CMAKE_COMPILER_IS_GNUCC )
SET( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wold-style-cast -pedantic -Wall -Wextra -Winit-self -Wshadow -Wconversion -Wlogical-op -Wnormalized=nfc -Winline -std=c++0x" )
SET( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x" )
SET( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -std=c++0x" )
SET( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -std=c++0x" )
ENDIF()
#linker
SET( CMAKE_LINK_FLAGS_DEBUG "-g -O0" )
SET( CMAKE_LINK_FLAGS_RELEASE "-O3" )
SET( CMAKE_LINK_FLAGS_RELWITHDEBINFO "-g -O3" )
SET( CMAKE_LINK_FLAGS_MINSIZEREL "-O3" )
# GNU ld specific
IF( CMAKE_COMPILER_IS_GNUCC )
SET( CMAKE_LINK_FLAGS_DEBUG "${CMAKE_LINK_FLAGS_RELEASE} --relax" )
SET( CMAKE_LINK_FLAGS_RELEASE "${CMAKE_LINK_FLAGS_RELEASE} --relax" )
SET( CMAKE_LINK_FLAGS_RELWITHDEBINFO "${CMAKE_LINK_FLAGS_RELWITHDEBINFO} --relax" )
SET( CMAKE_LINK_FLAGS_MINSIZEREL "${CMAKE_LINK_FLAGS_MINSIZEREL} -s --gc-sections --relax" )
ENDIF()
# build the release as default
SET( CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_RELEASE} )
SET( CMAKE_LINK_FLAGS ${CMAKE_LINK_FLAGS_RELEASE} )
# make sure the boost include files are available
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} )
# all libs that will be linked to hsadminc
SET( HSADMINC_LIB ${Boost_LIBRARIES} gnutls )
# now this is where the source is
ADD_SUBDIRECTORY( source )
# packaging
IF( ${UNIX} )
SET( CPACK_GNERATOR "DEB;RPM;" )
SET( CPACK_PACKAGE_DESCRIPTION "hsadmin command line client" )
SET( CPACK_PACKAGE_DESCRIPTION_SUMMARY "a command line tool to access servers of the configuration tool hsadmin developed by Hostsharing e.G." )
SET( CPACK_PACKAGE_NAME "hsadminc" )
SET( CPACK_DEBIAN_PACKAGE_DEPENDS "boost (>= 1.44), gnutls (>= 2.8.6)" )
SET( CPACK_PACKAGE_CONTACT "Christof Donat" )
SET( CPACK_PACKAGE_VENDOR "Hostsharing e.G." )
SET( CPACK_PACKAGE_VERSION_MAJOR "0" )
SET( CPACK_PACKAGE_VERSION_MINOR "0" )
SET( CPACK_PACKAGE_VERSION_PATCH "1" )
SET( VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}" )
ENDIF()
# currently WIN32 is not supported
#IF( ${WIN32} )
# SET( CPACK_GNERATOR "NSIS;" )
# SET( CPACK_NSIS_MUI_ICON "" )
# SET( CPACK_NSIS_MUI_UNIICON "" )
# SET( CPACK_PACKAGE_ICON "" )
# SET( CPACK_NSIS_EXTRA_INSTALL_COMMANDS "" )
# SET( CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "" )
# SET( CPACK_NSIS_COMPRESSOR "" )
# SET( CPACK_NSIS_MODIFY_PATH "" )
# SET( CPACK_NSIS_DISPLAY_NAME "" )
# SET( CPACK_NSIS_INSTALLED_ICON_NAME "" )
# SET( CPACK_NSIS_HELP_LINK "" )
# SET( CPACK_NSIS_URL_INFO_ABOUT "" )
# SET( CPACK_NSIS_CONTACT "" )
# SET( CPACK_NSIS_CREATE_ICONS_EXTRA "" )
# SET( CPACK_NSIS_DELETE_ICONS_EXTRA "" )
# SET( CPACK_NSIS_MENU_LINKS "" )
# SET( CPACK_NSIS_MUI_FINISHPAGE_RUN "" )
#ENDIF()
# currently OSX is not supported
#IF( ${APPLE} )
# SET( CPACK_GNERATOR "MACOSX_BUNDLE;" )
# SET( CPACK_PACKAGE_FILE_NAME "" )
# SET( CPACK_PACKAGE_ICON "" )
# SET( CPACK_BUNDLE_NAME "" )
# SET( CPACK_BUNDLE_ICON "" )
# SET( CPACK_BUNDLE_PLIST "" )
# SET( CPACK_BUNDLE_STARTUP_COMMAND "" )
#ENDIF()
#
# doxygen documentation
#
CONFIGURE_FILE( doc/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile )
ADD_CUSTOM_TARGET( doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile )
SET_PROPERTY( DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CKEAN_FILES doc )
GET_TARGET_PROPERTY( DOC_TARGET doc TYPE )
IF( NOT DOC_TARGET )
ADD_CUSTOM_TARGET( doc )
ENDIF()
ADD_DEPENDENCIES( doc doxygen )
SET( DOC_PATH "share/doc/${CPACK_PACKAGE_NAME}-${VERSION}" )
INSTALL( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION DOC_PATH )

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,11 @@
CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} )
SET( HSADMINC_SRC abstractcmdlineparser.cpp cmdlineparser.cpp configfile.cpp hsadminc.cpp httpclient.cpp logger.cpp sslclient.cpp transaction.cpp xmlparser.cpp )
ADD_EXECUTABLE( hsadminc ${HSADMINC_SRC} )
TARGET_LINK_LIBRARIES( hsadminc ${HSADMINC_LIB} )
INSTALL( TARGETS hsadminc RUNTIME DESTINATION bin )

View File

@ -0,0 +1,22 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "abstractcmdlineparser.h"

View File

@ -0,0 +1,417 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <vector>
#include <string>
#include "logger.h"
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/algorithm/string.hpp>
/** abstractcommandlineparser holds some basic stuff for making commandline-Parsers easier. */
namespace abstractcommandlineparser {
#ifndef HSADMIN_ABSTRACTCMDLINEPARSER
#define HSADMIN_ABSTRACTCMDLINEPARSER
using std::vector;
using std::string;
using boost::shared_ptr;
using boost::scoped_ptr;
using boost::starts_with;
using boost::erase_first;
/** \brief template for Commandline-Parser
*
* Has two Parameters:
* - class Options: This class must provide a method 'parseThis()'. - see template CmdLineOption for an example
* - class parseResult: a shared pointer to an Object of this class is passed to the Options.
*/
template<class Options,class parserResult> class CmdLineParser {
public:
/** \brief this actually not only instatiates the parser but also parses Parameters.
*
* takes the Options in a vector<string>
*/
CmdLineParser(vector<string> options) : m_parsed(new parserResult), m_parseSuccessful(false) {
Options o;
while( options.size() > 0 )
if( !(this->m_parseSuccessful = o.parseThis(options,m_parsed)) )
return;
};
//! has the parser been successful?
inline bool operator!() { return !this->m_parseSuccessful; }
protected:
shared_ptr<parserResult> m_parsed;
bool m_parseSuccessful;
};
/** \brief base template for Option classes
*
* usually you would use one of the many specialisations
* has four parameters:
* - bool hasLongName: the Parameter has a long name (e.g. --verbose)
* - bool hasShortName: the Parameter has a short name (e.g. -v)
* - bool hasParameter: the Parameter is followed by another Parameter that belongs to it
* - class parseResult: takes the Parse results
*
* You should implement a protected virtual method 'bool handle(string &parameter, shared_ptr<parseResult> result)'
* if you have 'hasParameter' set to true or 'bool handle(shared_ptr<parseResult> result)' otherwise. There you
* can actually store your values in your parseResult.
*/
template <bool hasLongName, bool hasShortName, bool hasParameter,class parseResult> class CmdLineOption {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {};
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that do have long and short names as well as a value.
*
* You should implement a protected virtual method
* 'bool handle(string &parameter, shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<true, true, true,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( starts_with(options[0], "-"+m_shortName) ) {
if( rval = this->handle(options[1],result) ) {
if( options[0] == "-"+m_shortName)
options.erase(options.begin(),options.begin()+2);
else {
options.erase(options.begin()+1);
erase_first(options[0], m_shortName);
}
}
} else {
if( starts_with(options[0], "--"+m_longName+m_parameterSeparator) ) {
string p = options[0].substr(m_longName.size()+m_parameterSeparator.size()+2);
if( rval = this->handle(p,result) )
options.erase(options.begin());
}
}
return rval;
}
protected:
string m_longName;
string m_shortName;
string m_parameterSeparator;
//! the handle function.
virtual bool handle(string &parameter, shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that do have long and short names but no value.
*
* You should implement a protected virtual method
* 'bool handle(shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<true, true, false,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( options[0] == "-"+m_shortName || options[0] == "--"+m_longName ) {
if( rval = this->handle(result) )
options.erase(options.begin());
} else if( starts_with(options[0], "-"+m_shortName) && (rval = this->handle(result)) )
erase_first(options[0], m_shortName);
return rval;
}
protected:
string m_longName;
string m_shortName;
//! the handle function.
virtual bool handle(shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that only have a long name and a value but no short name.
*
* You should implement a protected virtual method
* 'bool handle(string &parameter, shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<true, false, true,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( starts_with(options[0], "--"+m_longName+m_parameterSeparator) ) {
string p = options[0].substr(m_longName.size()+m_parameterSeparator.size()+2);
if ( rval = this->handle(p, result) )
options.erase(options.begin());
}
return rval;
}
protected:
string m_longName;
string m_parameterSeparator;
//! the handle function.
virtual bool handle(string &parameter, shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that only have a long name but no value or short name.
*
* You should implement a protected virtual method
* 'bool handle(shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<true, false, false,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( options[0] == "--"+m_longName && (rval = this->handle(result)) )
options.erase(options.begin());
return rval;
}
protected:
string m_longName;
//! the handle function.
virtual bool handle(shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that only have short name and a value but no long name.
*
* You should implement a protected virtual method
* 'bool handle(string &parameter, shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<false, true, true,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( starts_with(options[0], "-"+m_shortName) && (rval = this->handle(options[1],result)) ) {
if( options[0] == "-"+m_shortName)
options.erase(options.begin(),options.begin()+2);
else {
options.erase(options.begin()+1);
erase_first(options[0], m_shortName);
}
}
return rval;
}
protected:
string m_shortName;
//! the handle function.
virtual bool handle(string &parameter, shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that only have short name bot no value or long name.
*
* You should implement a protected virtual method
* 'bool handle(shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<false, true, false,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( starts_with(options[0], "-"+m_shortName) && (rval = this->handle(result)) ) {
if( options[0] == "-"+m_shortName )
options.erase(options.begin());
else
erase_first(options[0], m_shortName);
}
return rval;
}
protected:
string m_shortName;
//! the handle function.
virtual bool handle(shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that only have a value but neither a long or short name.
*
* You should implement a protected virtual method
* 'bool handle(string &parameter, shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<false, false, true,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( !starts_with(options[0], "-") && (rval = this->handle(options[0],result)) )
options.erase(options.begin());
return rval;
}
protected:
//! the handle function.
virtual bool handle(string &parameter, shared_ptr<parseResult> result) { return true; };
};
/** \brief base template for Option classes - specialisation
*
* this is the specialisation for Parameters that neither have a value, a long or short name.
*
* You should implement a protected virtual method
* 'bool handle(shared_ptr<parseResult> result)'.
* There you can actually store your values in your parseResult.
*/
template <class parseResult> class CmdLineOption<false, false, false,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
bool rval = false;
if( !starts_with(options[0], "-") && (rval = this->handle(result)) )
options.erase(options.begin());
return rval;
}
protected:
//! the handle function.
virtual bool handle(shared_ptr<parseResult> result) { return true; };
};
//! just needed for typelists
class nullType {};
//! typelist for multiple Options parser
template<class CAR, class CDR> class typelist {
public:
typedef CAR car;
typedef CDR cdr;
};
/** \brief A Commandline-Option for CmdLineParser that works with a typelist of Options.
*
* this is meant to combine multiple Parameters in a typelist to build a complex Command Line parser
*/
template<class tl, class parseResult> class CmdLineOptionList : public CmdLineOption<false,false,false,parseResult> {
public:
//! the actual parser function.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
return m_first.parseThis(options,result) || m_second.parseThis(options,result);
}
private:
typename tl::car m_first;
CmdLineOptionList<typename tl::cdr,parseResult> m_second;
};
/** \brief specialisation for empty type list
*/
template<class parseResult> class CmdLineOptionList<nullType,parseResult> : public CmdLineOption<false,false,false,parseResult> {
public:
//! the actual parser function; always returns false.
bool parseThis(vector<string>& options, shared_ptr<parseResult> result) {
return false;
}
};
#define Parameterlist1(t1) \
abstractcommandlineparser::typelist<t1,abstractcommandlineparser::nullType>
#define Parameterlist2(t1,t2) \
abstractcommandlineparser::typelist<t1,Parameterlist1(t2) >
#define Parameterlist3(t1,t2,t3) \
abstractcommandlineparser::typelist<t1,Parameterlist2(t2,t3) >
#define Parameterlist4(t1,t2,t3,t4) \
abstractcommandlineparser::typelist<t1,Parameterlist3(t2,t3,t4) >
#define Parameterlist5(t1,t2,t3,t4,t5) \
abstractcommandlineparser::typelist<t1,Parameterlist4(t2,t3,t4,t5) >
#define Parameterlist6(t1,t2,t3,t4,t5,t6) \
abstractcommandlineparser::typelist<t1,Parameterlist5(t2,t3,t4,t5,t6) >
#define Parameterlist7(t1,t2,t3,t4,t5,t6,t7) \
abstractcommandlineparser::typelist<t1,Parameterlist6(t2,t3,t4,t5,t6,t7) >
#define Parameterlist8(t1,t2,t3,t4,t5,t6,t7,t8) \
abstractcommandlineparser::typelist<t1,Parameterlist7(t2,t3,t4,t5,t6,t7,t8) >
#define Parameterlist9(t1,t2,t3,t4,t5,t6,t7,t8,t9) \
abstractcommandlineparser::typelist<t1,Parameterlist8(t2,t3,t4,t5,t6,t7,t8,t9) >
#define Parameterlist10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) \
abstractcommandlineparser::typelist<t1,Parameterlist9(t2,t3,t4,t5,t6,t7,t8,t9,t10) >
#define Parameterlist11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) \
abstractcommandlineparser::typelist<t1,Parameterlist10(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) >
#define Parameterlist12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) \
abstractcommandlineparser::typelist<t1,Parameterlist11(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) >
#define Parameterlist13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) \
abstractcommandlineparser::typelist<t1,Parameterlist12(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) >
#define Parameterlist14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) \
abstractcommandlineparser::typelist<t1,Parameterlist13(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) >
#define Parameterlist15(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) \
abstractcommandlineparser::typelist<t1,Parameterlist14(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) >
#define Parameterlist16(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16) \
abstractcommandlineparser::typelist<t1,Parameterlist15(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16) >
#define Parameterlist17(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17) \
abstractcommandlineparser::typelist<t1,Parameterlist16(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17) >
#define Parameterlist18(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18) \
abstractcommandlineparser::typelist<t1,Parameterlist17(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18) >
#define Parameterlist19(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19) \
abstractcommandlineparser::typelist<t1,Parameterlist18(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19) >
#define Parameterlist20(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20) \
abstractcommandlineparser::typelist<t1,Parameterlist19(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20) >
#define Parameterlist21(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21) \
abstractcommandlineparser::typelist<t1,Parameterlist20(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21) >
#define Parameterlist22(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22) \
abstractcommandlineparser::typelist<t1,Parameterlist21(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22) >
#define Parameterlist23(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23) \
abstractcommandlineparser::typelist<t1,Parameterlist22(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23) >
#define Parameterlist24(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24) \
abstractcommandlineparser::typelist<t1,Parameterlist23(t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24) >
#else
template<class Options,class parseResult> class CmdLineParser;
template <bool hasLongName, bool hasShortName, bool hasParameter,class parseResult> class CmdLineOption;
class nullType;
template<class CAR, class CDR> class typelist;
template<class tl, class parseResult> class CmdLineOptionList;
#endif /* HSADMIN_ABSTRACTCMDLINEPARSER */
};

View File

@ -0,0 +1,772 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <iostream>
#include <sstream>
#include <fstream>
#include "cmdlineparser.h"
#include "logger.h"
#include <termios.h>
#include <unistd.h>
namespace commandline {
using std::cout;
using std::cin;
using std::flush;
using std::ifstream;
using std::ostringstream;
using boost::lexical_cast;
using boost::bad_lexical_cast;
using boost::shared_ptr;
using boost::scoped_ptr;
using boost::starts_with;
using boost::erase_first;
// dynamic cast needs this
vector<string> callParameter::parseDisplayspec() {
vector<string> rval;
boost::regex pattern("\\$\\{([^\\}]*)\\}");
boost::sregex_iterator end;
for(boost::sregex_iterator i(this->m_display.begin(),this->m_display.end(),pattern); i != end; i++ )
rval.insert(rval.end(),(*i)[1]);
Logger::log(Logger::DEBUG,"have parsed displayspec Parameter '"+this->m_display+"'");
return rval;
}
string callParameter::evalDisplay(const map<string, string> &values) {
string rval = this->m_display;
string::size_type pos;
for( map<string,string>::const_iterator i = values.begin(); i != values.end(); i++ ) {
string pattstring = "${"+i->first+"}";
while( (pos = rval.find(pattstring,0)) != string::npos ) rval.replace(pos,pattstring.length(),i->second);
}
while( (pos = rval.find("\\n",0)) != string::npos ) rval.replace(pos,2,"\n");
while( (pos = rval.find("\\t",0)) != string::npos ) rval.replace(pos,2,"\t");
while( (pos = rval.find("\\r",0)) != string::npos ) rval.replace(pos,2,"\r");
Logger::log(Logger::DEBUG,"have evaluated displayspec Parameter '"+this->m_display+"': '"+rval+"'");
return rval;
}
string setParameter::toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile) {
string rpccall = "<struct>";
rpccall += "<member><name>property</name><value>"+m_property+"</value></member>";
rpccall += "<member><name>value</name><value>"+m_value+"</value></member>";
rpccall += "</struct>";
return rpccall;
}
string whereParameter::toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile) {
string rpccall = "<struct>";
rpccall += "<member><name>property</name><value>"+m_property+"</value></member>";
rpccall += "<member><name>value</name><value>"+m_pattern+"</value></member>";
rpccall += "</struct>";
return rpccall;
}
string orderParameter::toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile) {
string rpccall = "<struct>";
rpccall += "<member><name>property</name><value>"+m_property+"</value></member>";
rpccall += "<member><name>ascending</name><value><boolean>";
rpccall += string((m_ascending?"1":"0"))+"</boolean></value></member>";
rpccall += "</struct>";
return rpccall;
}
string callParameter::toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile) {
string rpccall = "<struct>";
rpccall += "<member>";
rpccall += "<name>module</name>";
rpccall += "<value>"+m_module+"</value>";
rpccall += "</member>";
rpccall += "<member>";
rpccall += "<name>function</name>";
rpccall += "<value>"+m_function+"</value>";
rpccall += "</member>";
if( m_force ) {
rpccall += "<member>";
rpccall += "<name>force</name>";
rpccall += "<value><boolean>1</boolean></value>";
rpccall += "</member>";
}
if( m_ignoreerror ) {
rpccall += "<member>";
rpccall += "<name>ignoreerror</name>";
rpccall += "<value><boolean>1</boolean></value>";
rpccall += "</member>";
}
// read
vector<string> reads = parseDisplayspec();
if(reads.size()) {
rpccall += "<member>";
rpccall += "<name>read</name>";
rpccall += "<value><array><data>";
for(vector<string>::iterator j = reads.begin(); j != reads.end(); j++ )
rpccall += "<value>"+(*j)+"</value>";
rpccall += "</data></array></value>";
rpccall += "</member>";
}
if( m_where.size() ) {
rpccall += "<member>";
rpccall += "<name>where</name>";
rpccall += "<value><array><data>";
for(vector<shared_ptr<whereParameter> >::iterator j = m_where.begin(); j != m_where.end(); j++ )
rpccall += "<value>"+((*j)->toXML(username,cfgfile))+"</value>";
rpccall += "</data></array></value>";
rpccall += "</member>";
}
if( m_set.size() ) {
rpccall += "<member>";
rpccall += "<name>set</name>";
rpccall += "<value><array><data>";
for(vector<shared_ptr<setParameter> >::iterator j = m_set.begin(); j != m_set.end(); j++ )
rpccall += "<value>"+((*j)->toXML(username,cfgfile))+"</value>";
rpccall += "</data></array></value>";
rpccall += "</member>";
}
if( m_order.size() ) {
rpccall += "<member>";
rpccall += "<name>order</name>";
rpccall += "<value><array><data>";
for(vector<shared_ptr<orderParameter> >::iterator j = m_order.begin(); j != m_order.end(); j++ )
rpccall += "<value>"+((*j)->toXML(username,cfgfile))+"</value>";
rpccall += "</data></array></value>";
rpccall += "</member>";
}
if( m_objects.size() ) {
rpccall += "<member>";
rpccall += "<name>objectid</name>";
rpccall += "<value><array><data>";
for(vector<string>::iterator j = m_objects.begin(); j != m_objects.end(); j++ )
rpccall += "<value>"+(*j)+"</value>";
rpccall += "</data></array></value>";
rpccall += "</member>";
}
if( m_unset.size() ) {
rpccall += "<member>";
rpccall += "<name>unset</name>";
rpccall += "<value><array><data>";
for(vector<string>::iterator j = m_unset.begin(); j != m_unset.end(); j++ )
rpccall += "<value><struct><member><name>property</name><value>"+(*j)+"</value></member></struct></value>";
rpccall += "</data></array></value>";
rpccall += "</member>";
}
rpccall += "</struct>";
return rpccall;
}
parsedParameters::parsedParameters():
m_error(NOERROR),
m_user(""),
m_ticket(""),
m_defaultDisplay(""),
m_addConfigFile(""),
m_test(false),
m_ignoreerrors(false) {}
string parsedParameters::toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile) {
// begin method call
string rpccall = "<?xml version=\"1.0\"?><methodCall><methodName>hsadmin.transaction</methodName><params>";
// ticket
rpccall += "<param><value><string>";
if( this->m_ticket != "" ) {
string ticket;
ifstream file(this->m_ticket.c_str());
if( ! file ) {
string msg = Logger::getMessageFormatString(Logger::CouldNotOpenFile);
boost::format fmt(msg);
fmt % this->m_ticket;
Logger::log(Logger::FATAL,fmt.str());
exit(-1);
}
char ch;
while(file.get(ch)) ticket += ch;
boost::regex findticket(".*\\n---\\n");
ticket = boost::regex_replace(ticket,findticket,"");
if( ticket[ticket.size()-1] == '\0' ) ticket = ticket.substr(0,ticket.size()-2);
rpccall += ticket;
} else {
rpccall += cfgfile->getTicket(username);
}
Logger::log(Logger::DEBUG,"have read ticket");
rpccall += "</string></value></param>";
// global Parameters
rpccall += "<param><value><struct>";
if( this->m_test )
rpccall += "<member><name>test</name><value><boolean>1</boolean></value></member>";
rpccall += "</struct></value></param>";
// calls Array
rpccall += "<param><value><array><data>";
for( vector<shared_ptr<callParameter> >::iterator c = m_call.begin(); c != m_call.end(); c++ )
rpccall += "<value>"+((*c)->toXML(username,cfgfile))+"</value>";
rpccall += "</data></array></value></param>";
rpccall += "</params></methodCall>\n";
return rpccall;
}
// specific Parser for --runas-Option
bool VerbosityOption::parseThis(vector<string>& options, shared_ptr<parsedParameters> result) {
bool rval = false;
if( starts_with(options[0], "-v") ) {
if( options[1] == "none" ||
options[1] == "normal" ||
options[1] == "high" ||
options[1] == "debug" ||
options[1] == "debugXML" ||
options[1] == "debugAll" ) {
if( rval = this->handle(options[1], result) ) {
if( options[0] == "-v" )
options.erase(options.begin(),options.begin()+2);
else {
erase_first(options[0], "v");
options.erase(options.begin()+1);
}
}
} else {
string p;
if( rval = this->handle(p, result) ) {
if( options[0] == "-v" )
options.erase(options.begin());
else
erase_first(options[0], "v");
}
}
}
if( starts_with(options[0], "--verbosity=") ) {
string p = options[0].substr(12);
if( rval = this->handle(p, result) )
options.erase(options.begin());
}
return rval;
}
// constuctors
TestOption::TestOption() {
m_longName = "test";
m_shortName = "t";
}
IgnoreErrorOption::IgnoreErrorOption() {
m_longName = "ignoreerror";
m_shortName = "e";
}
IgnoreErrorsOption::IgnoreErrorsOption() {
m_longName = "ignoreerrors";
m_shortName = "E";
}
VerbosityOption::VerbosityOption() {
m_longName = "verbosity";
m_shortName = "v";
m_parameterSeparator = "=";
}
RunAsOption::RunAsOption() {
m_longName = "runas";
m_shortName = "r";
m_parameterSeparator = "=";
}
TicketOption::TicketOption() {
m_longName = "ticket";
m_shortName = "T";
m_parameterSeparator = "=";
}
ConfigOption::ConfigOption() {
m_longName = "config";
m_shortName = "C";
m_parameterSeparator = "=";
}
ForceOption::ForceOption() {
m_longName = "force";
}
GlobalsOption::GlobalsOption() {
m_longName = "globals";
m_shortName = "l";
}
WhereOption::WhereOption() {
m_longName = "where";
m_shortName = "w";
m_parameterSeparator = ":";
}
OnlyOption::OnlyOption() {
m_longName = "only";
m_shortName = "W";
m_parameterSeparator = ":";
}
SetOption::SetOption() {
m_longName = "set";
m_shortName = "s";
m_parameterSeparator = ":";
}
SetAllOption::SetAllOption() {
m_longName = "setall";
m_shortName = "S";
m_parameterSeparator = ":";
}
InfileOption::InfileOption() {
m_longName = "infile";
m_shortName = "f";
m_parameterSeparator = ":";
}
OrderOption::OrderOption() {
m_longName = "order";
m_shortName = "o";
m_parameterSeparator = ":";
}
GlobalOrderOption::GlobalOrderOption() {
m_longName = "global-order";
m_shortName = "O";
m_parameterSeparator = ":";
}
InputOption::InputOption() {
m_longName = "input";
m_shortName = "i";
m_parameterSeparator = ":";
}
PassInputOption::PassInputOption() {
m_longName = "passinput";
m_shortName = "p";
m_parameterSeparator = ":";
}
DisplayOption::DisplayOption() {
m_longName = "display";
m_shortName = "d";
m_parameterSeparator = ":";
}
DefaultDisplayOption::DefaultDisplayOption() {
m_longName = "default-display";
m_shortName = "D";
m_parameterSeparator = ":";
}
CallOption::CallOption() {
m_longName = "call";
m_shortName = "c";
m_parameterSeparator = ":";
}
UnsetOption::UnsetOption() {
m_longName = "unset";
m_shortName = "u";
m_parameterSeparator = ":";
}
UnsetAllOption::UnsetAllOption() {
m_longName = "unsetall";
m_shortName = "U";
m_parameterSeparator = ":";
}
ObjectID::ObjectID() { };
// handle functions
bool TestOption::handle(shared_ptr<parsedParameters> result) {
result->m_test = true;
Logger::log(Logger::DEBUG," found test Option");
return true;
}
bool IgnoreErrorOption::handle(shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
result->m_call.back()->m_ignoreerror = true;
Logger::log(Logger::DEBUG," found ignoreerror Option");
return true;
}
bool IgnoreErrorsOption::handle(shared_ptr<parsedParameters> result) {
result->m_ignoreerrors = true;
Logger::log(Logger::DEBUG," found ignoreerrors Option");
return true;
}
bool VerbosityOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( parameter == "none" ) Logger::setLevel(0);
else if( parameter == "normal") Logger::setLevel(1);
else if( parameter == "high") Logger::setLevel(2);
else if( parameter == "debug") Logger::setLevel(3);
else if( parameter == "debugXML") Logger::setLevel(4);
else if( parameter == "debugAll") Logger::setLevel(5);
else Logger::incrementLevel();
Logger::log(Logger::DEBUG," set Verbosity Level to "+lexical_cast<string>(Logger::level));
return true;
}
bool QuietOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
Logger::decrementLevel();
Logger::log(Logger::DEBUG," set Verbosity Level to "+lexical_cast<string>(Logger::level));
return true;
}
bool RunAsOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
result->m_user = parameter;
Logger::log(Logger::DEBUG," found runas Option: "+parameter);
return true;
}
bool TicketOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
result->m_ticket = parameter;
Logger::log(Logger::DEBUG," found ticket Option: "+parameter);
return true;
}
bool ConfigOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
result->m_addConfigFile = parameter;
Logger::log(Logger::DEBUG," found config Option: "+parameter);
return true;
}
bool ForceOption::handle(shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
result->m_call.back()->m_force = true;
Logger::log(Logger::DEBUG," found force Option");
return true;
}
bool GlobalsOption::handle(shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
result->m_call.back()->m_globalOrderIndex = result->m_call.back()->m_order.size();
Logger::log(Logger::DEBUG," found globals Option");
return true;
}
bool WhereOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
string::size_type pos = parameter.find('=');
string property(parameter,0,pos);
string pattern(parameter,(pos != string::npos)?(pos+1):(string::npos));
whereParameter *where = new whereParameter();
where->m_property = property;
where->m_pattern = pattern;
result->m_call.back()->m_where.push_back(shared_ptr<whereParameter>(where));
Logger::log(Logger::DEBUG," found where Option: "+parameter);
return true;
}
bool OnlyOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
string::size_type pos = parameter.find('=');
string property(parameter,0,pos);
string pattern(parameter,(pos != string::npos)?(pos+1):(string::npos));
whereParameter *where = new whereParameter();
where->m_property = property;
where->m_pattern = pattern;
result->m_only.push_back(shared_ptr<whereParameter>(where));
Logger::log(Logger::DEBUG," found only Option: "+parameter);
return true;
}
bool UnsetOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
result->m_call.back()->m_unset.push_back(parameter);
Logger::log(Logger::DEBUG," found unset Option: "+parameter);
return true;
}
bool UnsetAllOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
result->m_unsetall.push_back(parameter);
Logger::log(Logger::DEBUG," found unsetall Option: "+parameter);
return true;
}
bool OrderOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
string::size_type pos = parameter.find('=');
string *property;
string * direction;
if( pos != string::npos ) {
property = new string(parameter,0,pos);
direction = new string(parameter,(pos != string::npos)?(pos+1):(string::npos));
} else {
property = new string(parameter);
direction = new string("a");
}
orderParameter *order = new orderParameter();
order->m_property = *property;
order->m_ascending = ((*direction)[0] == 'a');
result->m_call.back()->m_order.push_back(shared_ptr<orderParameter>(order));
Logger::log(Logger::DEBUG," found order Option: "+parameter);
return true;
}
bool GlobalOrderOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
string::size_type pos = parameter.find('=');
string *property;
string * direction;
if( pos != string::npos ) {
property = new string(parameter,0,pos);
direction = new string(parameter,(pos != string::npos)?(pos+1):(string::npos));
} else {
property = new string(parameter);
direction = new string("a");
}
orderParameter *order = new orderParameter();
order->m_property = *property;
order->m_ascending = ((*direction)[0] == 'a');
result->m_globalOrder.push_back(shared_ptr<orderParameter>(order));
Logger::log(Logger::DEBUG," found global order Option: "+parameter);
return true;
}
bool SetOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
string::size_type pos = parameter.find('=');
string property(parameter,0,pos);
string value(parameter,(pos != string::npos)?(pos+1):(string::npos));
setParameter *set = new setParameter();
set->m_property = property;
set->m_value = value;
result->m_call.back()->m_set.push_back(shared_ptr<setParameter>(set));
Logger::log(Logger::DEBUG," found set Option: "+parameter);
return true;
}
bool SetAllOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
string::size_type pos = parameter.find('=');
string property(parameter,0,pos);
string value(parameter,(pos != string::npos)?(pos+1):(string::npos));
setParameter *set = new setParameter();
set->m_property = property;
set->m_value = value;
result->m_setall.push_back(shared_ptr<setParameter>(set));
Logger::log(Logger::DEBUG," found setall Option: "+parameter);
return true;
}
bool InfileOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
string::size_type pos = parameter.find('=');
string property(parameter,0,pos);
string filename(parameter,(pos != string::npos)?(pos+1):(string::npos));
setParameter *set = new setParameter();
set->m_property = property;
ifstream file(filename.c_str());
if( ! file ) {
string msg = Logger::getMessageFormatString(Logger::CouldNotOpenFile);
boost::format fmt(msg);
fmt % filename;
Logger::log(Logger::FATAL,fmt.str());
exit(-1);
}
char ch;
while(file.get(ch)) set->m_value += ch;
result->m_call.back()->m_set.push_back(shared_ptr<setParameter>(set));
Logger::log(Logger::DEBUG," found infile Option: "+parameter);
return true;
}
bool InputOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
setParameter *set = new setParameter();
set->m_property = parameter;
cout << "Eingabe (" << parameter << "): " << flush;
std::getline(cin, set->m_value);
result->m_call.back()->m_set.push_back(shared_ptr<setParameter>(set));
Logger::log(Logger::DEBUG," found input Option: "+parameter);
return true;
}
string readPasswd() {
string rval = "";
struct termios t, t2;
tcgetattr(0,&t);
t2 = t;
t2.c_lflag &= ~ECHO;
tcsetattr(0,TCSANOW,&t2);
std::getline(cin, rval);
tcsetattr(0,TCSANOW,&t);
return rval;
}
bool PassInputOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
setParameter *set = new setParameter();
set->m_property = parameter;
cout << "Passworteingabe (" << parameter << "): " << flush;
set->m_value = readPasswd();
result->m_call.back()->m_set.push_back(shared_ptr<setParameter>(set));
Logger::log(Logger::DEBUG," found password-input Option: "+parameter);
return true;
}
bool DisplayOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
result->m_call.back()->m_display = parameter;
Logger::log(Logger::DEBUG," found display Option: "+parameter);
return true;
}
bool DefaultDisplayOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
result->m_defaultDisplay = parameter;
Logger::log(Logger::DEBUG," found default display Option: "+parameter);
return true;
}
bool ObjectID::handle(string &parameter, shared_ptr<parsedParameters> result) {
if( result->m_call.size() <= 0 ) {
result->m_error = NeedCall;
return false;
}
result->m_call.back()->m_objects.push_back(parameter);
Logger::log(Logger::DEBUG," found an ObjectID: "+parameter);
return true;
}
bool CallOption::handle(string &parameter, shared_ptr<parsedParameters> result) {
string::size_type pos = parameter.find('.');
string module(parameter,0,pos);
string function(parameter,(pos != string::npos)?(pos+1):(string::npos));
callParameter *call = new callParameter();
call->m_module = module;
call->m_function = function;
result->m_call.push_back(shared_ptr<callParameter>(call));
Logger::log(Logger::DEBUG," found call Option: "+parameter);
return true;
}
};

View File

@ -0,0 +1,386 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <vector>
#include <string>
#include <map>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include "abstractcmdlineparser.h"
#include "configfile.h"
//! here comes the commandline-Parser - with help of the abstractcommandlineparser.
namespace commandline {
#ifndef HSADMIN_CMDLINEPARSER
#define HSADMIN_CMDLINEPARSER
using std::vector;
using std::string;
using std::map;
using boost::shared_ptr;
using boost::scoped_ptr;
// Parameter Objects are the resultof each Parser step and used in second step.
//! parsed values of a --setall, --set, --input, --passinput or a --infile option
class setParameter {
public:
string m_property;
string m_value;
string toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile);
};
//! parsed values of a --only or a --where option
class whereParameter {
public:
string m_property;
string m_pattern;
string toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile);
};
//! parsed values of a --global-order or a --order option
class orderParameter {
public:
string m_property;
bool m_ascending;
string toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile);
};
//! a whole parsed --call Option which holds all the relevant other options
class callParameter {
public:
callParameter(): m_module(""), m_function(""), m_display(""), m_ignoreerror(false), m_force(false), m_globalOrderIndex(-1) { };
string m_module;
string m_function;
string m_display;
vector<shared_ptr<setParameter> > m_set;
vector<shared_ptr<whereParameter> > m_where;
vector<shared_ptr<orderParameter> > m_order;
vector<string> m_objects;
vector<string> m_unset;
bool m_ignoreerror;
bool m_force;
int m_globalOrderIndex;
vector<string> parseDisplayspec();
string evalDisplay(const map<string, string> &values);
string toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile);
};
enum parseError { NOERROR = 0, NeedCall = 1 };
//! all the parsed values
class parsedParameters {
public:
parsedParameters();
parseError m_error;
string m_user;
string m_ticket;
string m_defaultDisplay;
string m_addConfigFile;
bool m_test;
bool m_ignoreerrors;
vector<shared_ptr<whereParameter> > m_only;
vector<shared_ptr<setParameter> > m_setall;
vector<shared_ptr<orderParameter> > m_globalOrder;
vector<shared_ptr<callParameter> > m_call;
vector<string> m_unsetall;
string toXML(string &username, shared_ptr< ::ConfigFileParser > cfgfile);
};
// Option classes are used in first Parse step
//! --test
class TestOption: public abstractcommandlineparser::CmdLineOption<true,true,false,parsedParameters> {
public:
TestOption();
protected:
virtual bool handle(shared_ptr<parsedParameters> result);
};
//! --ignoreerror
class IgnoreErrorOption: public abstractcommandlineparser::CmdLineOption<true,true,false,parsedParameters> {
public:
IgnoreErrorOption();
protected:
virtual bool handle(shared_ptr<parsedParameters> result);
};
//! --ignoreerrors
class IgnoreErrorsOption: public IgnoreErrorOption {
public:
IgnoreErrorsOption();
protected:
virtual bool handle(shared_ptr<parsedParameters> result);
};
//! --verbosity
class VerbosityOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
VerbosityOption();
bool parseThis(vector<string>& options, shared_ptr<parsedParameters> result);
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --quiet
class QuietOption: public abstractcommandlineparser::CmdLineOption<true,true,false,parsedParameters> {
public:
QuietOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --runas
class RunAsOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
RunAsOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --ticket
class TicketOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
TicketOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --config
class ConfigOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
ConfigOption();
protected:
virtual bool handle(string & parameter, shared_ptr<parsedParameters> result);
};
//! --force
class ForceOption: public abstractcommandlineparser::CmdLineOption<true,false,false,parsedParameters> {
public:
ForceOption();
protected:
virtual bool handle(shared_ptr<parsedParameters> result);
};
//! --globals
class GlobalsOption: public abstractcommandlineparser::CmdLineOption<true,true,false,parsedParameters> {
public:
GlobalsOption();
protected:
virtual bool handle(shared_ptr<parsedParameters> result);
};
//! --where
class WhereOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
WhereOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --only
class OnlyOption: public WhereOption {
public:
OnlyOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --set
class SetOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
SetOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --setall
class SetAllOption: public SetOption {
public:
SetAllOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --infile
class InfileOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
InfileOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --order
class OrderOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
OrderOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --global-order
class GlobalOrderOption: public OrderOption {
public:
GlobalOrderOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --input
class InputOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
InputOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --passinput
class PassInputOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
PassInputOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --display
class DisplayOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
DisplayOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --default-display
class DefaultDisplayOption: public DisplayOption {
public:
DefaultDisplayOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --call
class CallOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
CallOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --unset
class UnsetOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
UnsetOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! --unsetall
class UnsetAllOption: public abstractcommandlineparser::CmdLineOption<true,true,true,parsedParameters> {
public:
UnsetAllOption();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! all other parameters are objectIDs.
class ObjectID: public abstractcommandlineparser::CmdLineOption<false,false,true,parsedParameters> {
public:
ObjectID();
protected:
virtual bool handle(string &parameter, shared_ptr<parsedParameters> result);
};
//! putting it all together in a typelist
typedef Parameterlist24(
TestOption,
IgnoreErrorsOption,
VerbosityOption,
RunAsOption,
TicketOption,
ConfigOption,
SetAllOption,
UnsetAllOption,
OnlyOption,
GlobalOrderOption,
DefaultDisplayOption,
IgnoreErrorOption,
ForceOption,
GlobalsOption,
WhereOption,
SetOption,
InfileOption,
OrderOption,
InputOption,
PassInputOption,
UnsetOption,
DisplayOption,
ObjectID,
CallOption ) allParameters;
//! generating a class with parse()-function from the list of Options
typedef abstractcommandlineparser::CmdLineOptionList<allParameters, parsedParameters> Parameters;
#else
class parsedParameters;
class setParameter;
class whereParameter;
class orderParameter;
class callParameter;
class TestOption;
class IgnoreErrorOption;
class IgnoreErrorsOption;
class VerbosityOption;
class RunAsOption;
class TicketOption;
class ConfigOption;
class SetAllOption;
class OnlyOption;
class UnsetAllOption;
class GlobalOrderOption;
class DefaultDisplayOption;
class ForceOption;
class GlobalsOption;
class WhereOption;
class SetOption;
class InfileOption;
class OrderOption;
class InputOption;
class PassInputOption;
class DisplayOption;
class unsetOption;
class CallOption;
class ObjectID;
#endif /* HSADMIN_CMDLINEPARSER */
};

View File

@ -0,0 +1,257 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "configfile.h"
#include "logger.h"
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
using std::ostringstream;
using std::istringstream;
using std::ifstream;
using std::fstream;
using std::string;
using boost::lexical_cast;
using boost::bad_lexical_cast;
ConfigFileFinder::ConfigFileFinder(Transaction& t): vector<string*>() {
try {
boost::filesystem::path general("/etc/hsadminc.conf");
if( boost::filesystem::exists(general) && !boost::filesystem::is_directory(general) )
this->loadFile(general.native());
} catch(boost::filesystem::filesystem_error) {}
string priv = getenv("HOME");
try {
boost::filesystem::path p( priv + "/.hsadmin.conf");
if( boost::filesystem::exists(p) && !boost::filesystem::is_directory(p) )
this->loadFile(p.native());
} catch(boost::filesystem::filesystem_error) {}
shared_ptr<commandline::parsedParameters> params = t.getParsed();
if( params->m_addConfigFile != "" ) try {
boost::filesystem::path c( params->m_addConfigFile);
if( boost::filesystem::exists(c) && !boost::filesystem::is_directory(c) )
this->loadFile(c.native());
} catch(boost::filesystem::filesystem_error) {}
}
void ConfigFileFinder::loadFile(string filename) {
ifstream file(filename.c_str(),std::ios::in);
ostringstream reader;
reader << file.rdbuf();
string *tmp = new string(reader.str());
this->insert(this->end(),tmp);
}
void ConfigFileParser::parse(string& text) {
vector<string> lines;
config * current = &(this->basic);
vector<config> configs;
boost::split(lines,text,boost::is_any_of("\n"));
if( current->pattern != ".*" ) {
current->pattern = ".*";
current->ticketcommand = "hsadmint \\0";
current->server = "http://localhost:7777/RPC2";
current->shell = "/bin/sh";
current->askpass = false;
}
for( vector<string>::iterator i = lines.begin(); i != lines.end(); i++ ) {
string& line = *i;
// ignore coments and empty lines
boost::trim_left(line);
if( line[0] == '#' || line == "" )
continue;
// is this a section?
if( line[0] == '[' ) {
line.erase(0,1);
line.erase(line.rfind(']'));
if( current != &(this->basic) ) {
configs.insert(configs.end(),*current);
delete(current);
}
current = new config;
*current = this->basic;
current->pattern = line;
} else {
string::size_type equals = line.find('=');
string name = boost::trim_copy(line.substr(0,equals));
string value = boost::trim_copy(line.substr(equals+1));
// trim name and value
boost::trim(name);
boost::trim(value);
if( name == "ticket" )
current->ticketcommand = value;
else if( name == "server" )
current->server = value;
else if( name == "shell" )
current->shell = value;
else if( name == "askpass" && value == "true" )
current->askpass = true;
else if( name == "askpass" && value == "false" )
current->askpass = false;
}
}
if( current != &(this->basic) ) {
configs.insert(configs.end(),*current);
delete(current);
}
this->configs.insert(this->configs.begin(),configs.begin(),configs.end());
}
string ConfigFileParser::replaceStringMatches(string &userpattern, string username, string content) {
if( username == "" ) {
char* u = (char*)malloc(L_cuserid+1);;
cuserid(u);
if( u != 0 ) username = u;
}
boost::regex pattern(userpattern);
boost::cmatch results;
if( !boost::regex_match(username.c_str(),results,pattern) ) return content;
for(int j = 0; j < results.size(); j++) {
ostringstream p;
p << "^\\\\" << j << "|([^\\\\])\\\\" << j;
boost::regex pat(p.str());
string replace = "$1";
if( results[j].matched ) for( const char* i = results[j].first; i != results[j].second; i++ )
replace += *i;
content = boost::regex_replace(content,pat,replace);
}
return content;
}
string ConfigFileParser::getTicket(string &username) {
string ticketstring = "";
config cfg = this->getConfig(username);
string command = cfg.getTicketcommand(username);
Logger::log(Logger::DEBUG,"use '"+command+"' as command");
pid_t pid;
pid_t parentpid = getpid();
int cmdout[2];
if(pipe(cmdout) || (pid=fork()) == -1)
return "";
if(!pid) {
close(1);
close(cmdout[0]);
dup(cmdout[1]);
//command = cfg.shell+" -c \""+command+"\"";
// this should never return.
execlp(cfg.shell.c_str(),cfg.shell.c_str(),"-c",command.c_str(),(char*)0);
// if we have reached this something has gone wrong.
string msg = Logger::getMessageFormatString(Logger::ErrorWithTicketCommand);
boost::format fmt(msg);
fmt % cfg.shell % command % Logger::getErrnoMessage(errno);
Logger::log(Logger::FATAL,fmt.str());
exit(-1);
}
int status;
waitpid(pid,&status,0);
close(cmdout[1]);
// check if ticket has been successfully generated
if( !WIFEXITED(status) || WEXITSTATUS(status) )
exit(WEXITSTATUS(status));
char buf[257];
bzero(buf,257);
errno = 0;
int i = 0;
while( (i = read(cmdout[0],buf,256)) != 0 ) {
if( i < 0 ) {
if( errno == EAGAIN ) {
usleep(20);
continue;
} else if( errno == EINTR ) continue;
else {
string msg = Logger::getMessageFormatString(Logger::ErrorReadingTicket);
boost::format fmt(msg);
fmt % Logger::getErrnoMessage(errno);
Logger::log(Logger::FATAL,fmt.str());
exit(-1);
}
errno = 0;
}
ticketstring += buf;
if( strlen(buf) < i ) break;
bzero(buf,257);
}
return ticketstring;
}
ConfigFileParser::config &ConfigFileParser::getConfig(string &username) {
if( username == "" ) return basic;
for( vector<config>::iterator i = configs.begin(); i != configs.end(); i++ ) {
boost::regex pat(i->pattern);
if(boost::regex_match(username,pat)) return *i;
}
return basic;
}

View File

@ -0,0 +1,94 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <vector>
#include <string>
#include <iostream>
#ifndef HSADMIN_CONFIGFILE
#define HSADMIN_CONFIGFILE
#include "transaction.h"
using std::vector;
using std::string;
using std::iostream;
//! this class manages configfiles
class ConfigFileFinder: public vector<string*> {
public:
//! find the standard config-files
ConfigFileFinder(Transaction& t);
//! load a config file
void loadFile(string filename);
};
//! parser for config files
class ConfigFileParser {
public:
//! parses one text
inline ConfigFileParser(string& text) { this->parse(text); };
//! parses multiple texts
inline ConfigFileParser(vector<string*>* texts) { this->parse(texts); };
inline string getTicket() { string s = ""; return getTicket(s); };
/** \brief get a ticket for a specified user.
*
* this function finds the config for this user and calls the tocket-command
* with the specified shell.
*/
string getTicket(string &username);
//! replaces references (\0, \1, etc.) in content with regex-matches.
static string replaceStringMatches(string &userpattern, string username, string content);
//! holds single config entries
struct config {
string pattern;
string ticketcommand;
string server;
string shell;
bool askpass;
string getTicketcommand(string &username) { return ConfigFileParser::replaceStringMatches(pattern,username,ticketcommand); };
string getServer(string &username) { return ConfigFileParser::replaceStringMatches(pattern,username,ticketcommand); };
string getShell(string &username) { return ConfigFileParser::replaceStringMatches(pattern,username,ticketcommand); };
};
//! find the config for a specified user
config& getConfig(string &username);
private:
void parse(string& text);
inline void parse(vector<string*>* texts) {
for( vector<string*>::iterator i = texts->begin(); i != texts->end(); i++ )
this->parse(**i);
}
vector<config> configs;
config basic;
};
#else
class ConfigFileFinder;
class ConfigFileParser;
#endif /* HSADMIN_CONFIGFILE */

View File

@ -0,0 +1,155 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/algorithm/string.hpp>
#include "cmdlineparser.h"
#include "configfile.h"
#include "logger.h"
#include "transaction.h"
using std::string;
using std::vector;
using std::cerr;
using std::endl;
using boost::shared_ptr;
using boost::scoped_ptr;
using boost::starts_with;
void printErrorMessage(Transaction& transact, vector<string>& options) {
shared_ptr<commandline::parsedParameters> p = transact.getParsed();
string FailedOption = options[0];
if( starts_with(FailedOption,"--") )
FailedOption = FailedOption.substr(2);
else if( starts_with(FailedOption,"-") )
FailedOption = FailedOption.substr(1,2);
cerr << "Error on Commandline at Parameter '"<< FailedOption;
if( p->m_error == commandline::NeedCall )
cerr << ": call specific Parameter before call";
cerr << endl;
}
void printUsage(char* cmdname) {
cerr << "Usage: " << endl << endl;
cerr << cmdname << " [--test|-t]" << endl;
cerr << "[--ignoreerrors|-e]" << endl;
cerr << "[--verbosity=<level>|-v <level>]" << endl;
cerr << "[--quiet|-q]" << endl;
cerr << "[--runas=<user>|-r <user>]" << endl;
cerr << "[--ticket=<ticketfile>|-T <ticketfile>]" << endl;
cerr << "[--config=<configfile>|-C <configfile>]" << endl;
cerr << "[--default-display:<displaySpec>|-D <displaySpec>]" << endl;
cerr << "[(--only:<property_1>=<expr_1>|-W <property_1>=<expr_1>)" << endl;
cerr << " ... (--only:<property_n>=<expr_n>|-W <property_n>=<expr_n>)]" << endl;
cerr << "[(--setall:<property_1>=<value_1>|-S <property_1>=<value_1>)" << endl;
cerr << " ... (--setall:<property_n>=<value_n>|-S <property_n>=<value_n>)]" << endl;
cerr << " [(--unsetall:property_1|-U property_1) ... (--unsetall:property_n|-U property_n)]" << endl;
cerr << "[(--global-order:<property_1>[=(asc|desc|a|d)]|-O <property_1>[=(asc|desc|a|d)])" << endl;
cerr << " ..." << endl;
cerr << " (--global-order:<property_n>[=(asc|desc|a|d)]|-O <property_n>[=(asc|desc|a|d)]]" << endl;
cerr << " [--ignoreerrors|-E]" << endl;
cerr << "(--call:<module_1>.<function_1>|-c <module_1>.<function_1>)" << endl;
cerr << " [--force]" << endl;
cerr << " [--ignoreerror|-e]" << endl;
cerr << " [--display:<displaySpec>|-d <displaySpec>]" << endl;
cerr << " [(--where:<property_1_1>=<expr_1_1>|-w <property_1_1>=<expr_1_1>)" << endl;
cerr << " ... (--where:<property_1_n>=<expr_1_n>|-w <property_1_n>=<expr_1_n>)]" << endl;
cerr << " [(--set:<property_1_1>=<value_1_1>|-s <property_1_1>=<value_1_1>)" << endl;
cerr << " ... (--set:<property_1_n>=<value_1_n>|-s <property_1_n>=<value_1_n>)]" << endl;
cerr << " [(--input:<property_1_1>|-i <property_1_1>)" << endl;
cerr << " ... (--input:<property_1_n>|-i <property_1_n>)]" << endl;
cerr << " [(--passinput:<property_1_1>|-p <property_1_1>)" << endl;
cerr << " ... (--passinput:<property_1_n>|-p <property_1_n>)]" << endl;
cerr << " [(--infile:<property_1_1>=<file_1_1>|-f <property_1_1>=<file_1_1>)" << endl;
cerr << " ... (--infile:<property_1_n>=<file_1_n>|-f <property_1_n>=<file_1_n>)]" << endl;
cerr << " [(--unset:property_1_1|-u property_1_1]) ... (--unset:property_1_n|-u property_1_n])]" << endl;
cerr << " [(--order:<property_1_1>[=(asc|desc|a|d)]|-o <property_1_1>[=(asc|desc|a|d)])" << endl;
cerr << " ..." << endl;
cerr << " [--globals|-l]" << endl;
cerr << " ..." << endl;
cerr << " (--order:<property_1_n>[=(asc|desc|a|d)]|-o <property_1_n>[=(asc|desc|a|d)]]" << endl;
cerr << " [object_1_1 ... object_1_n]" << endl;
cerr << "..." << endl;
cerr << "(--call:<module_m>.<function_m>|-c <module_m>.<function_m>)" << endl;
cerr << " [--force]" << endl;
cerr << " [--ignoreerror|-e]" << endl;
cerr << " [--display:<displaySpec>|-d <displaySpec>]" << endl;
cerr << " [(--where:<property_m_1>=<expr_m_1>|-w <property_m_1>=<expr_m_1>)" << endl;
cerr << " ... (--where:<property_m_n>=<expr_m_n>|-w <property_m_n>=<expr_m_n>)]" << endl;
cerr << " [(--set:<property_m_1>=<value_m_1>|-s <property_m_1>=<value_m_1>)" << endl;
cerr << " ... (--set:<property_m_n>=<value_m_n>|-s <property_m_n>=<value_m_n>)]" << endl;
cerr << " [(--input:<property_m_1>|-i <property_m_1>)" << endl;
cerr << " ... (--input:<property_m_n>|-i <property_m_n>)]" << endl;
cerr << " [(--passinput:<property_m_1>|-p <property_m_1>)" << endl;
cerr << " ... (--passinput:<property_m_n>|-p <property_m_n>)]" << endl;
cerr << " [(--infile:<property_m_1>=<file_m_1>|-f <property_m_1>=<file_m_1>)" << endl;
cerr << " ... (--infile:<property_m_n>=<file_m_n>|-f <property_m_n>=<file_m_n>)]" << endl;
cerr << " [(--unset:property_m_1|-u property_m_1]) ... (--unset:property_m_n|-u property_m_n])]" << endl;
cerr << " [(--order:<property_m_1>[=(asc|desc|a|d)]|-o <property_m_1>[=(asc|desc|a|d)])" << endl;
cerr << " ..." << endl;
cerr << " [--globals|-l]" << endl;
cerr << " ..." << endl;
cerr << " (--order:<property_m_n>[=(asc|desc|a|d)]|-o <property_m_n>[=(asc|desc|a|d)]]" << endl;
cerr << " [object_m_1 ... object_m_n]" << endl;
}
int main(int argc, char *argv[])
{
if( argc == 1 ) {
printUsage(*argv);
exit(1);
}
vector<string> options(argv+1,argv+argc);
Transaction transact(options);
if( !transact ) {
printErrorMessage(transact, options);
printUsage(*argv);
exit(1);
}
Logger::log(Logger::DEBUG,"have parsed Parameters");
scoped_ptr<ConfigFileFinder> cfff(new ConfigFileFinder(transact));
shared_ptr<ConfigFileParser> cfg(new ConfigFileParser(cfff.get()));
Logger::log(Logger::DEBUG,"have read config File");
transact(cfg);
Logger::log(Logger::DEBUG,"have executed Transaction");
//cout << transact.formatOutput();
//exit(transact.errorCode());
return 0;
}

View File

@ -0,0 +1,146 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "httpclient.h"
#include "logger.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
using std::string;
using std::streamsize;
using std::iostream;
using boost::lexical_cast;
using boost::bad_lexical_cast;
TCPDevice::TCPDevice(const string& address, const short int port) {
this->init(address.c_str(),port);
}
TCPDevice::TCPDevice(const char* address, const short int port) {
this->init(address,port);
}
void TCPDevice::init(const char* address, const short int port) {
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
if( (addr.sin_addr.s_addr = inet_addr(address)) == INADDR_NONE ) {
struct hostent* hp = gethostbyname(address);
if( hp == 0 ) throw("can't resolve hostname '"+string(address)+"'");
bcopy(hp->h_addr, (char*) &addr.sin_addr, hp->h_length);
}
addr.sin_port = htons(port);
if( (m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) throw(string("can't open socket"));
if( ::connect(m_socket, (struct sockaddr*) &addr, sizeof(addr)) < 0 ) {
::close(m_socket);
throw("can't connect to '"+string(address)+"' port "+(lexical_cast<string>(port)));
}
}
TCPDevice::TCPDevice(const int socket) : m_socket(socket) {}
TCPDevice::TCPDevice(const TCPDevice& other) : m_socket(other.m_socket) { }
TCPDevice::~TCPDevice() { }
void TCPDevice::closeSocket() { ::close(m_socket); }
streamsize TCPDevice::read(char* s, streamsize n) { return (streamsize)::read(m_socket,(void*)s,(size_t)n); }
streamsize TCPDevice::write(const char* s, streamsize n) { return (streamsize)::write(m_socket,(const void*)s,(size_t)n); }
GenericHttpClient::GenericHttpClient(const string &url, const unsigned short defaultPort = 80):
m_url(url), m_defaultPort(defaultPort) {};
string GenericHttpClient::post(string postcontent) {
iostream *connection;
try { connection = this->parseUrl(); }
catch(string &e) {
Logger::log(Logger::FATAL,"connection failed: "+e);
exit(-1);
}
if( connection == 0 ) return "";
string outbuf = "POST "+m_path+" HTTP/1.1\r\n";
outbuf += "Connection: close\r\n";
outbuf += "User-Agent: hsadmin CLI client\r\n";
outbuf += "Content-Type: text/xml\r\n";
outbuf += "Content-Length: "+boost::lexical_cast<string>(postcontent.length())+"\r\n";
outbuf += "Host: "+m_hostname+"\r\n\r\n";
outbuf += postcontent;
for( int i = 0; i < outbuf.length(); i++ )
(*connection) << outbuf[i];;
connection->flush();
string reply = "";
char buf[257];
do { // we simply ignore the http header in the response
bzero(buf,257);
connection->getline(buf,256);
} while( string(buf) != "" && string(buf) != "\r" );
string tmp;
do {
tmp = "";
(*connection) >> tmp;
reply += " "+tmp;
} while( tmp.length() );
this->close();
delete connection;
return reply;
};
iostream * GenericHttpClient::parseUrl() {
int protocolend = m_url.find("://");
m_protocol = m_url.substr(0,protocolend);
if( ! this->checkProtocol(m_protocol) ) return (iostream *)0;
int hostnameend = m_url.find("/",protocolend+3);
m_hostname = m_url.substr(protocolend+3,hostnameend-(protocolend+3));
m_port = m_defaultPort;
m_path = m_url.substr(hostnameend);
int portstart = m_hostname.find(":");
if( portstart >= 0 ) {
string portstring = m_hostname.substr(portstart+1);
if( portstring.size() > 0 ) {
try {
m_port = lexical_cast<int>(portstring.c_str());
m_hostname = m_hostname.substr(0,m_hostname.find(":"));
} catch(bad_lexical_cast &) { }
}
}
return this->getConnection(m_hostname, m_port);
};
GenericHttpClient *createHttpClient(const string &url) {
int protocolend = url.find("://");
string protocol = url.substr(0,protocolend);
if( protocol == "http" ) return (GenericHttpClient *) new HttpClient<HTTP>(url);
if( protocol == "https" ) return (GenericHttpClient *) new HttpClient<HTTPS>(url);
return 0;
}

View File

@ -0,0 +1,163 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <iosfwd>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/iostreams/stream.hpp>
#include "sslclient.h"
#ifndef HSADMIN_HTTPCLIENT
#define HSADMIN_HTTPCLIENT
using std::string;
using std::iostream;
using std::streamsize;
using boost::lexical_cast;
using boost::bad_lexical_cast;
//! A Socket as a Device
class TCPDevice : public boost::iostreams::device<boost::iostreams::bidirectional> {
public:
//! create a TCP-Stream by connecting to the given port at the given address
TCPDevice(const string& address, const short int port);
//! create a TCP-Stream by connecting to the given port at the given address
TCPDevice(const char* address, const short int port);
//! create a TCP-Stream from a connected socket - use this with accept
TCPDevice(const int socket);
//! copy constructor
TCPDevice(const TCPDevice& other);
//! does not close the socket - use closeSocket before deleting the Device.
virtual ~TCPDevice();
//! closes the socket
void closeSocket();
//! read n Bytes from socket
virtual streamsize read(char* s, streamsize n);
//! write n Bytes to socket
virtual streamsize write(const char* s, streamsize n);
private:
void init(const char* address, const short int port);
int m_socket;
};
//class SSLDevice;
const int HTTP = 0;
const int HTTPS = 1;
//! the basic HTTP Client - can only handle POST method.
class GenericHttpClient {
public:
//! initialize HTTP CLient with URL and default Port (usually 80)
GenericHttpClient(const string &url, const unsigned short defaultPort);
//! Post
string post(string postcontent);
protected:
//! get a buffered iostream for the connection - must be overridden by derived classes
virtual iostream * getConnection(const string &host, unsigned short port) = 0;
//! check if this class can handle the protocol - must be overridden by derived classes
virtual bool checkProtocol(const string &protocol) { return false; };
//! close the underlying connection
virtual void close() = 0;
private:
iostream * parseUrl();
const string& m_url;
string m_protocol;
string m_hostname;
string m_path;
unsigned short m_port;
const unsigned short m_defaultPort;
};
//! This template should usually be used in one of the specialized Versions below.
template <int protocol> class HttpClient: public GenericHttpClient {
public:
HttpClient(const string &url, unsigned short defaultPort = 80): GenericHttpClient(url,defaultPort) {};
protected:
iostream * getConnection(const string &host, unsigned short port) { return (iostream *)0; };
bool checkProtocol(const string &p) { return false; };
virtual void close() { };
};
//! a HTTP CLient with a plain TCP socket as transport
template <> class HttpClient<HTTP>: public GenericHttpClient {
public:
//! initialize HTTP CLient with URL and default Port (usually 80)
HttpClient(const string &url, unsigned short defaultPort = 80): GenericHttpClient(url,defaultPort), device(0) {};
protected:
//! get a buffered iostream for the connection
iostream * getConnection(const string &host, unsigned short port) {
if( device == 0 ) device = new TCPDevice(host,port);
return (iostream *) new boost::iostreams::stream<TCPDevice>(*device);
}
//! check if this class can handle the protocol
bool checkProtocol(const string &protocol) { return (protocol == "http"); };
//! close the underlying connection
virtual void close() { device->closeSocket(); };
private:
TCPDevice *device;
};
//! a HTTP CLient with a SSL stream as transport
template <> class HttpClient<HTTPS>: public GenericHttpClient {
public:
//! initialize HTTPS CLient with URL and default Port (usually 443)
HttpClient(const string &url, unsigned short defaultPort = 443): GenericHttpClient(url,defaultPort), device(0) {};
protected:
//! get a buffered iostream for the connection
iostream * getConnection(const string &host, unsigned short port) {
try {
if( device == 0 ) device = new SSLDevice(host,port);
return (iostream *) new boost::iostreams::stream<SSLDevice>(*device);
} catch( SSLDevice::CertificateError &e ) {
if( device != 0 ) {
delete(device);
device = 0;
}
std::cerr << e.msg << std::endl;
return (iostream *)0;
}
}
//! check if this class can handle the protocol
bool checkProtocol(const string &protocol) { return (protocol == "https"); };
//! close the underlying connection
virtual void close() { device->closeSocket(); };
private:
SSLDevice *device;
};
/** \brief get the best HTTP client for the defined Protocol
*
* returns HttpClient<HTTP> or HttpClient<HTTPS> depending on the protocol
*/
GenericHttpClient *createHttpClient(const string &uri);
#else /* HSADMIN_HTTPCLIENT */
class TCPDevice;
class GenericHttpClient;
genericHttpClient *createHttpClient(url);
extern const int HTTP = 0;
extern const int HTTPS = 1;
#endif /* HSADMIN_HTTPCLIENT */

View File

@ -0,0 +1,136 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <map>
#include <fstream>
#include <errno.h>
#include "logger.h"
namespace Logger {
const int FATAL = 1;
const int ERROR = 2;
const int WARNING = 4;
const int DEBUG = 8;
const int XML = 16;
int levels[6] = { 1, 3, 7, 15, 23, 31 };
int level = 1;
std::map<int,std::string> messages;
void setLevel(int newlevel) {
level = newlevel;
if( level > 5 ) level = 5;
if( level < 0 ) level = 0;
}
void incrementLevel() {
level++;
if( level > 5 ) level = 5;
}
void decrementLevel() {
level--;
if( level < 0 ) level = 0;
}
void log(int type, const std::string text) {
int bitmask = levels[level];
if( type & bitmask )
std::cerr << text << std::endl;
}
void insertMessages(std::string filename) {
std::ifstream file(filename.c_str(),std::ios::in);
if( !file ) return;
char input[1024];
while(!file.eof()) {
bzero(input,1024);
file.getline(input,1023);
char *c = input;
// ignore whitespace at beginning of line
while( *c == ' ' || *c == '\t' ) c++;
// lines that dont't begin with a digit are ignored
if( *c < '0' || *c > '9' ) continue;
char *i = c;
while( *c >= '0' && *c <= '9' ) c++;
char *j = c;
while( *c == ' ' || *c == '\t' ) c++;
// the digit istn't followed by a '=' -> ignore this line
if( *c != '=' ) continue;
// separate number from content
*j = '\0';
std::string number(i);
std::string formatstring(c+1);
messages[boost::lexical_cast<int>(number)] = boost::trim_copy(formatstring);
}
}
void loadMessages() {
std::string lang = getenv("LANG");
std::string priv = getenv("HOME");
try {
boost::filesystem::path general("/etc/hsadminc.messages");
if( boost::filesystem::exists(general) && !boost::filesystem::is_directory(general) )
insertMessages(general.native());
} catch(boost::filesystem::filesystem_error) {}
try {
boost::filesystem::path generalLang("/etc/hsadminc.messages."+lang);
if( boost::filesystem::exists(generalLang) && !boost::filesystem::is_directory(generalLang) )
insertMessages(generalLang.native());
} catch(boost::filesystem::filesystem_error) {}
try {
boost::filesystem::path p( priv + "/.hsadmin.messages" );
if( boost::filesystem::exists(p) && !boost::filesystem::is_directory(p) )
insertMessages(p.native());
} catch(boost::filesystem::filesystem_error) {}
try {
boost::filesystem::path pLang( priv + "/.hsadmin.messages."+lang );
if( boost::filesystem::exists(pLang) && !boost::filesystem::is_directory(pLang) )
insertMessages(pLang.native());
} catch(boost::filesystem::filesystem_error) {}
}
std::string getErrnoMessage(int e) {
if( messages.empty() ) loadMessages();
std::map<int,std::string>::iterator i = messages.find(e);
if( i != messages.end() ) return i->second;
else return std::string("");
}
std::string getMessageFormatString(const message msg) {
return getErrnoMessage((int)msg);
}
}

View File

@ -0,0 +1,68 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef HSADMIN_LOGGER
#define HSADMIN_LOGGER
#include <string>
#include <stdarg.h>
//! a simple logger
namespace Logger {
extern const int FATAL;
extern const int ERROR;
extern const int WARNING;
extern const int DEBUG;
extern const int XML;
extern int levels[6];
extern int level;
typedef enum {
CouldNotOpenFile = 1001,
NoBodyInResponse = 1002,
CantResolveHostname = 1003,
CantOpenSocket = 1004,
CantConnetcToHost = 1005,
ServerErrorCode = 1006,
UnknownCallbackInXMLParser = 1007,
ConnectionFailed = 1008,
ErrorWithTicketCommand = 1009,
ErrorReadingTicket = 1010
} message;
//! change the loglevel - used by VerbosityOption
void setLevel(int newlevel);
//! increment the loglevel - used by VerbosityOption
void incrementLevel();
//! decrement theloglevel - used by QuietOption
void decrementLevel();
//! do actualy output loginfo
void log(int type, const std::string text);
//! get a message format string for a defined Message Type; use boost::format to insert Values
std::string getMessageFormatString(const message msg);
//! get an appropriate Message for an errno.
std::string getErrnoMessage(int e);
};
#endif /* HSADMIN_LOGGER */

View File

@ -0,0 +1,171 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "sslclient.h"
#include "logger.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <boost/filesystem/operations.hpp>
#include <boost/lexical_cast.hpp>
#include <gnutls/x509.h>
using std::string;
using std::streamsize;
using boost::lexical_cast;
using boost::bad_lexical_cast;
int SSLDevice::countInstances = 0;
SSLDevice::SSLDevice(const string& address, const short int port): m_session(0) {
this->init(address.c_str(),port);
}
SSLDevice::SSLDevice(const char* address, const short int port): m_session(0) {
this->init(address,port);
}
void SSLDevice::init(const char* address, const short int port) {
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
if( (addr.sin_addr.s_addr = inet_addr(address)) == INADDR_NONE ) {
struct hostent* hp = gethostbyname(address);
if( hp == 0 ) throw("can't resolve hostname '"+string(address)+"'");
bcopy(hp->h_addr, (char*) &addr.sin_addr, hp->h_length);
}
addr.sin_port = htons(port);
if( (m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) throw(string("can't open socket"));
if( ::connect(m_socket, (struct sockaddr*) &addr, sizeof(addr)) < 0 ) {
::close(m_socket);
throw("can't connect to '"+string(address)+"' port "+(lexical_cast<string>(port)));
}
const int cert_type_priority[3] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
m_session = new gnutls_session;
if( countInstances == 0 ) gnutls_global_init();
countInstances++;
gnutls_certificate_allocate_credentials(&m_xcred);
gnutls_certificate_set_x509_trust_file(m_xcred, "ca.pem", GNUTLS_X509_FMT_PEM);
gnutls_init(m_session,GNUTLS_CLIENT);
gnutls_set_default_priority(*m_session);
gnutls_credentials_set(*m_session, GNUTLS_CRD_CERTIFICATE, m_xcred);
gnutls_transport_set_ptr(*m_session, (gnutls_transport_ptr)&m_socket);
if( gnutls_handshake(*m_session) < 0 )
throw(string(gnutls_protocol_get_name(gnutls_protocol_get_version(*m_session)))+" Handshake failed");
verify_certificate( *m_session, address);
}
SSLDevice::SSLDevice(const SSLDevice& other) : m_session(other.m_session), m_socket(other.m_socket), m_xcred(other.m_xcred) { }
SSLDevice::~SSLDevice() { }
void SSLDevice::closeSocket() {
gnutls_bye(*m_session, GNUTLS_SHUT_RDWR);
gnutls_certificate_free_credentials(m_xcred);
::close(m_socket);
gnutls_deinit(*m_session);
delete(m_session);
countInstances--;
if( countInstances == 0 ) gnutls_global_deinit();
}
streamsize SSLDevice::read(char* s, streamsize n) { return (streamsize)gnutls_record_recv(*m_session,(void*)s,(size_t)n); }
streamsize SSLDevice::write(const char* s, streamsize n) {
/*streamsize i = (streamsize)gnutls_record_send(*m_session,(const void*)s,(size_t)n);
Logger::log(Logger::DEBUG,string("sending ")+boost::lexical_cast<string>(i)+" von "+boost::lexical_cast<string>(n)+" bytes: \n---\n"+s+"\n---\n");*/
return (streamsize)gnutls_record_send(*m_session,(const void*)s,(size_t)n); //i;
}
void SSLDevice::verify_certificate( gnutls_session session, string hostname) {
boost::filesystem::path general("/etc/hsadminc.cert");
if( boost::filesystem::exists(general) && !boost::filesystem::is_directory(general) )
gnutls_certificate_set_x509_trust_file (m_xcred, general.native().c_str(), GNUTLS_X509_FMT_PEM);
//string privfilename = getenv("HOME");
string priv = getenv("HOME");
boost::filesystem::path p( priv + "/.hsadmin.cert" );
//p /= ".hsadminc.conf";
if( boost::filesystem::exists(p) && !boost::filesystem::is_directory(p) )
gnutls_certificate_set_x509_trust_file (m_xcred, p.native().c_str(), GNUTLS_X509_FMT_PEM);
//gnutls_certificate_set_x509_trust_file (m_xcred, const char * cafile, PEM)
unsigned int status = 0;//gnutls_certificate_verify_peers(*m_session);
/*if( gnutls_certificate_verify_peers2(*m_session, &status) < 0 )
throw(string("Error while verifying certificate"));*/
string tval = "Certificate Verification failed: ";
if( status & GNUTLS_CERT_INVALID ) { throw(tval+"The certificate is not trustet"); }
if( status & GNUTLS_CERT_SIGNER_NOT_FOUND ) { throw(tval+"The certificate has no known Issuer"); }
if( status & GNUTLS_CERT_REVOKED ) { throw(tval+"The certificate has been revoked"); }
// the further checks are only valid for X509 certificates
if ( gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) return;
const gnutls_datum* cert_list;
unsigned int cert_list_size;
gnutls_x509_crt cert;
if ( gnutls_x509_crt_init(&cert) < 0) throw(tval+"error in initialization");
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
if ( cert_list == NULL ) throw(tval+"no certificate found");
bool failed = false;
string tReason = "";
for( int i = 0; i < cert_list_size-1; i++ ) {
bool failed = false;
if ( gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
throw(tval+"error parsing certificate Number "+lexical_cast<string>(i));
if ( gnutls_x509_crt_get_expiration_time(cert) < time(0) ) {
tReason = "The certificate has expired";
failed = true;
}
if ( gnutls_x509_crt_get_activation_time(cert) > time(0) ) {
tReason = "The certificate is not yet activated";
failed = true;
}
if ( !gnutls_x509_crt_check_hostname(cert,hostname.c_str()) ) {
tReason = "The certificates owner does not match hostname ";
tReason += hostname +"'";
failed = true;
}
gnutls_x509_crt_deinit(cert);
if( !failed ) break;
}
if( failed ) throw(tval+tReason);
}

View File

@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <iosfwd>
#include <string>
#include <iostream>
#include <boost/iostreams/stream.hpp>
#include <gnutls/gnutls.h>
#ifndef HSADMIN_SSLCLIENT
#define HSADMIN_SSLCLIENT
using std::string;
using std::streamsize;
//! A SSL connection as a Device
class SSLDevice : public boost::iostreams::device<boost::iostreams::bidirectional> {
public:
//! create a SSL-Stream by connecting to the given port at the given address and checking the Certificate
SSLDevice(const string& address, const short int port);
//! create a SSL-Stream by connecting to the given port at the given address and checking the Certificate
SSLDevice(const char* address, const short int port);
//! copy constructor
SSLDevice(const SSLDevice& other);
//! does not close the SSL strem - use closeSocket before deleting the Device.
virtual ~SSLDevice();
//! closes the SSL Stream
void closeSocket();
//! read n Bytes from SSL Stream
virtual streamsize read(char* s, streamsize n);
//! write n Bytes to SSL stream
virtual streamsize write(const char* s, streamsize n);
//! indicates an error while checking the certificate
class CertificateError {
public:
CertificateError(const string &s): msg(s) {};
CertificateError(const char* s): msg(s) {};
string msg;
};
private:
void init(const char* address, const short int port);
void verify_certificate( gnutls_session session, string hostname);
gnutls_session *m_session;
gnutls_certificate_credentials m_xcred;
int m_socket;
static int countInstances;
};
#else /* HSADMIN_SSLCLIENT */
class SSLDevice;
#endif /* HSADMIN_SSLCLIENT */

View File

@ -0,0 +1,502 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "transaction.h"
#include "xmlparser.h"
#include "httpclient.h"
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include <boost/format.hpp>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
using boost::lexical_cast;
using boost::bad_lexical_cast;
using namespace xmlParser;
Transaction::Transaction(vector<string> options) :
abstractcommandlineparser::CmdLineParser<commandline::Parameters,commandline::parsedParameters>(options),
m_nextAttributeValue(""),
m_globalFault(false),
m_currentCall(0) {
if(!this->m_parseSuccessful) return;
vector<shared_ptr<commandline::callParameter> >& calls = m_parsed->m_call;
for( vector<shared_ptr<commandline::callParameter> >::iterator c = calls.begin(); c != calls.end(); c++ ) {
shared_ptr<commandline::callParameter> call = *c;
vector<shared_ptr<commandline::orderParameter> >::iterator orderhere = call->m_order.end();
if( call->m_globalOrderIndex >= 0 ) orderhere = call->m_order.begin()+call->m_globalOrderIndex;
call->m_order.insert( orderhere, m_parsed->m_globalOrder.begin(), m_parsed->m_globalOrder.end() );
call->m_where.insert( call->m_where.end(), m_parsed->m_only.begin(), m_parsed->m_only.end() );
call->m_set.insert( call->m_set.end(), m_parsed->m_setall.begin(), m_parsed->m_setall.end() );
call->m_unset.insert( call->m_unset.end(), m_parsed->m_unsetall.begin(), m_parsed->m_unsetall.end() );
if( m_parsed->m_ignoreerrors ) call->m_ignoreerror = true;
}
};
void Transaction::operator()(shared_ptr<ConfigFileParser> cfgfile) {
class {
public:
void post(string &url) {
GenericHttpClient * client = createHttpClient(url);
m_response = client->post(m_request);
};
void execCall(Transaction *t, string &username, string &url, shared_ptr<ConfigFileParser> cfgfile) {
m_request = t->getParsed()->toXML(username,cfgfile);
Logger::log(Logger::XML,"--XML request--\n"+m_request+"\n---");
this->post(url);
ResponseParser parse;
if( !parse(m_response, t) ) Logger::log(Logger::XML,"parse error");
Logger::log(Logger::XML,"response parsed:");
if(Logger::XML && Logger::levels[Logger::level]) logNode(t->m_docelem,0);
}
void logNode(Node* node, int ind) {
Text *text;
Element *elm;
string indent = "";
for( int j = 0; j < ind; j++ ) indent += " ";
string attributes;
switch(node->m_type) {
case ELEMENT:
elm = (Element*)node;
for(map<string,string>::iterator i = elm->m_attributes.begin(); i != elm->m_attributes.end(); i++)
attributes += " "+(i->first)+"=\""+(i->second)+"\"";
Logger::log(Logger::XML,indent+"<"+elm->m_name+attributes+">");
for( vector<Node*>::iterator i = elm->m_nodes.begin(); i != elm->m_nodes.end(); i++ )
logNode(*i,ind+1);
Logger::log(Logger::XML,indent+"</"+elm->m_name+">");
break;
case TEXT:
text = (Text*)node;
Logger::log(Logger::XML,indent+text->m_content);
break;
}
}
private:
int connectToHost(const string hostname, const int port) const {
int sock;
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
if( (server_addr.sin_addr.s_addr = inet_addr(hostname.c_str())) == INADDR_NONE ) {
struct hostent* hp = gethostbyname(hostname.c_str());
if( hp == 0 ) {
string msg = Logger::getMessageFormatString(Logger::CantResolveHostname);
boost::format fmt(msg);
fmt % hostname;
Logger::log(Logger::FATAL,fmt.str());
exit(1);
}
bcopy(hp->h_addr, (char*) &server_addr.sin_addr, hp->h_length);
}
server_addr.sin_port = htons(port);
if( (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {
Logger::log(Logger::FATAL,Logger::getMessageFormatString(Logger::CantOpenSocket));
exit(1);
}
if( connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0 ) {
string msg = Logger::getMessageFormatString(Logger::CantConnetcToHost);
boost::format fmt(msg);
fmt % hostname % port;
Logger::log(Logger::FATAL,fmt.str());
close(sock);
exit(1);
}
return sock;
}
string m_request;
string m_response;
} XMLRPCrequest;
string username = "";
ConfigFileParser::config cfg = cfgfile->getConfig(username);
string url = cfg.server;
username = this->getUser();
cfg = cfgfile->getConfig(username);
if( cfg.server != "" ) url = cfg.server;
Logger::log(Logger::DEBUG,"now I know which Config to use");
XMLRPCrequest.execCall(this,username,url,cfgfile);
}
// XML Parser stuff
Element* Transaction::stepin(int count,Element* value) {
if( count<= 0 ) return value;
for( ; count > 0; count-- )
if(value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0];
return value;
}
string Transaction::getContent(Element* value) {
while( value->m_nodes.size() > 0 && value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0];
if( value->m_nodes.size() > 0 ) {
Text* txt = (Text*)value->m_nodes[0];
if( value->m_name == "boolean") {
int b = boost::lexical_cast<int>(replaceEntities(txt->m_content));
return (b == 0)?"false":"true";
} else if( value->m_name == "dateTime.iso8601") {
string datestring = replaceEntities(txt->m_content);
string year = datestring.substr(0,4);
string month = datestring.substr(4,2);
string day = datestring.substr(6,2);
string hour = datestring.substr(9,2);
string minute= datestring.substr(12,2);
string second= datestring.substr(15,2);
return day+"."+month+"."+year+" "+hour+":"+minute+":"+second;
} else if( value->m_name == "base64") {
string encoded = replaceEntities(txt->m_content);
string decoded;
char next = '\0';
int shift = 0;
while( encoded.size() ) {
int d = encoded[0];
encoded = encoded.substr(1,encoded.size()-1);
if ( d >= 'A' && d <= 'Z') d -= 'A';
else if ( d >= 'a' && d <= 'z') d = (d-'a')+26;
else if ( d >= '0' && d <= '9') d = (d-'0')+52;
else if ( d == '+') d = 62;
else if ( d == '/') d = 63;
else continue;
next += d << shift;
if( !shift ) { decoded += (char)(next&255); next = next >> 8; }
shift = (shift-2)%8;
}
if( shift ) decoded += next;
return decoded;
} else {
return replaceEntities(txt->m_content);
}
}
return string("");
}
void Transaction::handleElem(Element * elem) {
if( m_tagstack.size() == 0 ) {
m_docelem = elem;
return;
}
Element *array, *data;
int tab = 8;
switch( m_tagstack.size() ) {
case 6: // fill next call
if(elem->m_name != "value" ) break;
array = (Element*)(elem->m_nodes[0]);
if( array->m_name == "struct" ) {
map<string,string> errorstruct;
if(array->m_nodes.size() != 0) for(vector<Node*>::iterator n = array->m_nodes.begin(); n != array->m_nodes.end(); n++) {
Element* member = (Element*)(*n);
if(member->m_nodes.size() >= 2) {
Element *name, *value;
name = (Element*)member->m_nodes[0];
if( name->m_name == "value" ) {
value = name;
name = (Element*)member->m_nodes[1];
} else
value = (Element*)member->m_nodes[1];
while( name->m_nodes.size() > 0 && name->m_nodes[0]->m_type == xmlParser::ELEMENT ) name = (Element*)name->m_nodes[0];
while( value->m_nodes.size() > 0 && value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0];
if( value->m_nodes.size() > 0 && name->m_nodes.size() > 0 ) {
string namtxt = getContent(name);
string valtxt = getContent(value);
errorstruct[namtxt] = valtxt;
}
}
}
string msg = Logger::getMessageFormatString(Logger::ServerErrorCode);
int errnum = boost::lexical_cast<int>(errorstruct["errorcode"]);
string errorstring = Logger::getErrnoMessage(errnum);
if( errorstring != "" ) errorstruct["errorstring"] = errorstring;
boost::format fmt(msg);
fmt % errorstruct["errorcode"] % errorstruct["errorstring"];
Logger::log(Logger::ERROR,fmt.str());
break;
}
data = (Element*)(array->m_nodes[0]);
if(data->m_nodes.size() != 0) {
vector<string> headlines;
int tabpos = 0;
vector<int> tabstops;
Element* headlinesdata = stepin(3,data);
if( m_parsed->m_call[m_currentCall]->m_display == "" ) {
if(headlinesdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = headlinesdata->m_nodes.begin(); in != headlinesdata->m_nodes.end(); in++) {
string output = "";
if((*in)->m_type == xmlParser::ELEMENT ) {
output = getContent((Element*)(*in));
} else {
Text* txt = (Text*)(*in);
output = replaceEntities(txt->m_content);
}
std::cout << output;
tabstops.push_back(tabpos);
tabpos += output.length();
if( in+1 != headlinesdata->m_nodes.end() )do {
std::cout << " ";
tabpos++;
} while( tabpos % tab );
}
std::cout << "\n";
for(;tabpos;tabpos--) std::cout << "-";
std::cout << "\n";
} else {
if(headlinesdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = headlinesdata->m_nodes.begin(); in != headlinesdata->m_nodes.end(); in++) {
string headline = getContent((Element*)(*in));
if( headline != "" ) headlines.push_back( headline );
}
}
Element* contentvalue;
if(data->m_nodes[1]->m_type == xmlParser::ELEMENT ) contentvalue = (Element*)data->m_nodes[1];
else contentvalue = data;
Element* contentdata = stepin(2,contentvalue);
if(contentdata->m_nodes.size() != 0) for(vector<Node*>::iterator n = contentdata->m_nodes.begin(); n != contentdata->m_nodes.end(); n++) {
if( m_parsed->m_call[m_currentCall]->m_display == "" ) {
tabpos = 0;
int i = 0;
Element* innerdata = stepin(2,(Element*)(*n));
if(innerdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = innerdata->m_nodes.begin(); in != innerdata->m_nodes.end(); in++) {
string oputput = getContent((Element*)(*in));
while( tabpos < tabstops[i] ) {
std::cout << " "; tabpos++;
}
std::cout << oputput;
tabpos += oputput.length();
i++;
}
std::cout << "\n";
} else {
map<string,string> values;
int i = 0;
Element* innerdata = stepin(2,(Element*)(*n));
if(innerdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = innerdata->m_nodes.begin(); in != innerdata->m_nodes.end(); in++) {
string oputput = getContent((Element*)(*in));
if( oputput != "" ) {
values[headlines[i]] = oputput;
i++;
}
}
std::cout << m_parsed->m_call[m_currentCall]->evalDisplay(values);
}
}
}
m_currentCall++;
break;
default:
break;
}
m_tagstack.top().m_nodes.push_back(elem);
}
void Transaction::handleGlobalFaultElem(xmlParser::Element * elem) {
if( m_tagstack.size() == 0 ) {
m_docelem = elem;
return;
}
Text *txt;
switch( m_tagstack.size() ) {
case 5:
if(elem->m_name == "value" )
Logger::log(Logger::FATAL,getContent(elem));
break;
default:
break;
}
m_tagstack.top().m_nodes.push_back(elem);
}
string Transaction::replaceEntities(const string &input) {
string rval;
for( string::const_iterator i = input.begin(); i != input.end(); i++ ) {
if( *i != '&' ) rval += *i;
else {
string tmp;
int j;
for( j = 1; *(i+j) != ';' && i+j != input.end(); j++ ) tmp += *(i+j);
if( *(i+j) != ';' ) { rval += "&"; continue; }
if( tmp == "amp" ) {
rval += "&";
i+=j;
} else if( tmp == "gt" ) {
rval += ">";
i+=j;
} else if( tmp == "lt" ) {
rval += "<";
i+=j;
} else if( tmp == "quot" ) {
rval += "\"";
i+=j;
} else if( tmp == "apos" ) {
rval += "'";
i+=j;
} else if( tmp[0] == '#' ) {
if( tmp[1] != 'x' ) {
wchar_t value[2];
value[0] = lexical_cast<int>(tmp.substr(1));
value[1] = 0;
char u[255];
bzero(u,255);
wcstombs(u,value,254);
rval += u;
i+=j;
} else {
wchar_t value[2];
value[0] = 0;
value[1] = 0;
if ( tmp[2] >= '0' && tmp[2] <= '9' ) value[0] = tmp[2]-'0';
else if( tmp[2] >= 'a' && tmp[2] <= 'f' ) value[0] = tmp[2]-'a';
else if( tmp[2] >= 'A' && tmp[2] <= 'F' ) value[0] = tmp[2]-'A';
else { rval += "&"; continue;}
value[0] = value[0] << 4;
if ( tmp[3] >= '0' && tmp[3] <= '9' ) value[0] += tmp[3]-'0';
else if( tmp[3] >= 'a' && tmp[3] <= 'f' ) value[0] += tmp[3]-'a';
else if( tmp[3] >= 'A' && tmp[3] <= 'F' ) value[0] += tmp[3]-'A';
else { rval += "&"; continue; }
char u[255];
bzero(u,255);
wcstombs(u,value,254);
rval += u;
i+=j;
}
} else {
rval += "&";
}
}
}
return rval;
}
bool Transaction::operator()(int type, string content) {
string tmp;
Element elem, currentelem;
Text text;
switch( type ) {
case responseParserHook::ELEMENT:
break;
case responseParserHook::ATTRIBUTE:
m_nextAttributeList[content] = m_nextAttributeValue;
m_nextAttributeValue = "";
break;
case responseParserHook::TEXT:
if( m_tagstack.size() ) {
m_tagstack.top().m_nodes.push_back(new Text(content));
} else return false;
break;
case responseParserHook::CDATA:
if( m_tagstack.size() ) {
m_tagstack.top().m_nodes.push_back(new Text(content));
} else return false;
break;
case responseParserHook::PROCESSING_INSTRUCTION:
if( m_nextAttributeList["version"] != "1.0" || content != "xml" ) return false;
tmp = "";
for(map<string,string>::iterator i = m_nextAttributeList.begin(); i != m_nextAttributeList.end(); i++)
tmp += " "+(i->first)+"="+(i->second);
m_nextAttributeList.clear();
break;
case responseParserHook::COMMENT:
break;
case responseParserHook::DOCUMENT:
break;
case responseParserHook::START_ELEMENT:
if(m_tagstack.size() == 1 && content == "fault") m_globalFault = true;
elem = Element(content,m_nextAttributeList,vector<Node*>());
m_nextAttributeList.clear();
m_tagstack.push(elem);
break;
case responseParserHook::END_ELEMENT:
currentelem = m_tagstack.top();
m_tagstack.pop();
if( currentelem.m_name != content ) {
return false;
}
if( !m_globalFault ) handleElem(new Element(currentelem));
else handleGlobalFaultElem(new Element(currentelem));
break;
case responseParserHook::EMPTY_ELEMENT:
if(m_tagstack.size() == 1 && content == "fault") m_globalFault = true;
if( !m_globalFault ) handleElem(new Element(content,m_nextAttributeList,vector<Node*>()));
else handleGlobalFaultElem(new Element(content,m_nextAttributeList,vector<Node*>()));
m_nextAttributeList.clear();
break;
case responseParserHook::ATTRIBUTE_VALUE:
m_nextAttributeValue = content;
break;
default:
string msg = Logger::getMessageFormatString(Logger::UnknownCallbackInXMLParser);
boost::format fmt(msg);
fmt % type % content;
Logger::log(Logger::FATAL,fmt.str());
break;
}
return true;
}

View File

@ -0,0 +1,77 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "cmdlineparser.h"
#include "xmlparser.h"
#include <boost/shared_ptr.hpp>
#include <stack>
#include <map>
#include <vector>
#include <string>
#ifndef HSADMIN_TRANSACTION
#define HSADMIN_TRANSACTION
using boost::shared_ptr;
using std::stack;
using std::map;
using std::vector;
using std::string;
//! encapsulates a transaction.
class Transaction:
public abstractcommandlineparser::CmdLineParser<commandline::Parameters,commandline::parsedParameters>,
public xmlParser::responseParserHook {
public:
//! parses all the commandline-Parameters
Transaction(vector<string> options);
string& getUser() { return m_parsed->m_user; };
//! actually execute the transaction - just needs the config and does everything else for you
void operator()(shared_ptr<ConfigFileParser> cfgfile);
//! callback for XML-Parser
virtual bool operator()(int type, string content);
//! returns the parsed parameters
shared_ptr<commandline::parsedParameters> getParsed() { return m_parsed; };
private:
bool m_globalFault;
int m_currentCall;
stack<xmlParser::Element> m_tagstack;
string m_nextAttributeValue;
map<string,string> m_nextAttributeList;
void handleElem(xmlParser::Element * elem);
void handleGlobalFaultElem(xmlParser::Element * elem);
string replaceEntities(const string &input);
string getContent(xmlParser::Element* value);
xmlParser::Element* stepin(int count,xmlParser::Element* value);
public:
xmlParser::Element *m_docelem;
};
#else
class Transaction;
#endif /* HSADMIN_TRANSACTION */

View File

@ -0,0 +1,209 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "xmlparser.h"
#include "logger.h"
namespace xmlParser {
bool parser::operator()(const string& content, int &pos, responseParserHook *hook) { return false; }
bool spaceParser::operator()(const string& content, int &pos, responseParserHook *hook) {
if( content[pos] == ' ' || content[pos] == '\t' || content[pos] == '\n' || content[pos] == '\r' ) {
pos++; return true;
}
return false;
}
bool commentParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content.substr(pos,4) == "<!--" ) {
pos+= 4;
while( content.substr(pos,3) != "-->" && pos < content.length() ) pos++;
if(pos < content.length()) {
pos += 3; return (*hook)(8,content.substr(oldpos+4,(pos-oldpos)-7));
}
pos = oldpos;
return false;
}
return false;
}
bool nameParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( !( (content[pos] >= '0' && content[pos] <= '9' ) ||
(content[pos] >= 'a' && content[pos] <= 'z' ) ||
(content[pos] >= 'A' && content[pos] <= 'Z' ) ||
content[pos] == '.' ||
content[pos] == ':' ||
content[pos] == '_' ) )
return false;
while( (content[pos] >= '0' && content[pos] <= '9' ) ||
(content[pos] >= 'a' && content[pos] <= 'z' ) ||
(content[pos] >= 'A' && content[pos] <= 'Z' ) ||
content[pos] == '.' ||
content[pos] == ':' ||
content[pos] == '_' ) pos++;
return true;
}
bool attributeValueParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content[pos] == '"' ) {
pos++;
while( content[pos] != '"' && pos < content.length() ) pos++;
if( pos >= content.length() ) { pos = oldpos; return false; }
pos++;
}
else if( content[pos] == '\'' ) {
pos++;
while( content[pos] != '\'' && pos < content.length() ) pos++;
if( pos >= content.length() ) { pos = oldpos; return false; }
pos++;
} else {
pos = oldpos;
return false;
}
return (*hook)(32,content.substr(oldpos+1,(pos-oldpos)-2));
}
bool attributeParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( ! space(content,pos,hook) ) return false;
while(space(content,pos,hook) && pos < content.length() );
int namestartpos = pos;
if( ! name(content,pos,hook) ) { pos = oldpos; return false; }
int nameendpos = pos;
if( content[pos] != '=' ) { pos = oldpos; return false; }
pos++;
if( ! value(content,pos,hook) ) { pos = oldpos; return false; }
return (*hook)(2,content.substr(oldpos+1,(nameendpos-oldpos)-1));
};
bool emptyelemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content[pos] != '<' ) return false;
pos++;
if( !name(content,pos,hook) ) { pos = oldpos; return false; }
int nameendpos = pos;
while(attrib(content,pos,hook) && pos < content.length() );
while(space(content,pos,hook) && pos < content.length() );
if( content.substr(pos,2) != "/>" ) { pos = oldpos; return false; }
pos += 2;
return (*hook)(18,content.substr(oldpos+1,(nameendpos-oldpos)-1));
}
bool startelemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content[pos] != '<' ) return false;
pos++;
if( !name(content,pos,hook) ) { pos = oldpos; return false; }
int nameendpos = pos;
while(attrib(content,pos,hook) && pos < content.length() );
while(space(content,pos,hook) && pos < content.length() );
if( content[pos] != '>' ) { pos = oldpos; return false; }
pos ++;
return (*hook)(16,content.substr(oldpos+1,(nameendpos-oldpos)-1));
}
bool endelemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content.substr(pos,2) != "</" ) return false;
pos += 2;
if( !name(content,pos,hook) ) { pos = oldpos; return false; }
int nameendpos = pos;
while(space(content,pos,hook) && pos < content.length() );
if( content[pos] != '>' ) { pos = oldpos; return false; }
pos ++;
return (*hook)(17,content.substr(oldpos+2,(nameendpos-oldpos)-2));
}
bool textParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content[pos] == '<' )
return false;
while( content[pos] != '<' && pos < content.length() ) pos++;
return (*hook)(3,content.substr(oldpos,pos-oldpos));
};
bool cdataParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content.substr(pos,9) != "<![CDATA[" ) return false;
bool foundend = false;
while( !( foundend = (content.substr(pos,3) == "]]>") ) && pos < content.length() ) pos++;
if( !foundend ) { pos = oldpos; return false; }
pos += 3;
return (*hook)(4,content.substr(oldpos+9,(pos-oldpos)-12));
};
bool elemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( emptyelem(content,pos,hook) ) return (*hook)(1,content.substr(oldpos,pos-oldpos));
if( ! elemstart(content,pos,hook) ) return false;
bool foundend = false;
while( !(foundend = endelem(content,pos,hook)) && pos < content.length() ) {
if( ! ( comspace(content,pos,hook) ||
text(content,pos,hook) ||
(*this)(content,pos,hook) ||
cdata(content,pos,hook) ) ) {
pos = oldpos;
return false;
}
}
if( foundend ) return (*hook)(1,content.substr(oldpos,pos-oldpos));
return false;
}
bool xmlpcParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( content.substr(pos,5) != "<?xml" ) return false;
pos += 5;
while(attrib(content,pos,hook) && pos < content.length() );
while(space(content,pos,hook) && pos < content.length() );
if( content.substr(pos,2) != "?>" ) { pos = oldpos; return false; }
pos += 2;
return (*hook)(7,string("xml"));
}
bool XMLParser::operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
while(space(content,pos,hook) && pos < content.length() );
if( ! xmlpc(content,pos,hook) ) { pos = oldpos; return false; }
while(comspace(content,pos,hook) && pos < content.length() );
if( ! elem(content,pos,hook) ) { pos = oldpos; return false; }
while(comspace(content,pos,hook) && pos < content.length() );
return (*hook)(9,content.substr(oldpos,pos-oldpos));
}
bool ResponseParser::operator()(const string& content, responseParserHook *hook) {
int pos = 0;
bool rval = xml(content,pos,hook);
if( pos < content.length() ) return false;
return rval;
}
}

View File

@ -0,0 +1,296 @@
/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <string>
#include <map>
#include <vector>
#ifndef HSADMIN_XMLPARSER
#define HSADMIN_XMLPARSER
/** \brief a general XML Parser
*
* well, it works for me. The API is inspired a bit by SAX, but I didn't
* whant to create the full SAX API.
*/
namespace xmlParser {
using std::string;
using std::map;
using std::vector;
//! Node Types
typedef enum {
UNKNOWN = 0,
ELEMENT = 1,
ATTRIBUTE = 2,
TEXT = 3,
CDATA = 4,
PROCESSING_INSTRUCTION = 7,
COMMENT = 8,
DOCUMENT = 9,
} nodeType;
//! base class for all Nodes
class Node {
public:
Node(nodeType type): m_type(type) {};
Node(): m_type(UNKNOWN) {};
nodeType m_type;
};
//! Text node
class Text: public Node {
public:
Text(): m_content(""), Node::Node(TEXT) {};
//! create a Text node from a C++ String
Text(string content): m_content(content), Node::Node(TEXT) {};
//! copy-construct a Text node
Text(const Text &text): m_content(text.m_content), Node::Node(TEXT) {};
//! the actual text
string m_content;
};
//! Element node
class Element: public Node {
public:
Element():
m_nodes(vector<Node*>(0)),
m_attributes(map<string,string>()),
m_name(""),
Node::Node(ELEMENT) {};
//! create a Element from its tag-name , a List of Attributes and a List of Child-Nodes
Element(string name, map<string,string> attributes, vector<Node*> content):
m_nodes(content),
m_attributes(attributes),
m_name(name),
Node::Node(ELEMENT) {};
//! copy-construct a Element Node
Element(const Element &elm):
m_nodes(elm.m_nodes),
m_attributes(elm.m_attributes),
m_name(elm.m_name),
Node::Node(ELEMENT) {};
//! The tag name
string m_name;
//! the attributes
map<string,string> m_attributes;
//! che child nodes
vector<Node*> m_nodes;
};
//! the XML parser calls the operator() for everything it finds
class responseParserHook {
public:
enum {
ELEMENT = 1,
ATTRIBUTE = 2,
TEXT = 3,
CDATA = 4,
PROCESSING_INSTRUCTION = 7,
COMMENT = 8,
DOCUMENT = 9,
START_ELEMENT = 16,
END_ELEMENT = 17,
EMPTY_ELEMENT = 18,
ATTRIBUTE_VALUE = 32,
};
virtual bool operator()(int type, string content) = 0;
};
//! a dummy Parser; the general parser base class
class parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
/** \brief Template to construct a Parser from two parsers.
*
* combines the results of the two parsers with 'or'.
*/
template <class first, class second> class orRule : public parser {
public:
inline bool operator()(const string& content, int &pos, responseParserHook *hook) {
int oldpos = pos;
if( !car(content,pos,hook) ) return cdr(content,pos,hook);
return true;
};
private:
first car;
second cdr;
};
//! parse everything that is a space
class spaceParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
//! parse XML comments
class commentParser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
//! parse either spaces or comments
typedef orRule<spaceParser, commentParser> comspaceParser;
//! parse XML names
class nameParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
//! parse XML attribute values
class attributeValueParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
//! parse XML attributes with name and value
class attributeParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
nameParser name;
spaceParser space;
attributeValueParser value;
};
//! parse an empty element
class emptyelemParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
nameParser name;
attributeParser attrib;
spaceParser space;
};
//! parse the start of an element
class startelemParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
nameParser name;
attributeParser attrib;
spaceParser space;
};
//! parse the end of an element
class endelemParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
nameParser name;
spaceParser space;
};
//! parse Text
class textParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
//! parse CDATA-sections
class cdataParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
};
//! parse general Elements
class elemParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
emptyelemParser emptyelem;
startelemParser elemstart;
comspaceParser comspace;
endelemParser endelem;
textParser text;
cdataParser cdata;
};
//! parse the xml Processing instruction at the beginning of each XML-File
class xmlpcParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
nameParser name;
attributeParser attrib;
spaceParser space;
};
//! parse an XML-File
class XMLParser: public parser {
public:
bool operator()(const string& content, int &pos, responseParserHook *hook);
private:
spaceParser space;
xmlpcParser xmlpc;
comspaceParser comspace;
elemParser elem;
};
//! just a convenient wraper around the XMLParser
class ResponseParser {
public:
bool operator()(const string& content, responseParserHook *hook);
private:
XMLParser xml;
};
}
#else /* HSADMIN_XMLPARSER */
namespace xmlParser {
class responseParserHook;
class parser;
template <class first, class second> class orRule;
class spaceParser;
class commentParser;
class nameParser;
class attributeValueParser;
class attributeParser;
class emptyelemParser;
class startelemParser;
class endelemParser;
class textParser;
class cdataParser;
class elemParser;
class xmlpcParser;
class XMLParser;
class ResponseParser;
}
#endif /* HSADMIN_XMLPARSER */