From: Maxim Mamontov Date: Sat, 17 Sep 2016 13:03:04 +0000 (+0300) Subject: Merge branch 'stg-2.409' X-Git-Url: https://git.stg.codes/stg.git/commitdiff_plain/d1c864e3feaf4295d366e2ef497495738ce15337?hp=4ad0ededeb39c31c200011957b63dc485a04027e Merge branch 'stg-2.409' --- diff --git a/functest/build.sh b/functest/build.sh new file mode 100755 index 00000000..a84e9e0d --- /dev/null +++ b/functest/build.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +BASEPATH=$1 + +if [ "$BASEPATH" == "" ] +then + printf "Usage: $0 \n" + exit -1 +fi + +if [ ! -d "$BASEPATH" ] +then + printf "Path '$BASEPATH' does not exist or not a directory.\n" + exit -1 +fi + +cd "$BASEPATH/stg/projects/stargazer" +./build debug +make clean +make + +cd "$BASEPATH/stg/projects/sgconf" +./build debug +make clean +make diff --git a/functest/clone.sh b/functest/clone.sh new file mode 100755 index 00000000..e185a464 --- /dev/null +++ b/functest/clone.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +BASEPATH=$1 +ARCHIVE=$2 +CURPATH=`pwd` +GIT=/usr/bin/git +TAR=/bin/tar +RM=/bin/rm + +if [ "$BASEPATH" == "" ] +then + printf "Usage: $0 \n" + exit -1 +fi + +if [ ! -d "$BASEPATH" ] +then + printf "Path '$BASEPATH' does not exist or not a directory.\n" + exit -1 +fi + +#$GIT clone "https://gitorious.org/stg/stg.git" "$BASEPATH/stg" +$GIT clone "../" "$BASEPATH/stg" + +if [ "$ARCHIVE" != "" ] +then + $RM -rf "$BASEPATH/stg/.git" + + $TAR -C "$BASEPATH" -jcf "$BASEPATH/stg.tar" "stg" +fi diff --git a/functest/do.sh b/functest/do.sh new file mode 100755 index 00000000..652dbcec --- /dev/null +++ b/functest/do.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +MKTEMP=/usr/bin/mktemp +RM=/bin/rm + +printf "Creating temporary dir... " +DIR=`$MKTEMP -d 2> /dev/null || $MKTEMP -d -t stg` + +if [ "$DIR" == "" ] +then + printf "Failed.\nTemporary dir is empty.\n" + exit -1 +fi + +if [ ! -d "$DIR" ] +then + printf "Failed.\nTemporary dir '$DIR' does not exist or not a directory.\n" + exit -1 +fi + +LOGFILE=`date "+%Y-%m-%d-%H%M%S.log"` + +printf "Ok. Working dir: $DIR\nCloning... " +./clone.sh "$DIR" >> "$LOGFILE" 2>&1 +if [ "$?" != "0" ] +then + printf "Failed.\n" + exit -1 +else + printf "Ok.\nBuilding... " +fi +./build.sh "$DIR" >> "$LOGFILE" 2>&1 +if [ "$?" != "0" ] +then + printf "Failed.\n" + exit -1 +else + printf "Ok.\n" +fi + +./test.sh "$DIR" # >> "$LOGFILE" 2>&1 + +printf "Cleaning up... " + +$RM -rf $DIR +if [ "$?" != "0" ] +then + printf "Failed.\n" + exit -1 +else + printf "Ok.\n" +fi diff --git a/functest/functions b/functest/functions new file mode 100644 index 00000000..a90b9dcd --- /dev/null +++ b/functest/functions @@ -0,0 +1,47 @@ +trim() +{ + printf "$1" | sed -e 's/^ *//' -e 's/ *$//' +} + +getField() +{ + NAME="$1" + DATA="$2" + + printf "$DATA" | grep "$NAME" > /dev/null 2> /dev/null + if [ "$?" != "0" ] + then + return 1 + fi + + trim `printf "$DATA" | cut -d: -f2` +} + +getFields() +{ + NAME=$1 + DATA=$2 + + IFS=`printf '\n+'` + for LINE in $DATA + do + VALUE=`getField $NAME $LINE` && printf "%s\n" "$VALUE" + done +} + +count() +{ + if [ "$1" == "" ] + then + printf "0" + else + RES=`printf "$1\n" | wc -l` + RES=`trim "$RES"` + printf "$RES" + fi +} + +subst() +{ + sed -i "s|$1|$2|g" "$3" 2> /dev/null || sed -i "" "s|$1|$2|g" "$3" +} diff --git a/functest/stuff/OnChange b/functest/stuff/OnChange new file mode 100755 index 00000000..8feb93ca --- /dev/null +++ b/functest/stuff/OnChange @@ -0,0 +1,6 @@ +#!/bin/sh + +login=$1 +param=$2 +oldValue=$3 +newValue=$4 diff --git a/functest/stuff/OnConnect b/functest/stuff/OnConnect new file mode 100755 index 00000000..d0f5a496 --- /dev/null +++ b/functest/stuff/OnConnect @@ -0,0 +1,18 @@ +#! /bin/sh + +# Login +LOGIN=$1 + +# User IP +IP=$2 + +# Cash +CASH=$3 + +# User ID +ID=$4 + +# Selected dirs to connect +DIRS=$5 + +TARIFFNAME=$6 diff --git a/functest/stuff/OnDisconnect b/functest/stuff/OnDisconnect new file mode 100755 index 00000000..7c80e5b2 --- /dev/null +++ b/functest/stuff/OnDisconnect @@ -0,0 +1,18 @@ +#! /bin/sh + +# Login +LOGIN=$1 + +# User IP +IP=$2 + +# Cash +CASH=$3 + +# User ID +ID=$4 + +# Selected dirs to disconnect +DIRS=$5 + +TARIFFNAME=$6 diff --git a/functest/stuff/db-stub/admins/admin.adm b/functest/stuff/db-stub/admins/admin.adm new file mode 100644 index 00000000..bfc6cde1 --- /dev/null +++ b/functest/stuff/db-stub/admins/admin.adm @@ -0,0 +1,8 @@ +password=geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa +ChgConf=1 +ChgPassword=1 +ChgStat=1 +ChgCash=1 +UsrAddDel=1 +ChgTariff=1 +ChgAdmin=1 diff --git a/functest/stuff/db-stub/tariffs/tariff.tf b/functest/stuff/db-stub/tariffs/tariff.tf new file mode 100644 index 00000000..2a6971f5 --- /dev/null +++ b/functest/stuff/db-stub/tariffs/tariff.tf @@ -0,0 +1,85 @@ +Fee=1.000000 +Free=2.000000 +NoDiscount0=0 +NoDiscount1=0 +NoDiscount2=0 +NoDiscount3=0 +NoDiscount4=0 +NoDiscount5=0 +NoDiscount6=0 +NoDiscount7=0 +NoDiscount8=0 +NoDiscount9=0 +PassiveCost=3.000000 +Period=day +PriceDayA0=5.000000 +PriceDayA1=0.000000 +PriceDayA2=0.000000 +PriceDayA3=0.000000 +PriceDayA4=0.000000 +PriceDayA5=0.000000 +PriceDayA6=0.000000 +PriceDayA7=0.000000 +PriceDayA8=0.000000 +PriceDayA9=0.000000 +PriceDayB0=3.500000 +PriceDayB1=0.000000 +PriceDayB2=0.000000 +PriceDayB3=0.000000 +PriceDayB4=0.000000 +PriceDayB5=0.000000 +PriceDayB6=0.000000 +PriceDayB7=0.000000 +PriceDayB8=0.000000 +PriceDayB9=0.000000 +PriceNightA0=4.000000 +PriceNightA1=0.000000 +PriceNightA2=0.000000 +PriceNightA3=0.000000 +PriceNightA4=0.000000 +PriceNightA5=0.000000 +PriceNightA6=0.000000 +PriceNightA7=0.000000 +PriceNightA8=0.000000 +PriceNightA9=0.000000 +PriceNightB0=2.500000 +PriceNightB1=0.000000 +PriceNightB2=0.000000 +PriceNightB3=0.000000 +PriceNightB4=0.000000 +PriceNightB5=0.000000 +PriceNightB6=0.000000 +PriceNightB7=0.000000 +PriceNightB8=0.000000 +PriceNightB9=0.000000 +SinglePrice0=0 +SinglePrice1=0 +SinglePrice2=0 +SinglePrice3=0 +SinglePrice4=0 +SinglePrice5=0 +SinglePrice6=0 +SinglePrice7=0 +SinglePrice8=0 +SinglePrice9=0 +Threshold0=1000 +Threshold1=0 +Threshold2=0 +Threshold3=0 +Threshold4=0 +Threshold5=0 +Threshold6=0 +Threshold7=0 +Threshold8=0 +Threshold9=0 +Time0=6:0-18:0 +Time1=0:0-0:0 +Time2=0:0-0:0 +Time3=0:0-0:0 +Time4=0:0-0:0 +Time5=0:0-0:0 +Time6=0:0-0:0 +Time7=0:0-0:0 +Time8=0:0-0:0 +Time9=0:0-0:0 +TraffType=up+down diff --git a/functest/stuff/db-stub/users/test/conf b/functest/stuff/db-stub/users/test/conf new file mode 100644 index 00000000..f19c6537 --- /dev/null +++ b/functest/stuff/db-stub/users/test/conf @@ -0,0 +1,27 @@ +Address= +AlwaysOnline=1 +CreationTime=1123487395 +Credit=0.000000 +CreditExpire=0 +DisabledDetailStat=0 +Down=0 +Email= +Group= +IP=192.168.0.5 +Note= +Passive=0 +Password=123456 +Phone= +RealName= +Tariff=tariff +TariffChange= +Userdata0= +Userdata1= +Userdata2= +Userdata3= +Userdata4= +Userdata5= +Userdata6= +Userdata7= +Userdata8= +Userdata9= diff --git a/functest/stuff/db-stub/users/test/stat b/functest/stuff/db-stub/users/test/stat new file mode 100644 index 00000000..d69d07c6 --- /dev/null +++ b/functest/stuff/db-stub/users/test/stat @@ -0,0 +1,26 @@ +Cash=100 +D0=0 +D1=0 +D2=0 +D3=0 +D4=0 +D5=0 +D6=0 +D7=0 +D8=0 +D9=0 +FreeMb=0 +LastActivityTime=0 +LastCashAdd=0 +LastCashAddTime=0 +PassiveTime=0 +U0=0 +U1=0 +U2=0 +U3=0 +U4=0 +U5=0 +U6=0 +U7=0 +U8=0 +U9=0 diff --git a/functest/stuff/rules b/functest/stuff/rules new file mode 100644 index 00000000..ad9faa18 --- /dev/null +++ b/functest/stuff/rules @@ -0,0 +1,4 @@ +ALL 192.168.0.0/16 DIR1 +ALL 172.16.0.0/12 DIR1 +ALL 10.0.0.0/8 DIR1 +ALL 0.0.0.0/0 DIR0 diff --git a/functest/stuff/stargazer-files.conf b/functest/stuff/stargazer-files.conf new file mode 100644 index 00000000..c4e0bd3e --- /dev/null +++ b/functest/stuff/stargazer-files.conf @@ -0,0 +1,57 @@ +PidFile = -STG-PATH-/stargazer.pid +LogFile = -STG-PATH-/stargazer.log +Rules = -STG-PATH-/rules +ModulesPath = -STG-PATH-/modules +DetailStatWritePeriod=1/6 +StatWritePeriod = 10 +DayFee = 1 +DayFeeIsLastDay = yes +DayResetTraff = 1 +SpreadFee = no +FreeMbAllowInet = no +WriteFreeMbTraffCost = no +FullFee=no +ShowFeeInCash=yes +ExecutersNum = 1 +ExecMsgKey = 5555 +# MonitorDir=/var/stargazer/monitor +ScriptParams = tariffName + + + DirName0 = dir + DirName1 = dir2 + DirName2 = dir3 + DirName3 = + DirName4 = + DirName5 = dir5 + DirName6 = + DirName7 = + DirName8 = + DirName9 = + + + + WorkDir = -STG-PATH-/db + + ConfOwner = root + ConfGroup = -STG-GROUP- + ConfMode = 600 + + StatOwner = root + StatGroup = -STG-GROUP- + StatMode = 640 + + UserLogOwner = root + UserLogGroup = -STG-GROUP- + UserLogMode = 640 + + + + + + + + Port = 5555 + BindAddress = localhost + + diff --git a/functest/test.sh b/functest/test.sh new file mode 100755 index 00000000..a463568f --- /dev/null +++ b/functest/test.sh @@ -0,0 +1,101 @@ +#!/bin/sh + +BASEPATH=$1 + +source `dirname $0`/functions + +if [ "$BASEPATH" == "" ] +then + printf "Usage: $0 \n" + exit -1 +fi + +if [ ! -d "$BASEPATH" ] +then + printf "Path '$BASEPATH' does not exist or not a directory.\n" + exit -1 +fi + +STGPATH="$BASEPATH/stg/projects/stargazer" + +cp "stuff/stargazer-files.conf" "$STGPATH/stargazer.conf" +cp "stuff/rules" "$STGPATH/" +cp "stuff/OnConnect" "$STGPATH/" +cp "stuff/OnDisconnect" "$STGPATH/" +cp "stuff/OnChange" "$STGPATH/" +cp -R "stuff/db-stub" "$STGPATH/db" + +GROUP=root +groups | grep root > /dev/null 2> /dev/null +if [ "$?" != "0" ] +then + groups | grep wheel > /dev/null 2> /dev/null + if [ "$?" != "0" ] + then + printf "Can't find neither 'root' nor 'wheel' group.\n" + exit -1 + fi + GROUP=wheel +fi + +subst "-STG-PATH-" "$STGPATH" "$STGPATH/stargazer.conf" +subst "-STG-GROUP-" "$GROUP" "$STGPATH/stargazer.conf" + +CURPATH=`pwd` +LOGFILE="$CURPATH/"`date "+%Y-%m-%d-%H%M%S.console.log"` + +cd "$STGPATH" + +printf "Starting Stargazer... " + +"$STGPATH/stargazer" "$STGPATH" >> "$LOGFILE" 2>&1 & + +COUNT="" +while true +do + grep "Stg started successfully" "$STGPATH/stargazer.log" > /dev/null 2> /dev/null + if [ "$?" == "0" ] + then + break + fi + COUNT="$COUNT." + if [ "$COUNT" == "....." ] + then + printf "Failed to start stg in 5 sec.\n" + exit -1 + fi + sleep 1 +done + +PID=`cat "$STGPATH/stargazer.pid"` +printf "Started with pid $PID\n" + +printf "\nTesting server info:\n" +"$CURPATH/test_server_info.sh" "$BASEPATH" +printf "\nTesting admins:\n" +"$CURPATH/test_admins.sh" "$BASEPATH" +printf "\nTesting services:\n" +"$CURPATH/test_services.sh" "$BASEPATH" +printf "\n" + +printf "Stopping... " +kill $PID + +COUNT="" +while true +do + grep "Stg stopped successfully" "$STGPATH/stargazer.log" > /dev/null 2> /dev/null + if [ "$?" == "0" ] + then + break + fi + COUNT="$COUNT." + if [ "$COUNT" == "....." ] + then + printf "Failed to stop stg in 5 sec.\n" + exit -1 + fi + sleep 1 +done + +printf "Stopped.\n" diff --git a/functest/test_admins.sh b/functest/test_admins.sh new file mode 100755 index 00000000..dae254ba --- /dev/null +++ b/functest/test_admins.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +source `dirname $0`/functions + +BASEPATH=$1 + +SGCONFPATH="$BASEPATH/stg/projects/sgconf" + +printf "Check initial admin list... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --get-admins` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to get admins list. Result:\n$RES\n" + exit 0 +fi + +LOGINS=`getFields "login" "$RES"` + +NUM=`count "$LOGINS"` + +if [ "$NUM" != "1" ] +then + printf "Failed.\n" + printf "Admin list should have exactly one entry.\n" + printf "Logins:\n$LOGINS\n" + printf -- "--------\n$NUM\n\n" + exit 0 +fi + +printf "Ok.\nCheck updating admin permissions... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --chg-admin admin --priv 111111111` + +if [ "$?" != "0" ] +then + printf "Error\n" + printf "Failed to update admin's priviledges Result:\n$RES\n" + exit 0 +fi + +printf "Ok.\n" diff --git a/functest/test_server_info.sh b/functest/test_server_info.sh new file mode 100755 index 00000000..caf01bca --- /dev/null +++ b/functest/test_server_info.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +source `dirname $0`/functions + +BASEPATH=$1 + +SGCONFPATH="$BASEPATH/stg/projects/sgconf" + +printf "Check server info... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --server-info` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to get admins list. Result:\n$RES\n" + exit 0 +fi + +printf "Ok\nResult:\n%s" "$RES" + +#LOGINS=`getFields "login" "$RES"` +# +#NUM=`count "$LOGINS"` +# +#if [ "$NUM" != "1" ] +#then +# printf "Failed.\n" +# printf "Admin list should have exactly one entry.\n" +# printf "Logins:\n$LOGINS\n" +# printf -- "--------\n$NUM\n\n" +# exit 0 +#fi diff --git a/functest/test_services.sh b/functest/test_services.sh new file mode 100755 index 00000000..0b8a2a8c --- /dev/null +++ b/functest/test_services.sh @@ -0,0 +1,103 @@ +#!/bin/sh + +source `dirname $0`/functions + +BASEPATH=$1 + +SGCONFPATH="$BASEPATH/stg/projects/sgconf" + +printf "Check initial service list... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --get-services` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to get services list. Result:\n$RES\n" + exit 0 +fi + +NAMES=`getFields "name" "$RES"` + +NUM=`count "$NAMES"` + +if [ "$NUM" != "0" ] +then + printf "Failed.\n" + printf "Services list should be empty.\n" + printf "Names:\n$NAMES\n" + printf -- "--------\n$NUM\n\n" + exit 0 +fi + +printf "Ok.\nCheck adding services... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --add-service test` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to add new service. Result:\n$RES\n" + exit 0 +fi + +printf "Ok.\nCheck new service list... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --get-services` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to get services list. Result:\n$RES\n" + exit 0 +fi + +NAMES=`getFields "name" "$RES"` + +NUM=`count "$NAMES"` + +if [ "$NUM" != "1" ] +then + printf "Failed.\n" + printf "Services list should have exactly one entry.\n" + printf "Names:\n$NAMES\n" + printf -- "--------\n$NUM\n\n" + exit 0 +fi + +printf "Ok.\nCheck deletion exisiting service... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --del-service test` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to delete a service. Result:\n$RES\n" + exit 0 +fi + +printf "Ok.\nCheck new service list... " + +RES=`"$SGCONFPATH/sgconf" -s localhost -p 5555 -u admin -w 123456 --get-services` + +if [ "$?" != "0" ] +then + printf "Error.\n" + printf "Failed to get services list. Result:\n$RES\n" + exit 0 +fi + +NAMES=`getFields "name" "$RES"` + +NUM=`count "$NAMES"` + +if [ "$NUM" != "0" ] +then + printf "Failed.\n" + printf "Services list should be empty.\n" + printf "Names:\n$NAMES\n" + printf -- "--------\n$NUM\n\n" + exit 0 +fi + +printf "Ok.\n" diff --git a/include/stg/admin_conf.h b/include/stg/admin_conf.h index f88ab0c8..6e073d6f 100644 --- a/include/stg/admin_conf.h +++ b/include/stg/admin_conf.h @@ -79,8 +79,7 @@ struct ADMIN_CONF //----------------------------------------------------------------------------- struct ADMIN_CONF_RES { - ADMIN_CONF_RES() - {} + ADMIN_CONF_RES() {} ADMIN_CONF_RES(const ADMIN_CONF_RES & rhs) : priv(rhs.priv), login(rhs.login), diff --git a/include/stg/array.h b/include/stg/array.h new file mode 100644 index 00000000..8550f167 --- /dev/null +++ b/include/stg/array.h @@ -0,0 +1,44 @@ +#ifndef __STG_ARRAY_H__ +#define __STG_ARRAY_H__ + +#include // size_t + +namespace STG +{ + +template +class ARRAY +{ + public: + typedef T value_type; + typedef size_t size_type; + typedef T * iterator; + typedef const T * const_iterator; + + ARRAY() + { + for (size_type i = 0; i < S; ++i) + m_data[i] = value_type(); + } + + const value_type & operator[](size_type i) const { return m_data[i]; } + value_type & operator[](size_type i) { return m_data[i]; } + size_type size() const { return S; } + + iterator begin() { return &m_data[0]; } + const_iterator begin() const { return &m_data[0]; } + iterator end() { return &m_data[S + 1]; } + const_iterator end() const { return &m_data[S + 1]; } + + const value_type & front() const { return m_data[0]; } + value_type & front() { return m_data[0]; } + const value_type & back() const { return m_data[S]; } + value_type & back() { return m_data[S]; } + + private: + value_type m_data[S]; +}; + +} // namespace STG + +#endif diff --git a/include/stg/corp_conf.h b/include/stg/corp_conf.h index d6cc2ebb..9bbc03d3 100644 --- a/include/stg/corp_conf.h +++ b/include/stg/corp_conf.h @@ -1,6 +1,28 @@ +/* + * 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 + */ + +/* + * Author : Maxim Mamontov + */ + #ifndef CORP_CONF_H #define CORP_CONF_H +#include "resetable.h" + #include struct CORP_CONF @@ -13,6 +35,31 @@ std::string name; double cash; }; +struct CORP_CONF_RES +{ +CORP_CONF_RES() + : name(), cash() +{} + +CORP_CONF_RES & operator=(const CORP_CONF & conf) +{ +name = conf.name; +cash = conf.cash; +return *this; +} + +CORP_CONF GetData() const +{ +CORP_CONF cc; +cc.name = name.data(); +cc.cash = cash.data(); +return cc; +} + +RESETABLE name; +RESETABLE cash; +}; + inline bool operator==(const CORP_CONF & a, const CORP_CONF & b) { diff --git a/include/stg/corporations.h b/include/stg/corporations.h index 2d07c6c6..e167301b 100644 --- a/include/stg/corporations.h +++ b/include/stg/corporations.h @@ -21,10 +21,10 @@ #ifndef CORPORATIONS_H #define CORPORATIONS_H -#include - #include "corp_conf.h" +#include + class ADMIN; class CORPORATIONS { diff --git a/include/stg/user_conf.h b/include/stg/user_conf.h index 5987c4d8..a16b3929 100644 --- a/include/stg/user_conf.h +++ b/include/stg/user_conf.h @@ -39,7 +39,7 @@ struct USER_CONF std::string note; std::string realName; std::string corp; - std::vector service; + std::vector services; std::string group; double credit; std::string nextTariff; @@ -67,13 +67,12 @@ struct USER_CONF_RES email = uc.email; note = uc.note; realName = uc.realName; + corp = uc.corp; group = uc.group; credit = uc.credit; nextTariff = uc.nextTariff; - for (int i = 0; i < USERDATA_NUM; i++) - { - userdata[i] = uc.userdata[i]; - } + for (size_t i = 0; i < USERDATA_NUM; i++) userdata[i] = uc.userdata[i]; + services = uc.services; creditExpire = uc.creditExpire; ips = uc.ips; return *this; @@ -92,13 +91,15 @@ struct USER_CONF_RES uc.email = email.data(); uc.note = note.data(); uc.realName = realName.data(); + uc.corp = corp.data(); uc.group = group.data(); uc.credit = credit.data(); uc.nextTariff = nextTariff.data(); - for (int i = 0; i < USERDATA_NUM; i++) + for (size_t i = 0; i < USERDATA_NUM; i++) { uc.userdata[i] = userdata[i].data(); } + uc.services = services.data(); uc.creditExpire = creditExpire.data(); uc.ips = ips.data(); return uc; @@ -116,10 +117,12 @@ struct USER_CONF_RES RESETABLE email; RESETABLE note; RESETABLE realName; + RESETABLE corp; RESETABLE group; RESETABLE credit; RESETABLE nextTariff; std::vector > userdata; + RESETABLE > services; RESETABLE creditExpire; RESETABLE ips; }; diff --git a/include/stg/user_stat.h b/include/stg/user_stat.h index 4c06155d..ff020dc7 100644 --- a/include/stg/user_stat.h +++ b/include/stg/user_stat.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include "os_int.h" #include "resetable.h" @@ -140,6 +142,8 @@ struct USER_STAT //----------------------------------------------------------------------------- typedef std::map TRAFF_STAT; //----------------------------------------------------------------------------- +typedef std::pair CASH_INFO; +//----------------------------------------------------------------------------- struct USER_STAT_RES { USER_STAT_RES() @@ -186,6 +190,8 @@ struct USER_STAT_RES } RESETABLE cash; + RESETABLE cashAdd; + RESETABLE cashSet; RESETABLE freeMb; RESETABLE lastCashAdd; RESETABLE lastCashAddTime; diff --git a/include/stg/user_traff.h b/include/stg/user_traff.h index eec46276..8ef8e260 100644 --- a/include/stg/user_traff.h +++ b/include/stg/user_traff.h @@ -80,6 +80,7 @@ return o; class DIR_TRAFF_RES { public: + typedef RESETABLE value_type; typedef RESETABLE ValueType; typedef std::vector ContainerType; typedef ContainerType::size_type IndexType; @@ -93,6 +94,7 @@ public: } const ValueType & operator[](IndexType idx) const { return traff[idx]; } ValueType & operator[](IndexType idx) { return traff[idx]; } + IndexType size() const { return traff.size(); } DIR_TRAFF GetData() const { DIR_TRAFF res; diff --git a/include/stg/version.h b/include/stg/version.h index 20538a7f..fb41a227 100644 --- a/include/stg/version.h +++ b/include/stg/version.h @@ -22,6 +22,6 @@ #define __VERSION_H__ // Stargazer version -#define SERVER_VERSION "2.409" +#define SERVER_VERSION "2.5" #endif diff --git a/projects/sgconf/Makefile b/projects/sgconf/Makefile index 795c2522..3a64cb61 100644 --- a/projects/sgconf/Makefile +++ b/projects/sgconf/Makefile @@ -7,21 +7,30 @@ include ../../Makefile.conf PROG = sgconf SRCS = ./main.cpp \ - ./common_sg.cpp - -STGLIBS = conffiles \ - srvconf \ + ./options.cpp \ + ./api_action.cpp \ + ./actions.cpp \ + ./admins.cpp \ + ./tariffs.cpp \ + ./users.cpp \ + ./services.cpp \ + ./corps.cpp \ + ./info.cpp \ + ./xml.cpp + +STGLIBS = srvconf \ crypto \ common STGLIBS_INCS = $(addprefix -I ../../stglibs/,$(addsuffix .lib/include,$(STGLIBS))) STGLIBS_LIBS = $(addprefix -L ../../stglibs/,$(addsuffix .lib,$(STGLIBS))) -LIBS += $(addprefix -lstg,$(STGLIBS)) -lexpat $(LIB_THREAD) $(LIBICONV) +LIBS += $(addprefix -lstg,$(STGLIBS)) -lexpat $(LIB_THREAD) ifeq ($(OS),linux) else -LIBS += -lc +LIBS += -lc \ + -liconv endif SEARCH_DIRS = -I ../../include @@ -56,11 +65,7 @@ $(PROG): $(OBJS) $(CXX) $^ $(LDFLAGS) $(LIBS) -o $(PROG) clean: - rm -f deps $(PROG) *.o tags *.*~ .OS - rm -f .OS - rm -f .store - rm -f .db.sql - rm -f core* + rm -f deps $(PROG) *.o $(MAKE) -C $(DIR_LIBSRC) clean distclean: clean @@ -92,7 +97,7 @@ endif endif endif -deps: $(SRCS) ../../Makefile.conf +deps: $(SRCS) ../../Makefile.conf $(MAKE) -C $(DIR_LIBSRC) @>deps ;\ for file in $(SRCS); do\ diff --git a/projects/sgconf/README.txt b/projects/sgconf/README.txt index cbdf9aca..bb2db5b9 100644 --- a/projects/sgconf/README.txt +++ b/projects/sgconf/README.txt @@ -1,3 +1,4 @@ Compiling: > ./build + diff --git a/projects/sgconf/TODO b/projects/sgconf/TODO new file mode 100644 index 00000000..19b51f5e --- /dev/null +++ b/projects/sgconf/TODO @@ -0,0 +1,2 @@ +1. No default value for server. +2. No default value for port. diff --git a/projects/sgconf/action.h b/projects/sgconf/action.h new file mode 100644 index 00000000..940ea7f6 --- /dev/null +++ b/projects/sgconf/action.h @@ -0,0 +1,57 @@ +/* + * 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 + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_SGCONF_ACTION_H__ +#define __STG_SGCONF_ACTION_H__ + +#include +#include +#include + +namespace SGCONF +{ + +class OPTION_BLOCK; +struct PARSER_STATE; +struct CONFIG; + +class ACTION +{ + public: + virtual ~ACTION() {} + + virtual ACTION * Clone() const = 0; + virtual std::string ParamDescription() const = 0; + virtual std::string DefaultDescription() const = 0; + virtual OPTION_BLOCK & Suboptions() = 0; + virtual PARSER_STATE Parse(int argc, char ** argv, void * data = NULL) = 0; + virtual void ParseValue(const std::string &) {} + + class ERROR : public std::runtime_error + { + public: + ERROR(const std::string & message) + : std::runtime_error(message.c_str()) {} + }; +}; + +} // namespace SGCONF + +#endif diff --git a/projects/sgconf/actions.cpp b/projects/sgconf/actions.cpp new file mode 100644 index 00000000..afa51621 --- /dev/null +++ b/projects/sgconf/actions.cpp @@ -0,0 +1,19 @@ +/* + * 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 + */ + +/* + * Author : Maxim Mamontov + */ diff --git a/projects/sgconf/actions.h b/projects/sgconf/actions.h new file mode 100644 index 00000000..08dc177e --- /dev/null +++ b/projects/sgconf/actions.h @@ -0,0 +1,246 @@ +/* + * 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 + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_SGCONF_ACTIONS_H__ +#define __STG_SGCONF_ACTIONS_H__ + +#include "action.h" +#include "options.h" +#include "parser_state.h" + +#include "stg/common.h" +#include "stg/resetable.h" + +#include + +#include + +namespace SGCONF +{ + +typedef void (* FUNC0)(); + +template +class FUNC0_ACTION : public ACTION +{ + public: + FUNC0_ACTION(const F & func) : m_func(func) {} + + virtual ACTION * Clone() const { return new FUNC0_ACTION(*this); } + + virtual std::string ParamDescription() const { return ""; } + virtual std::string DefaultDescription() const { return ""; } + virtual OPTION_BLOCK & Suboptions() { return m_suboptions; } + virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/) + { + m_func(); + return PARSER_STATE(true, argc, argv); + } + + private: + F m_func; + OPTION_BLOCK m_suboptions; +}; + +template +inline +FUNC0_ACTION * MakeFunc0Action(F func) +{ +return new FUNC0_ACTION(func); +} + +template +class PARAM_ACTION : public ACTION +{ + public: + PARAM_ACTION(RESETABLE & param, + const T & defaultValue, + const std::string & paramDescription) + : m_param(param), + m_defaltValue(defaultValue), + m_description(paramDescription), + m_hasDefault(true) + {} + PARAM_ACTION(RESETABLE & param) + : m_param(param), + m_hasDefault(false) + {} + PARAM_ACTION(RESETABLE & param, + const std::string & paramDescription) + : m_param(param), + m_description(paramDescription), + m_hasDefault(false) + {} + + virtual ACTION * Clone() const { return new PARAM_ACTION(*this); } + + virtual std::string ParamDescription() const { return m_description; } + virtual std::string DefaultDescription() const; + virtual OPTION_BLOCK & Suboptions() { return m_suboptions; } + virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/); + virtual void ParseValue(const std::string & value); + + private: + RESETABLE & m_param; + T m_defaltValue; + std::string m_description; + bool m_hasDefault; + OPTION_BLOCK m_suboptions; +}; + +template +inline +std::string PARAM_ACTION::DefaultDescription() const +{ +return m_hasDefault ? " (default: '" + x2str(m_defaltValue) + "')" + : ""; +} + +template <> +inline +std::string PARAM_ACTION::DefaultDescription() const +{ +return m_hasDefault ? " (default: '" + m_defaltValue + "')" + : ""; +} + +template +inline +PARSER_STATE PARAM_ACTION::Parse(int argc, char ** argv, void * /*data*/) +{ +if (argc == 0 || + argv == NULL || + *argv == NULL) + throw ERROR("Missing argument."); +T value; +if (str2x(*argv, value)) + throw ERROR(std::string("Bad argument: '") + *argv + "'"); +m_param = value; +return PARSER_STATE(false, --argc, ++argv); +} + +template <> +inline +PARSER_STATE PARAM_ACTION::Parse(int argc, char ** argv, void * /*data*/) +{ +m_param = true; +return PARSER_STATE(false, argc, argv); +} + +template +inline +void PARAM_ACTION::ParseValue(const std::string & stringValue) +{ +if (stringValue.empty()) + throw ERROR("Missing value."); +T value; +if (str2x(stringValue, value)) + throw ERROR(std::string("Bad value: '") + stringValue + "'"); +m_param = value; +} + +template <> +inline +void PARAM_ACTION::ParseValue(const std::string & stringValue) +{ +m_param = stringValue; +} + +template <> +inline +PARSER_STATE PARAM_ACTION::Parse(int argc, char ** argv, void * /*data*/) +{ +if (argc == 0 || + argv == NULL || + *argv == NULL) + throw ERROR("Missing argument."); +m_param = *argv; +return PARSER_STATE(false, --argc, ++argv); +} + +template +inline +PARAM_ACTION * MakeParamAction(RESETABLE & param, + const T & defaultValue, + const std::string & paramDescription) +{ +return new PARAM_ACTION(param, defaultValue, paramDescription); +} + +template +inline +PARAM_ACTION * MakeParamAction(RESETABLE & param) +{ +return new PARAM_ACTION(param); +} + +template +inline +PARAM_ACTION * MakeParamAction(RESETABLE & param, + const std::string & paramDescription) +{ +return new PARAM_ACTION(param, paramDescription); +} + +class KV_ACTION : public ACTION +{ + public: + KV_ACTION(const std::string & name, + const std::string & paramDescription) + : m_name(name), + m_description(paramDescription) + {} + + virtual ACTION * Clone() const { return new KV_ACTION(*this); } + + virtual std::string ParamDescription() const { return m_description; } + virtual std::string DefaultDescription() const { return ""; } + virtual OPTION_BLOCK & Suboptions() { return m_suboptions; } + virtual PARSER_STATE Parse(int argc, char ** argv, void * data); + + private: + std::string m_name; + std::string m_description; + OPTION_BLOCK m_suboptions; +}; + +inline +PARSER_STATE KV_ACTION::Parse(int argc, char ** argv, void * data) +{ +if (argc == 0 || + argv == NULL || + *argv == NULL) + throw ERROR("Missing argument."); +assert(data != NULL && "Expecting container pointer."); +std::map & kvs = *static_cast*>(data); +kvs[m_name] = *argv; +return PARSER_STATE(false, --argc, ++argv); +} + +inline +KV_ACTION * MakeKVAction(const std::string & name, + const std::string & paramDescription) +{ +return new KV_ACTION(name, paramDescription); +} + +} // namespace SGCONF + +#endif diff --git a/projects/sgconf/admins.cpp b/projects/sgconf/admins.cpp new file mode 100644 index 00000000..c16e6e2b --- /dev/null +++ b/projects/sgconf/admins.cpp @@ -0,0 +1,204 @@ +#include "admins.h" + +#include "api_action.h" +#include "options.h" +#include "config.h" +#include "utils.h" + +#include "stg/servconf.h" +#include "stg/servconf_types.h" +#include "stg/os_int.h" + +#include +#include +#include +#include + +namespace +{ + +std::string Indent(size_t level, bool dash = false) +{ +if (level == 0) + return ""; +return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' '); +} + +std::string PrivToString(const PRIV& priv) +{ +return std::string("") + + (priv.corpChg ? "1" : "0") + + (priv.serviceChg ? "1" : "0") + + (priv.tariffChg ? "1" : "0") + + (priv.adminChg ? "1" : "0") + + (priv.userAddDel ? "1" : "0") + + (priv.userPasswd ? "1" : "0") + + (priv.userCash ? "1" : "0") + + (priv.userConf ? "1" : "0") + + (priv.userStat ? "1" : "0"); +} + +void PrintAdmin(const STG::GET_ADMIN::INFO & info, size_t level = 0) +{ +std::cout << Indent(level, true) << "login: " << info.login << "\n" + << Indent(level) << "priviledges: " << PrivToString(info.priv) << "\n"; +} + +std::vector GetAdminParams() +{ +std::vector params; +params.push_back(SGCONF::API_ACTION::PARAM("password", "", "password")); +params.push_back(SGCONF::API_ACTION::PARAM("priv", "", "priviledges")); +return params; +} + +void ConvPriv(const std::string & value, RESETABLE & res) +{ +if (value.length() != 9) + throw SGCONF::ACTION::ERROR("Priviledges value should be a 9-digits length binary number."); +PRIV priv; +priv.corpChg = (value[0] == '0' ? 0 : 1); +priv.serviceChg = (value[1] == '0' ? 0 : 1); +priv.tariffChg = (value[2] == '0' ? 0 : 1); +priv.adminChg = (value[3] == '0' ? 0 : 1); +priv.userAddDel = (value[4] == '0' ? 0 : 1); +priv.userPasswd = (value[5] == '0' ? 0 : 1); +priv.userCash = (value[6] == '0' ? 0 : 1); +priv.userConf = (value[7] == '0' ? 0 : 1); +priv.userStat = (value[8] == '0' ? 0 : 1); +res = priv; +} + +void SimpleCallback(bool result, + const std::string & reason, + void * /*data*/) +{ +if (!result) + { + std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl; + return; + } +std::cout << "Success.\n"; +} + +void GetAdminsCallback(bool result, + const std::string & reason, + const std::vector & info, + void * /*data*/) +{ +if (!result) + { + std::cerr << "Failed to get admin list. Reason: '" << reason << "'." << std::endl; + return; + } +std::cout << "Admins:\n"; +for (size_t i = 0; i < info.size(); ++i) + PrintAdmin(info[i], 1); +} + +void GetAdminCallback(bool result, + const std::string & reason, + const std::vector & info, + void * data) +{ +assert(data != NULL && "Expecting pointer to std::string with the admin's login."); +const std::string & login = *static_cast(data); +if (!result) + { + std::cerr << "Failed to get admin. Reason: '" << reason << "'." << std::endl; + return; + } +for (size_t i = 0; i < info.size(); ++i) + if (info[i].login == login) + PrintAdmin(info[i]); +} + + +bool GetAdminsFunction(const SGCONF::CONFIG & config, + const std::string & /*arg*/, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.GetAdmins(GetAdminsCallback, NULL) == STG::st_ok; +} + +bool GetAdminFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +// STG currently doesn't support . +// So get a list of admins and filter it. 'data' param holds a pointer to 'login'. +std::string login(arg); +return proto.GetAdmins(GetAdminCallback, &login) == STG::st_ok; +} + +bool DelAdminFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.DelAdmin(arg, SimpleCallback, NULL) == STG::st_ok; +} + +bool AddAdminFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & options) +{ +ADMIN_CONF_RES conf; +conf.login = arg; +SGCONF::MaybeSet(options, "priv", conf.priv, ConvPriv); +SGCONF::MaybeSet(options, "password", conf.password); +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.AddAdmin(arg, conf, SimpleCallback, NULL) == STG::st_ok; +} + +bool ChgAdminFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & options) +{ +ADMIN_CONF_RES conf; +conf.login = arg; +SGCONF::MaybeSet(options, "priv", conf.priv, ConvPriv); +SGCONF::MaybeSet(options, "password", conf.password); +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.ChgAdmin(conf, SimpleCallback, NULL) == STG::st_ok; +} + +} // namespace anonymous + +void SGCONF::AppendAdminsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks) +{ +std::vector params(GetAdminParams()); +blocks.Add("Admin management options") + .Add("get-admins", SGCONF::MakeAPIAction(commands, GetAdminsFunction), "\tget admin list") + .Add("get-admin", SGCONF::MakeAPIAction(commands, "", GetAdminFunction), "get admin") + .Add("add-admin", SGCONF::MakeAPIAction(commands, "", params, AddAdminFunction), "add admin") + .Add("del-admin", SGCONF::MakeAPIAction(commands, "", DelAdminFunction), "del admin") + .Add("chg-admin", SGCONF::MakeAPIAction(commands, "", params, ChgAdminFunction), "change admin"); +} diff --git a/projects/sgconf/admins.h b/projects/sgconf/admins.h new file mode 100644 index 00000000..6bc47380 --- /dev/null +++ b/projects/sgconf/admins.h @@ -0,0 +1,14 @@ +#ifndef __STG_SGCONF_ADMINS_H__ +#define __STG_SGCONF_ADMINS_H__ + +namespace SGCONF +{ + +class OPTION_BLOCKS; +class COMMANDS; + +void AppendAdminsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks); + +} // namespace SGCONF + +#endif diff --git a/projects/sgconf/api_action.cpp b/projects/sgconf/api_action.cpp new file mode 100644 index 00000000..d5b1e8e6 --- /dev/null +++ b/projects/sgconf/api_action.cpp @@ -0,0 +1,40 @@ +#include "api_action.h" + +#include "actions.h" +#include "parser_state.h" + +SGCONF::PARSER_STATE SGCONF::API_ACTION::Parse(int argc, char ** argv, void * /*data*/) +{ +PARSER_STATE state(false, argc, argv); +if (!m_argument.empty()) + { + if (argc == 0 || + argv == NULL || + *argv == NULL) + throw ERROR("Missing argument."); + m_argument = *argv; + --state.argc; + ++state.argv; + } +state = m_suboptions.Parse(state.argc, state.argv, &m_params); +m_commands.Add(m_funPtr, m_argument, m_params); +return state; +} + +SGCONF::API_ACTION::API_ACTION(COMMANDS & commands, + const std::string & paramDescription, + bool needArgument, + const std::vector & params, + API_FUNCTION funPtr) + : m_commands(commands), + m_description(paramDescription), + m_argument(needArgument ? "1" : ""), // Hack + m_funPtr(funPtr) +{ +std::vector::const_iterator it(params.begin()); +while (it != params.end()) + { + m_suboptions.Add(it->name, MakeKVAction(it->name, it->shortDescr), it->longDescr); + ++it; + } +} diff --git a/projects/sgconf/api_action.h b/projects/sgconf/api_action.h new file mode 100644 index 00000000..f27715ca --- /dev/null +++ b/projects/sgconf/api_action.h @@ -0,0 +1,143 @@ +#ifndef __STG_SGCONF_API_ACTION_H__ +#define __STG_SGCONF_API_ACTION_H__ + +#include "action.h" + +#include "options.h" + +#include +#include +#include + +namespace SGCONF +{ + +typedef bool (* API_FUNCTION) (const CONFIG &, + const std::string &, + const std::map &); + +class COMMAND +{ + public: + COMMAND(API_FUNCTION funPtr, + const std::string & arg, + const std::map & options) + : m_funPtr(funPtr), + m_arg(arg), + m_options(options) + {} + bool Execute(const SGCONF::CONFIG & config) const + { + return m_funPtr(config, m_arg, m_options); + } + + private: + API_FUNCTION m_funPtr; + std::string m_arg; + std::map m_options; +}; + +class COMMANDS +{ + public: + void Add(API_FUNCTION funPtr, + const std::string & arg, + const std::map & options) { m_commands.push_back(COMMAND(funPtr, arg, options)); } + bool Execute(const SGCONF::CONFIG & config) const + { + std::vector::const_iterator it(m_commands.begin()); + bool res = true; + while (it != m_commands.end() && res) + { + res = res && it->Execute(config); + ++it; + } + return res; + } + private: + std::vector m_commands; +}; + +class API_ACTION : public ACTION +{ + public: + struct PARAM + { + PARAM(const std::string & n, + const std::string & s, + const std::string & l) + : name(n), + shortDescr(s), + longDescr(l) + {} + std::string name; + std::string shortDescr; + std::string longDescr; + }; + + API_ACTION(COMMANDS & commands, + const std::string & paramDescription, + bool needArgument, + const std::vector & params, + API_FUNCTION funPtr); + API_ACTION(COMMANDS & commands, + const std::string & paramDescription, + bool needArgument, + API_FUNCTION funPtr) + : m_commands(commands), + m_description(paramDescription), + m_argument(needArgument ? "1" : ""), // Hack + m_funPtr(funPtr) + {} + + virtual ACTION * Clone() const { return new API_ACTION(*this); } + + virtual std::string ParamDescription() const { return m_description; } + virtual std::string DefaultDescription() const { return ""; } + virtual OPTION_BLOCK & Suboptions() { return m_suboptions; } + virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/); + + private: + COMMANDS & m_commands; + std::string m_description; + std::string m_argument; + OPTION_BLOCK m_suboptions; + std::map m_params; + API_FUNCTION m_funPtr; +}; + +inline +ACTION * MakeAPIAction(COMMANDS & commands, + const std::string & paramDescription, + const std::vector & params, + API_FUNCTION funPtr) +{ +return new API_ACTION(commands, paramDescription, true, params, funPtr); +} + +inline +ACTION * MakeAPIAction(COMMANDS & commands, + const std::vector & params, + API_FUNCTION funPtr) +{ +return new API_ACTION(commands, "", false, params, funPtr); +} + +inline +ACTION * MakeAPIAction(COMMANDS & commands, + const std::string & paramDescription, + API_FUNCTION funPtr) +{ +return new API_ACTION(commands, paramDescription, true, funPtr); +} + +inline +ACTION * MakeAPIAction(COMMANDS & commands, + API_FUNCTION funPtr) +{ +return new API_ACTION(commands, "", false, funPtr); +} + +} + +#endif diff --git a/projects/sgconf/common_sg.cpp b/projects/sgconf/common_sg.cpp deleted file mode 100644 index 9c1b7283..00000000 --- a/projects/sgconf/common_sg.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/* - * 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 - */ - -/* - * Author : Boris Mikhailenko - */ - - /* - $Author: faust $ - $Revision: 1.12 $ - $Date: 2009/06/08 10:02:28 $ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stg/common.h" -#include "sg_error_codes.h" -#include "common_sg.h" -#include "version_sg.h" - -using namespace std; - -const int usageConf = 0; -const int usageInfo = 1; - -const int TO_KOI8 = 0; -const int FROM_KOI8 = 1; -//----------------------------------------------------------------------------- -struct GetUserCbData -{ - void * data; - bool * result; -}; -//----------------------------------------------------------------------------- -struct AuthByCbData -{ - void * data; - bool * result; -}; -//--------------------------------------------------------------------------- -struct HelpParams -{ - string setActionName; - string getActionName; - string valueName; - string valueParam; -}; -//--------------------------------------------------------------------------- -void Usage(int usageType) -{ -printf("Sgconf version: %s\n\n", VERSION_SG); - -char action[4]; -if (usageType == usageConf) - strcpy(action, "set"); -else - strcpy(action, "get"); - -printf("To add or to set cash use:\n"); -printf("sgconf set -s -p -a -w -u -c \n"); -printf("sgconf set -s -p -a -w -u -v \n"); -printf("To get cash use:\n"); -printf("sgconf get -s -p -a -w -u -c\n\n"); - -HelpParams hp[] = -{ - {"set tariff", "get tariff", "-t", ""}, - {"set credit", "get credit", "-r", ""}, - {"set credit expire", "get credit expire", "-E", ""}, - {"set password", "get password", "-o", ""}, - {"set prepaid traffic", "get prepaid traffic", "-e", ""}, - {"set IP-addresses", "get IP-addresses", "-I", "<*|ip_addr[,ip_addr...]>"}, - {"set name", "get name", "-A", ""}, - {"set note", "get note", "-N", ""}, - {"set street address", "get street address", "-D", "
"}, - {"set email", "get email", "-L", ""}, - {"set phone", "get phone", "-P", ""}, - {"set group", "get group", "-G", ""}, - {"set/unset down", "get down", "-d", "<0/1>"}, - {"set/unset \'passive\'", "get \'passive\'", "-i", "<0/1>"}, - {"set/unset \'disableDetailStat\'", "get \'disableDetailStat\'", "--disable-stat", "<0/1>"}, - {"set/unset \'alwaysOnline\'", "get \'alwaysOnline\'", "--always-online", "<0/1>"}, -}; - -for (unsigned i = 0; i < sizeof(hp) / sizeof(HelpParams); i++) - { - printf("To %s use:\n", hp[i].setActionName.c_str()); - printf("sgconf set -s -p -a -w -u %s %s\n", - hp[i].valueName.c_str(), hp[i].valueParam.c_str()); - printf("To %s use:\n", hp[i].getActionName.c_str()); - printf("sgconf get -s -p -a -w -u %s\n\n", - hp[i].valueName.c_str()); - } - -printf("To set user\'s upload traffic value use:\n"); -printf("sgconf set -s -p -a -w -u --u0 [--u1 ...]\n"); -printf("To get user\'s upload traffic value use:\n"); -printf("sgconf get -s -p -a -w -u --u0 [--u1 ...]\n\n"); - -printf("To set user\'s download traffic value use:\n"); -printf("sgconf set -s -p -a -w -u --d0 [--d1 ...]\n"); -printf("To get user\'s download traffic value use:\n"); -printf("sgconf get -s -p -a -w -u --d0 [--d1 ...]\n\n"); - -printf("To set userdata<0...9> use:\n"); -printf("sgconf set -s -p -a -w -u --ud0 [--ud1 ...]\n"); -printf("To get userdata<0...9> use:\n"); -printf("sgconf get -s -p -a -w -u --ud0 [--ud1 ...]\n\n"); - -printf("To get user's authorizers list use:\n"); -printf("sgconf get -s -p -a -w -u --authorized-by\n\n"); - -printf("To send message use:\n"); -printf("sgconf set -s -p -a -w -u -m \n\n"); - -printf("To create user use:\n"); -printf("sgconf set -s -p -a -w -u -n\n\n"); - -printf("To delete user use:\n"); -printf("sgconf set -s -p -a -w -u -l\n\n"); -} -//--------------------------------------------------------------------------- -void UsageConf() -{ -Usage(usageConf); -} -//--------------------------------------------------------------------------- -void UsageInfo() -{ -Usage(usageInfo); -} -//--------------------------------------------------------------------------- -int CheckLogin(const char * login) -{ -for (int i = 0; i < (int)strlen(login); i++) - { - if (!(( login[i] >= 'a' && login[i] <= 'z') - || (login[i] >= 'A' && login[i] <= 'Z') - || (login[i] >= '0' && login[i] <= '9') - || login[i] == '.' - || login[i] == '_' - || login[i] == '-')) - { - return 1; - } - } -return 0; -} -//----------------------------------------------------------------------------- -short int ParseServerPort(const char * p) -{ -int port; -if (str2x(p, port) != 0) - { - printf("Incorresct server port %s\n", p); - exit(NETWORK_ERR_CODE); - } -return (short)port; -} -//----------------------------------------------------------------------------- -char * ParseAdminLogin(char * adm) -{ -if (CheckLogin(adm)) - { - printf("Incorresct admin login %s\n", adm); - exit(PARAMETER_PARSING_ERR_CODE); - } -return adm; -} -//----------------------------------------------------------------------------- -char * ParsePassword(char * pass) -{ -if (strlen(pass) >= ADM_PASSWD_LEN) - { - printf("Password too big %s\n", pass); - exit(PARAMETER_PARSING_ERR_CODE); - } - -return pass; -} -//----------------------------------------------------------------------------- -char * ParseUser(char * usr) -{ -if (CheckLogin(usr)) - { - printf("Incorresct user login %s\n", usr); - exit(PARAMETER_PARSING_ERR_CODE); - } -return usr; -} -//----------------------------------------------------------------------------- -void ConvertKOI8(const string & src, string * dst, int encType) -{ -iconv_t cd; -char * ob = new char[src.size() * 2 + 1]; -char * ib = new char[src.size() + 1]; - -strcpy(ib, src.c_str()); - -char * outbuf = ob; -char * inbuf = ib; - -setlocale(LC_ALL, ""); - -char charsetF[100]; -char charsetT[100]; - -if (encType == TO_KOI8) - { - strcpy(charsetF, nl_langinfo(CODESET)); - strcpy(charsetT, "koi8-ru"); - } -else - { - strcpy(charsetT, nl_langinfo(CODESET)); - strcpy(charsetF, "koi8-ru"); - } - -size_t nconv = 1; - -size_t insize = strlen(ib); -size_t outsize = insize * 2 + 1; - -insize = src.size(); - -cd = iconv_open(charsetT, charsetF); -if (cd == (iconv_t) -1) - { - if (errno != EINVAL) - printf("error iconv_open\n"); - else - { - printf("Warning: iconv from %s to %s failed\n", charsetF, charsetT); - *dst = src; - return; - } - - exit(ICONV_ERR_CODE); - } - -#if defined(CONST_ICONV) -nconv = iconv(cd, (const char **)&inbuf, &insize, &outbuf, &outsize); -#else -nconv = iconv(cd, &inbuf, &insize, &outbuf, &outsize); -#endif -//printf("charsetT=%s charsetF=%s\n", charsetT, charsetF); -//printf("ib=%s ob=%s\n", ib, ob); -//printf("nconv=%d outsize=%d\n", nconv, outsize); -if (nconv == (size_t) -1) - { - if (errno != EINVAL) - { - printf("iconv error\n"); - exit(ICONV_ERR_CODE); - } - } - -*outbuf = L'\0'; - -iconv_close(cd); -*dst = ob; - -delete[] ob; -delete[] ib; -} -//----------------------------------------------------------------------------- -void ConvertFromKOI8(const string & src, string * dst) -{ -ConvertKOI8(src, dst, FROM_KOI8); -} -//----------------------------------------------------------------------------- -void ConvertToKOI8(const string & src, string * dst) -{ -ConvertKOI8(src, dst, TO_KOI8); -} -//----------------------------------------------------------------------------- -int RecvSetUserAnswer(const char * ans, void * d) -{ -GetUserCbData * gucbd; -gucbd = (GetUserCbData *)d; - -bool * result = gucbd->result; - -//REQUEST * req = (REQUEST *)gucbd->data; - -//printf("ans=%s\n", ans); -if (strcasecmp("Ok", ans) == 0) - *result = true; -else - *result = false; - -return 0; -} -//----------------------------------------------------------------------------- -struct StringReqParams -{ - string name; - RESETABLE reqParam; - string * value; -}; -//----------------------------------------------------------------------------- -void RecvUserData(USERDATA * ud, void * d) -{ -GetUserCbData * gucbd; -gucbd = (GetUserCbData *)d; - -bool * result = gucbd->result; - -REQUEST * req = (REQUEST *)gucbd->data; - -if (ud->login == "") - { - *result = false; - return; - } - -if (!req->cash.empty()) - cout << "cash=" << ud->cash << endl; - -if (!req->credit.empty()) - cout << "credit=" << ud->credit << endl; - -if (!req->creditExpire.empty()) - { - char buf[32]; - struct tm brokenTime; - time_t tt = ud->creditExpire; - - brokenTime.tm_wday = 0; - brokenTime.tm_yday = 0; - brokenTime.tm_isdst = 0; - brokenTime.tm_hour = 0; - brokenTime.tm_min = 0; - brokenTime.tm_sec = 0; - - gmtime_r(&tt, &brokenTime); - - strftime(buf, 32, "%Y-%m-%d", &brokenTime); - - cout << "creditExpire=" << buf << endl; - } - -if (!req->down.empty()) - cout << "down=" << ud->down << endl; - -if (!req->passive.empty()) - cout << "passive=" << ud->passive << endl; - -if (!req->disableDetailStat.empty()) - cout << "disableDetailStat=" << ud->disableDetailStat << endl; - -if (!req->alwaysOnline.empty()) - cout << "alwaysOnline=" << ud->alwaysOnline << endl; - -if (!req->prepaidTraff.empty()) - cout << "prepaidTraff=" << ud->prepaidTraff << endl; - -for (int i = 0; i < DIR_NUM; i++) - { - if (!req->u[i].empty()) - cout << "u" << i << "=" << ud->stat.mu[i] << endl; - if (!req->d[i].empty()) - cout << "d" << i << "=" << ud->stat.md[i] << endl; - } - -for (int i = 0; i < USERDATA_NUM; i++) - { - if (!req->ud[i].empty()) - { - string str; - ConvertFromKOI8(ud->userData[i], &str); - cout << "userdata" << i << "=" << str << endl; - } - } - -StringReqParams strReqParams[] = -{ - {"note", req->note, &ud->note}, - {"name", req->name, &ud->name}, - {"address", req->address, &ud->address}, - {"email", req->email, &ud->email}, - {"phone", req->phone, &ud->phone}, - {"group", req->group, &ud->group}, - {"tariff", req->tariff, &ud->tariff}, - {"password", req->usrPasswd, &ud->password}, - {"ip", req->ips, &ud->ips} // IP-address of user -}; -for (unsigned i = 0; i < sizeof(strReqParams) / sizeof(StringReqParams); i++) - { - if (!strReqParams[i].reqParam.empty()) - { - string str; - ConvertFromKOI8(*strReqParams[i].value, &str); - cout << strReqParams[i].name << "=" << str << endl; - } - } -*result = true; -} -//----------------------------------------------------------------------------- -void RecvAuthByData(const std::vector & list, void * d) -{ -AuthByCbData * abcbd; -abcbd = (AuthByCbData *)d; - -bool * result = abcbd->result; - -for (std::vector::const_iterator it = list.begin(); it != list.end(); ++it) - cout << *it << "\n"; -cout << endl; - -*result = true; -} -//----------------------------------------------------------------------------- -int ProcessSetUser(const std::string &server, - int port, - const std::string &admLogin, - const std::string &admPasswd, - const std::string &str, - void * data, - bool isMessage) -{ -SERVCONF sc; - -bool result = false; - - -sc.SetServer(server.c_str()); // õÓÔÁÎÁ×ÌÉ×ÁÅÍ ÉÍÑ ÓÅÒ×ÅÒÁ Ó ËÏÔÏÒÇÏ ÚÁÂÉÒÁÔØ ÉÎÆÕ -sc.SetPort(port); // ÁÄÍÉÎÓËÉÊ ÐÏÒÔ ÓÅÒ×ÅÒÁÐÏÒÔ -sc.SetAdmLogin(admLogin.c_str()); // ÷ÙÓÔÁ×ÌÑÅÍ ÌÏÇÉÎ É ÐÁÒÏÌØ ÁÄÍÉÎÁ -sc.SetAdmPassword(admPasswd.c_str()); - -// TODO Good variable name :) -GetUserCbData gucbd; - -gucbd.data = data; -gucbd.result = &result; - -if (isMessage) - { - sc.SetSendMessageCb(RecvSetUserAnswer, &gucbd); - sc.MsgUser(str.c_str()); - } -else - { - sc.SetChgUserCb(RecvSetUserAnswer, &gucbd); - sc.ChgUser(str.c_str()); - } - -if (result) - { - printf("Ok\n"); - return 0; - } -else - { - printf("Error\n"); - return -1; - } - -return 0; -} -//----------------------------------------------------------------------------- -int ProcessGetUser(const std::string &server, - int port, - const std::string &admLogin, - const std::string &admPasswd, - const std::string &login, - void * data) -{ -SERVCONF sc; - -bool result = false; - -sc.SetServer(server.c_str()); // õÓÔÁÎÁ×ÌÉ×ÁÅÍ ÉÍÑ ÓÅÒ×ÅÒÁ Ó ËÏÔÏÒÇÏ ÚÁÂÉÒÁÔØ ÉÎÆÕ -sc.SetPort(port); // ÁÄÍÉÎÓËÉÊ ÐÏÒÔ ÓÅÒ×ÅÒÁÐÏÒÔ -sc.SetAdmLogin(admLogin.c_str()); // ÷ÙÓÔÁ×ÌÑÅÍ ÌÏÇÉÎ É ÐÁÒÏÌØ ÁÄÍÉÎÁ -sc.SetAdmPassword(admPasswd.c_str()); - -// TODO Good variable name :) -GetUserCbData gucbd; - -gucbd.data = data; -gucbd.result = &result; - -sc.SetGetUserDataRecvCb(RecvUserData, &gucbd); -sc.GetUser(login.c_str()); - -if (result) - { - printf("Ok\n"); - return 0; - } -else - { - printf("Error\n"); - return -1; - } - -return 0; -} -//----------------------------------------------------------------------------- -int ProcessAuthBy(const std::string &server, - int port, - const std::string &admLogin, - const std::string &admPasswd, - const std::string &login, - void * data) -{ -SERVCONF sc; - -bool result = false; - -sc.SetServer(server.c_str()); // õÓÔÁÎÁ×ÌÉ×ÁÅÍ ÉÍÑ ÓÅÒ×ÅÒÁ Ó ËÏÔÏÒÇÏ ÚÁÂÉÒÁÔØ ÉÎÆÕ -sc.SetPort(port); // ÁÄÍÉÎÓËÉÊ ÐÏÒÔ ÓÅÒ×ÅÒÁÐÏÒÔ -sc.SetAdmLogin(admLogin.c_str()); // ÷ÙÓÔÁ×ÌÑÅÍ ÌÏÇÉÎ É ÐÁÒÏÌØ ÁÄÍÉÎÁ -sc.SetAdmPassword(admPasswd.c_str()); - -// TODO Good variable name :) -AuthByCbData abcbd; - -abcbd.data = data; -abcbd.result = &result; - -sc.SetGetUserAuthByRecvCb(RecvAuthByData, &abcbd); -sc.GetUserAuthBy(login.c_str()); - -if (result) - { - printf("Ok\n"); - return 0; - } -else - { - printf("Error\n"); - return -1; - } - -return 0; -} -//----------------------------------------------------------------------------- diff --git a/projects/sgconf/common_sg.h b/projects/sgconf/common_sg.h deleted file mode 100644 index a5cbffad..00000000 --- a/projects/sgconf/common_sg.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 - */ - -/* - * Author : Boris Mikhailenko - */ - - /* - $Author: faust $ - $Revision: 1.5 $ - $Date: 2009/06/08 10:02:28 $ - */ - - -#ifndef COMMON_SG_H -#define COMMON_SG_H - -#include - -#include "stg/servconf.h" -#include "request.h" - -void UsageConf(); -void UsageInfo(); - -char * ParseUser(char * usr); -char * ParsePassword(char * pass); -char * ParseAdminLogin(char * adm); -short int ParseServerPort(const char * p); -void ParseAnyString(const char * c, string * msg, const char * enc = "cp1251"); -int CheckLogin(const char * login); -void ConvertFromKOI8(const std::string & src, std::string * dst); -void ConvertToKOI8(const std::string & src, std::string * dst); - -int ProcessGetUser(const std::string &server, - int port, - const std::string &admLogin, - const std::string &admPasswd, - const std::string &login, - void * data); - -int ProcessAuthBy(const std::string &server, - int port, - const std::string &admLogin, - const std::string &admPasswd, - const std::string &login, - void * data); - -int ProcessSetUser(const std::string &server, - int port, - const std::string &admLogin, - const std::string &admPasswd, - const std::string &str, - void * data, - bool isMessage = false); - -#endif - diff --git a/projects/sgconf/config.h b/projects/sgconf/config.h new file mode 100644 index 00000000..d3659a1d --- /dev/null +++ b/projects/sgconf/config.h @@ -0,0 +1,88 @@ +/* + * 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 + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_SGCONF_CONFIG_H__ +#define __STG_SGCONF_CONFIG_H__ + +#include "stg/common.h" +#include "stg/resetable.h" +#include "stg/os_int.h" + +#include + +namespace SGCONF +{ + +struct CONFIG +{ + RESETABLE configFile; + RESETABLE server; + RESETABLE port; + RESETABLE localAddress; + RESETABLE localPort; + RESETABLE userName; + RESETABLE userPass; + RESETABLE showConfig; + + CONFIG & operator=(const CONFIG & rhs) + { + if (!rhs.configFile.empty()) + configFile = rhs.configFile; + if (!rhs.server.empty()) + server = rhs.server; + if (!rhs.port.empty()) + port = rhs.port; + if (!rhs.localAddress.empty()) + localAddress = rhs.localAddress; + if (!rhs.localPort.empty()) + localPort = rhs.localPort; + if (!rhs.userName.empty()) + userName = rhs.userName; + if (!rhs.userPass.empty()) + userPass = rhs.userPass; + if (!rhs.showConfig.empty()) + showConfig = rhs.showConfig; + return *this; + } + + std::string Serialize() const + { + std::string res; + if (!configFile.empty()) + res += "configFile: '" + configFile.data() + "'\n"; + if (!server.empty()) + res += "server: '" + server.data() + "'\n"; + if (!port.empty()) + res += "port: " + x2str(port.data()) + "\n"; + if (!localAddress.empty()) + res += "local address: '" + localAddress.data() + "'\n"; + if (!localPort.empty()) + res += "local port: " + x2str(localPort.data()) + "\n"; + if (!userName.empty()) + res += "userName: '" + userName.data() + "'\n"; + if (!userPass.empty()) + res += "userPass: '" + userPass.data() + "\n"; + return res; + } +}; + +} // namespace SGCONF + +#endif diff --git a/projects/sgconf/corps.cpp b/projects/sgconf/corps.cpp new file mode 100644 index 00000000..4bd436dd --- /dev/null +++ b/projects/sgconf/corps.cpp @@ -0,0 +1,162 @@ +#include "corps.h" + +#include "api_action.h" +#include "options.h" +#include "config.h" +#include "utils.h" + +#include "stg/servconf.h" +#include "stg/servconf_types.h" +#include "stg/corp_conf.h" +#include "stg/common.h" + +#include +#include +#include + +namespace +{ + +std::string Indent(size_t level, bool dash = false) +{ +if (level == 0) + return ""; +return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' '); +} + +void PrintCorp(const STG::GET_CORP::INFO & info, size_t level = 0) +{ +std::cout << Indent(level, true) << "name: " << info.name << "\n" + << Indent(level) << "cash: " << info.cash << "\n"; +} + +std::vector GetCorpParams() +{ +std::vector params; +params.push_back(SGCONF::API_ACTION::PARAM("cash", "", "\tcorporation's cash")); +return params; +} + +void SimpleCallback(bool result, + const std::string & reason, + void * /*data*/) +{ +if (!result) + { + std::cerr << "Operation failed. Reason: '" << reason << "'." << std::endl; + return; + } +std::cout << "Success.\n"; +} + +void GetCorpsCallback(bool result, + const std::string & reason, + const std::vector & info, + void * /*data*/) +{ +if (!result) + { + std::cerr << "Failed to get corp list. Reason: '" << reason << "'." << std::endl; + return; + } +std::cout << "Corps:\n"; +for (size_t i = 0; i < info.size(); ++i) + PrintCorp(info[i], 1); +} + +void GetCorpCallback(bool result, + const std::string & reason, + const STG::GET_CORP::INFO & info, + void * /*data*/) +{ +if (!result) + { + std::cerr << "Failed to get corp. Reason: '" << reason << "'." << std::endl; + return; + } +PrintCorp(info); +} + +bool GetCorpsFunction(const SGCONF::CONFIG & config, + const std::string & /*arg*/, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.GetCorporations(GetCorpsCallback, NULL) == STG::st_ok; +} + +bool GetCorpFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.GetCorp(arg, GetCorpCallback, NULL) == STG::st_ok; +} + +bool DelCorpFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.DelCorp(arg, SimpleCallback, NULL) == STG::st_ok; +} + +bool AddCorpFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & options) +{ +CORP_CONF_RES conf; +conf.name = arg; +SGCONF::MaybeSet(options, "cash", conf.cash); +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.AddCorp(arg, conf, SimpleCallback, NULL) == STG::st_ok; +} + +bool ChgCorpFunction(const SGCONF::CONFIG & config, + const std::string & arg, + const std::map & options) +{ +CORP_CONF_RES conf; +conf.name = arg; +SGCONF::MaybeSet(options, "cash", conf.cash); +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.ChgCorp(conf, SimpleCallback, NULL) == STG::st_ok; +} + +} // namespace anonymous + +void SGCONF::AppendCorpsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks) +{ +std::vector params(GetCorpParams()); +blocks.Add("Corporation management options") + .Add("get-corps", SGCONF::MakeAPIAction(commands, GetCorpsFunction), "\tget corporation list") + .Add("get-corp", SGCONF::MakeAPIAction(commands, "", GetCorpFunction), "get corporation") + .Add("add-corp", SGCONF::MakeAPIAction(commands, "", params, AddCorpFunction), "add corporation") + .Add("del-corp", SGCONF::MakeAPIAction(commands, "", DelCorpFunction), "delete corporation") + .Add("chg-corp", SGCONF::MakeAPIAction(commands, "", params, ChgCorpFunction), "change corporation"); +} diff --git a/projects/sgconf/corps.h b/projects/sgconf/corps.h new file mode 100644 index 00000000..de823b7b --- /dev/null +++ b/projects/sgconf/corps.h @@ -0,0 +1,14 @@ +#ifndef __STG_SGCONF_CORPS_H__ +#define __STG_SGCONF_CORPS_H__ + +namespace SGCONF +{ + +class OPTION_BLOCKS; +class COMMANDS; + +void AppendCorpsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks); + +} // namespace SGCONF + +#endif diff --git a/projects/sgconf/info.cpp b/projects/sgconf/info.cpp new file mode 100644 index 00000000..0e98d3dc --- /dev/null +++ b/projects/sgconf/info.cpp @@ -0,0 +1,60 @@ +#include "info.h" + +#include "api_action.h" +#include "options.h" +#include "config.h" + +#include "stg/servconf.h" + +#include +#include +#include + +#include + +namespace +{ + +void PrintInfo(const STG::SERVER_INFO::INFO& info) +{ + std::cout << "Server version: '" << info.version << "'\n" + << "Number of tariffs: " << info.tariffNum << "\n" + << "Tariff subsystem version: " << info.tariffType << "\n" + << "Number of users: " << info.usersNum << "\n" + << "UName: '" << info.uname << "\n" + << "Number of directions: " << info.dirNum << "\n" + << "Dirs:\n"; + for (size_t i = 0; i < info.dirName.size(); ++i) + std::cout << "\t - '" << info.dirName[i] << "'\n"; +} + +void InfoCallback(bool result, const std::string & reason, const STG::SERVER_INFO::INFO & info, void * /*data*/) +{ +if (!result) + { + std::cerr << "Failed to get server info. Reason: '" << reason << "'." << std::endl; + return; + } +PrintInfo(info); +} + +bool InfoFunction(const SGCONF::CONFIG & config, + const std::string& /*arg*/, + const std::map & /*options*/) +{ +STG::SERVCONF proto(config.server.data(), + config.port.data(), + config.localAddress.data(), + config.localPort.data(), + config.userName.data(), + config.userPass.data()); +return proto.ServerInfo(InfoCallback, NULL) == STG::st_ok; +} + +} + +void SGCONF::AppendServerInfoBlock(COMMANDS & commands, OPTION_BLOCKS & blocks) +{ +blocks.Add("Server info") + .Add("server-info", SGCONF::MakeAPIAction(commands, InfoFunction), "\tget server info"); +} diff --git a/projects/sgconf/info.h b/projects/sgconf/info.h new file mode 100644 index 00000000..86e4a9ec --- /dev/null +++ b/projects/sgconf/info.h @@ -0,0 +1,34 @@ +/* + * 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 + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_SGCONF_SERVER_INFO_H__ +#define __STG_SGCONF_SERVER_INFO_H__ + +namespace SGCONF +{ + +class OPTION_BLOCKS; +class COMMANDS; + +void AppendServerInfoBlock(COMMANDS & commands, OPTION_BLOCKS & blocks); + +} + +#endif diff --git a/projects/sgconf/main.cpp b/projects/sgconf/main.cpp index b107ee95..97908195 100644 --- a/projects/sgconf/main.cpp +++ b/projects/sgconf/main.cpp @@ -16,1120 +16,450 @@ /* * Author : Boris Mikhailenko + * Author : Maxim Mamontov */ - /* - $Author: faust $ - $Revision: 1.25 $ - $Date: 2010/03/25 14:37:43 $ - */ +#include "xml.h" +#include "admins.h" +#include "tariffs.h" +#include "users.h" +#include "services.h" +#include "corps.h" +#include "info.h" -#include -#include -#include -#include +#include "api_action.h" +#include "options.h" +#include "actions.h" +#include "config.h" -#include -#include -#include -#include #include -#include -#include - -#include "stg/common.h" -#include "stg/netunit.h" -#include "request.h" -#include "common_sg.h" -#include "sg_error_codes.h" - -using namespace std; - -time_t stgTime; - -int ParseReplyGet(void * data, list * ans); -//int ParseReplySet(void * data, list * ans); - -struct option long_options_get[] = { -{"server", 1, 0, 's'}, //Server -{"port", 1, 0, 'p'}, //Port -{"admin", 1, 0, 'a'}, //Admin -{"admin_pass", 1, 0, 'w'}, //passWord -{"user", 1, 0, 'u'}, //User -{"addcash", 0, 0, 'c'}, //Add Cash -//{"setcash", 0, 0, 'v'}, //Set Cash -{"credit", 0, 0, 'r'}, //cRedit -{"tariff", 0, 0, 't'}, //Tariff -{"message", 0, 0, 'm'}, //message -{"password", 0, 0, 'o'}, //password -{"down", 0, 0, 'd'}, //down -{"passive", 0, 0, 'i'}, //passive -{"disable-stat",0, 0, 'S'}, //disable detail stat -{"always-online",0, 0, 'O'}, //always online -{"u0", 0, 0, 500}, //U0 -{"u1", 0, 0, 501}, //U1 -{"u2", 0, 0, 502}, //U2 -{"u3", 0, 0, 503}, //U3 -{"u4", 0, 0, 504}, //U4 -{"u5", 0, 0, 505}, //U5 -{"u6", 0, 0, 506}, //U6 -{"u7", 0, 0, 507}, //U7 -{"u8", 0, 0, 508}, //U8 -{"u9", 0, 0, 509}, //U9 -{"d0", 0, 0, 600}, //D0 -{"d1", 0, 0, 601}, //D1 -{"d2", 0, 0, 602}, //D2 -{"d3", 0, 0, 603}, //D3 -{"d4", 0, 0, 604}, //D4 -{"d5", 0, 0, 605}, //D5 -{"d6", 0, 0, 606}, //D6 -{"d7", 0, 0, 607}, //D7 -{"d8", 0, 0, 608}, //D8 -{"d9", 0, 0, 609}, //D9 - -{"ud0", 0, 0, 700}, //UserData0 -{"ud1", 0, 0, 701}, //UserData1 -{"ud2", 0, 0, 702}, //UserData2 -{"ud3", 0, 0, 703}, //UserData3 -{"ud4", 0, 0, 704}, //UserData4 -{"ud5", 0, 0, 705}, //UserData5 -{"ud6", 0, 0, 706}, //UserData6 -{"ud7", 0, 0, 707}, //UserData7 -{"ud8", 0, 0, 708}, //UserData8 -{"ud9", 0, 0, 709}, //UserData9 - -{"prepaid", 0, 0, 'e'}, //prepaid traff -{"create", 0, 0, 'n'}, //create -{"delete", 0, 0, 'l'}, //delete - -{"note", 0, 0, 'N'}, //Note -{"name", 0, 0, 'A'}, //nAme -{"address", 0, 0, 'D'}, //aDdress -{"email", 0, 0, 'L'}, //emaiL -{"phone", 0, 0, 'P'}, //phone -{"group", 0, 0, 'G'}, //Group -{"ip", 0, 0, 'I'}, //IP-address of user -{"authorized-by",0, 0, 800}, //always online - -{0, 0, 0, 0}}; +#include -struct option long_options_set[] = { -{"server", 1, 0, 's'}, //Server -{"port", 1, 0, 'p'}, //Port -{"admin", 1, 0, 'a'}, //Admin -{"admin_pass", 1, 0, 'w'}, //passWord -{"user", 1, 0, 'u'}, //User -{"addcash", 1, 0, 'c'}, //Add Cash -{"setcash", 1, 0, 'v'}, //Set Cash -{"credit", 1, 0, 'r'}, //cRedit -{"tariff", 1, 0, 't'}, //Tariff -{"message", 1, 0, 'm'}, //message -{"password", 1, 0, 'o'}, //password -{"down", 1, 0, 'd'}, //down -{"passive", 1, 0, 'i'}, //passive -{"disable-stat",1, 0, 'S'}, //disable detail stat -{"always-online",1, 0, 'O'}, //always online -{"u0", 1, 0, 500}, //U0 -{"u1", 1, 0, 501}, //U1 -{"u2", 1, 0, 502}, //U2 -{"u3", 1, 0, 503}, //U3 -{"u4", 1, 0, 504}, //U4 -{"u5", 1, 0, 505}, //U5 -{"u6", 1, 0, 506}, //U6 -{"u7", 1, 0, 507}, //U7 -{"u8", 1, 0, 508}, //U8 -{"u9", 1, 0, 509}, //U9 -{"d0", 1, 0, 600}, //D0 -{"d1", 1, 0, 601}, //D1 -{"d2", 1, 0, 602}, //D2 -{"d3", 1, 0, 603}, //D3 -{"d4", 1, 0, 604}, //D4 -{"d5", 1, 0, 605}, //D5 -{"d6", 1, 0, 606}, //D6 -{"d7", 1, 0, 607}, //D7 -{"d8", 1, 0, 608}, //D8 -{"d9", 1, 0, 609}, //D9 +#include // getenv +#include // str* -{"ud0", 1, 0, 700}, //UserData -{"ud1", 1, 0, 701}, //UserData1 -{"ud2", 1, 0, 702}, //UserData2 -{"ud3", 1, 0, 703}, //UserData3 -{"ud4", 1, 0, 704}, //UserData4 -{"ud5", 1, 0, 705}, //UserData5 -{"ud6", 1, 0, 706}, //UserData6 -{"ud7", 1, 0, 707}, //UserData7 -{"ud8", 1, 0, 708}, //UserData8 -{"ud9", 1, 0, 709}, //UserData9 +#include // access +#include // basename -{"prepaid", 1, 0, 'e'}, //prepaid traff -{"create", 1, 0, 'n'}, //create -{"delete", 1, 0, 'l'}, //delete - -{"note", 1, 0, 'N'}, //Note -{"name", 1, 0, 'A'}, //nAme -{"address", 1, 0, 'D'}, //aDdress -{"email", 1, 0, 'L'}, //emaiL -{"phone", 1, 0, 'P'}, //phone -{"group", 1, 0, 'G'}, //Group -{"ip", 0, 0, 'I'}, //IP-address of user - -{0, 0, 0, 0}}; - -//----------------------------------------------------------------------------- -double ParseCash(const char * c, string * message) +namespace { -//-c 123.45:log message -double cash; -char * msg; -char * str; -str = new char[strlen(c) + 1]; - -strncpy(str, c, strlen(c)); -str[strlen(c)] = 0; - -msg = strchr(str, ':'); - -if (msg) - { - *message = msg + 1; - str[msg - str] = 0; - } -else - *message = ""; -if (strtodouble2(str, cash) != 0) - { - printf("Incorrect cash value %s\n", c); - exit(PARAMETER_PARSING_ERR_CODE); - } - -delete[] str; -return cash; -} -//----------------------------------------------------------------------------- -double ParseCredit(const char * c) +template +struct nullary_function { -double credit; -if (strtodouble2(c, credit) != 0) - { - printf("Incorrect credit value %s\n", c); - exit(PARAMETER_PARSING_ERR_CODE); - } +typedef T result_type; +}; -return credit; -} -//----------------------------------------------------------------------------- -double ParsePrepaidTraffic(const char * c) +template +class binder0 : public nullary_function { -double credit; -if (strtodouble2(c, credit) != 0) - { - printf("Incorrect prepaid traffic value %s\n", c); - exit(PARAMETER_PARSING_ERR_CODE); - } - -return credit; -} -//----------------------------------------------------------------------------- -int64_t ParseTraff(const char * c) + public: + binder0(const F & func, const typename F::argument_type & arg) + : m_func(func), m_arg(arg) {} + typename F::result_type operator()() const { return m_func(m_arg); } + private: + F m_func; + typename F::argument_type m_arg; +}; + +template +inline +binder0 bind0(const F & func, const typename F::argument_type & arg) { -int64_t traff; -if (str2x(c, traff) != 0) - { - printf("Incorrect credit value %s\n", c); - exit(PARAMETER_PARSING_ERR_CODE); - } - -return traff; +return binder0(func, arg); } -//----------------------------------------------------------------------------- -bool ParseDownPassive(const char * dp) -{ -if (!(dp[1] == 0 && (dp[0] == '1' || dp[0] == '0'))) - { - printf("Incorrect value %s\n", dp); - exit(PARAMETER_PARSING_ERR_CODE); - } -return dp[0] - '0'; -} -//----------------------------------------------------------------------------- -string ParseTariff(const char * t, int &chgType) +template +class FUNC1_ADAPTER : public std::unary_function { -int l = strlen(t); -char * s; -s = new char[l]; -char * s1, * s2; -string ss; - -strcpy(s, t); - -s1 = strtok(s, ":"); - -if (strlen(s1) >= TARIFF_NAME_LEN) - { - printf("Tariff name too big %s\n", s1); - exit(PARAMETER_PARSING_ERR_CODE); - } - -//*tariff = s; - -if (CheckLogin(s1)) - { - printf("Incorrect tariff value %s\n", t); - exit(PARAMETER_PARSING_ERR_CODE); - } - -s2 = strtok(NULL, ":"); - -chgType = -1; - -if (s2 == NULL) - { - chgType = TARIFF_NOW; - ss = s; - delete[] s; - return ss; - } - - -if (strcmp(s2, "now") == 0) - chgType = TARIFF_NOW; - -if (strcmp(s2, "delayed") == 0) - chgType = TARIFF_DEL; - -if (strcmp(s2, "recalc") == 0) - chgType = TARIFF_REC; - -if (chgType < 0) - { - printf("Incorrect tariff value %s\n", t); - exit(PARAMETER_PARSING_ERR_CODE); - } - -ss = s; -delete[] s; -return ss; -} -//----------------------------------------------------------------------------- -time_t ParseCreditExpire(const char * str) + public: + FUNC1_ADAPTER(R (*func)(A)) : m_func(func) {} + const R operator()(A arg) const { return (m_func)(arg); } + private: + R (*m_func)(A); +}; + +template +class METHOD1_ADAPTER : public std::unary_function { -struct tm brokenTime; - -brokenTime.tm_wday = 0; -brokenTime.tm_yday = 0; -brokenTime.tm_isdst = 0; -brokenTime.tm_hour = 0; -brokenTime.tm_min = 0; -brokenTime.tm_sec = 0; - -stg_strptime(str, "%Y-%m-%d", &brokenTime); - -return stg_timegm(&brokenTime); -} -//----------------------------------------------------------------------------- -void ParseAnyString(const char * c, string * msg, const char * enc) + public: + METHOD1_ADAPTER(R (C::* func)(A), C & obj) : m_func(func), m_obj(obj) {} + R operator()(A arg) { return (m_obj.*m_func)(arg); } + private: + R (C::* m_func)(A); + C & m_obj; +}; + +template +class CONST_METHOD1_ADAPTER : public std::unary_function { -iconv_t cd; -char * ob = new char[strlen(c) + 1]; -char * ib = new char[strlen(c) + 1]; - -strcpy(ib, c); - -char * outbuf = ob; -char * inbuf = ib; - -setlocale(LC_ALL, ""); - -char charsetF[255]; -strncpy(charsetF, nl_langinfo(CODESET), 255); - -const char * charsetT = enc; + public: + CONST_METHOD1_ADAPTER(R (C::* func)(A) const, C & obj) : m_func(func), m_obj(obj) {} + R operator()(A arg) const { return (m_obj.*m_func)(arg); } + private: + R (C::* m_func)(A) const; + C & m_obj; +}; + +template +FUNC1_ADAPTER Func1Adapt(R (func)(A)) +{ +return FUNC1_ADAPTER(func); +} -size_t nconv = 1; +template +METHOD1_ADAPTER Method1Adapt(R (C::* func)(A), C & obj) +{ +return METHOD1_ADAPTER(func, obj); +} -size_t insize = strlen(ib); -size_t outsize = strlen(ib); +template +CONST_METHOD1_ADAPTER Method1Adapt(R (C::* func)(A) const, C & obj) +{ +return CONST_METHOD1_ADAPTER(func, obj); +} -insize = strlen(c); +void Version(const std::string & self) +{ +std::cout << self << ", version: 2.0.0.\n"; +} -cd = iconv_open(charsetT, charsetF); -if (cd == (iconv_t) -1) +void ReadUserConfigFile(SGCONF::OPTION_BLOCK & block) +{ +std::vector paths; +const char * configHome = getenv("XDG_CONFIG_HOME"); +if (configHome == NULL) { - if (errno == EINVAL) - { - printf("Warning: iconv from %s to %s failed\n", charsetF, charsetT); - *msg = c; + const char * home = getenv("HOME"); + if (home == NULL) return; - } - else - printf("error iconv_open\n"); - - exit(ICONV_ERR_CODE); + paths.push_back(std::string(home) + "/.config/sgconf/sgconf.conf"); + paths.push_back(std::string(home) + "/.sgconf/sgconf.conf"); } - -#if defined(CONST_ICONV) -nconv = iconv (cd, (const char**)&inbuf, &insize, &outbuf, &outsize); -#else -nconv = iconv (cd, &inbuf, &insize, &outbuf, &outsize); -#endif -//printf("nconv=%d outsize=%d\n", nconv, outsize); -if (nconv == (size_t) -1) - { - if (errno != EINVAL) +else + paths.push_back(std::string(configHome) + "/sgconf/sgconf.conf"); +for (std::vector::const_iterator it = paths.begin(); it != paths.end(); ++it) + if (access(it->c_str(), R_OK) == 0) { - printf("iconv error\n"); - exit(ICONV_ERR_CODE); + block.ParseFile(*it); + return; } - } - -*outbuf = L'\0'; - -iconv_close(cd); -*msg = ob; - -delete[] ob; -delete[] ib; } -//----------------------------------------------------------------------------- -void CreateRequestSet(REQUEST * req, char * r) -{ -const int strLen = 10024; -char str[strLen]; -memset(str, 0, strLen); -r[0] = 0; +} // namespace anonymous -if (!req->usrMsg.empty()) - { - string msg; - Encode12str(msg, req->usrMsg.const_data()); - sprintf(str, "", req->login.const_data().c_str(), msg.c_str()); - //sprintf(str, "\n", req->login, msg); - strcat(r, str); - return; - } - -if (req->deleteUser) - { - sprintf(str, "", req->login.const_data().c_str()); - strcat(r, str); - //printf("%s\n", r); - return; - } - -if (req->createUser) - { - sprintf(str, " ", req->login.const_data().c_str()); - strcat(r, str); - //printf("%s\n", r); - return; - } - -strcat(r, "\n"); -sprintf(str, "\n", req->login.const_data().c_str()); -strcat(r, str); -if (!req->credit.empty()) - { - sprintf(str, "\n", req->credit.const_data()); - strcat(r, str); - } - -if (!req->creditExpire.empty()) - { - sprintf(str, "\n", req->creditExpire.const_data()); - strcat(r, str); - } +namespace SGCONF +{ -if (!req->prepaidTraff.empty()) - { - sprintf(str, "\n", req->prepaidTraff.const_data()); - strcat(r, str); - } +class CONFIG_ACTION : public ACTION +{ + public: + CONFIG_ACTION(SGCONF::CONFIG & config, + const std::string & paramDescription) + : m_config(config), + m_description(paramDescription) + {} -if (!req->cash.empty()) - { - string msg; - Encode12str(msg, req->message.c_str()); - sprintf(str, "\n", req->cash.const_data(), msg.c_str()); - strcat(r, str); - } + virtual ACTION * Clone() const { return new CONFIG_ACTION(*this); } -if (!req->setCash.empty()) - { - string msg; - Encode12str(msg, req->message.c_str()); - sprintf(str, "\n", req->setCash.const_data(), msg.c_str()); - strcat(r, str); - } + virtual std::string ParamDescription() const { return m_description; } + virtual std::string DefaultDescription() const { return ""; } + virtual OPTION_BLOCK & Suboptions() { return m_suboptions; } + virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/); -if (!req->usrPasswd.empty()) - { - sprintf(str, "\n", req->usrPasswd.const_data().c_str()); - strcat(r, str); - } + private: + SGCONF::CONFIG & m_config; + std::string m_description; + OPTION_BLOCK m_suboptions; -if (!req->down.empty()) - { - sprintf(str, "\n", req->down.const_data()); - strcat(r, str); - } + void ParseCredentials(const std::string & credentials); + void ParseHostAndPort(const std::string & hostAndPort); +}; -if (!req->passive.empty()) - { - sprintf(str, "\n", req->passive.const_data()); - strcat(r, str); - } -if (!req->disableDetailStat.empty()) - { - sprintf(str, "\n", req->disableDetailStat.const_data()); - strcat(r, str); - } - -if (!req->alwaysOnline.empty()) +PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv, void * /*data*/) +{ +if (argc == 0 || + argv == NULL || + *argv == NULL) + throw ERROR("Missing argument."); +char * pos = strchr(*argv, '@'); +if (pos != NULL) { - sprintf(str, "\n", req->alwaysOnline.const_data()); - strcat(r, str); + ParseCredentials(std::string(*argv, pos)); + ParseHostAndPort(std::string(pos + 1)); } - -// IP-address of user -if (!req->ips.empty()) +else { - sprintf(str, "\n", req->ips.const_data().c_str()); - strcat(r, str); + ParseHostAndPort(std::string(*argv)); } +return PARSER_STATE(false, --argc, ++argv); +} -int uPresent = false; -int dPresent = false; -for (int i = 0; i < DIR_NUM; i++) - { - if (!req->u[i].empty()) - { - if (!uPresent && !dPresent) - { - sprintf(str, "u[i].const_data(); - //sprintf(str, "MU%d=\"%lld\" ", i, req->u[i].const_data()); - sprintf(str, "MU%d=\"%s\" ", i, ss.str().c_str()); - strcat(r, str); - } - if (!req->d[i].empty()) - { - if (!uPresent && !dPresent) - { - sprintf(str, "d[i].const_data(); - sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str()); - strcat(r, str); - } - } -if (uPresent || dPresent) +void CONFIG_ACTION::ParseCredentials(const std::string & credentials) +{ +std::string::size_type pos = credentials.find_first_of(':'); +if (pos != std::string::npos) { - strcat(r, "/>"); + m_config.userName = credentials.substr(0, pos); + m_config.userPass = credentials.substr(pos + 1); } - -//printf("%s\n", r); - -if (!req->tariff.empty()) +else { - switch (req->chgTariff) - { - case TARIFF_NOW: - sprintf(str, "\n", req->tariff.const_data().c_str()); - strcat(r, str); - break; - case TARIFF_REC: - sprintf(str, "\n", req->tariff.const_data().c_str()); - strcat(r, str); - break; - case TARIFF_DEL: - sprintf(str, "\n", req->tariff.const_data().c_str()); - strcat(r, str); - break; - } - + m_config.userName = credentials; } +} -if (!req->note.empty()) +void CONFIG_ACTION::ParseHostAndPort(const std::string & hostAndPort) +{ +std::string::size_type pos = hostAndPort.find_first_of(':'); +if (pos != std::string::npos) { - string note; - Encode12str(note, req->note.const_data()); - sprintf(str, "", note.c_str()); - strcat(r, str); + m_config.server = hostAndPort.substr(0, pos); + uint16_t port = 0; + if (str2x(hostAndPort.substr(pos + 1), port)) + throw ERROR("Invalid port value: '" + hostAndPort.substr(pos + 1) + "'"); + m_config.port = port; } - -if (!req->name.empty()) +else { - string name; - Encode12str(name, req->name.const_data()); - sprintf(str, "", name.c_str()); - strcat(r, str); + m_config.server = hostAndPort; } +} -if (!req->address.empty()) - { - string address; - Encode12str(address, req->address.const_data()); - sprintf(str, "
", address.c_str()); - strcat(r, str); - } +inline +CONFIG_ACTION * MakeParamAction(SGCONF::CONFIG & config, + const std::string & paramDescription) +{ +return new CONFIG_ACTION(config, paramDescription); +} -if (!req->email.empty()) - { - string email; - Encode12str(email, req->email.const_data()); - sprintf(str, "", email.c_str()); - strcat(r, str); - } +} // namespace SGCONF -if (!req->phone.empty()) - { - string phone; - Encode12str(phone, req->phone.const_data()); - sprintf(str, "", phone.c_str()); - strcat(r, str); - } +//----------------------------------------------------------------------------- +int main(int argc, char **argv) +{ +std::string self(basename(argv[0])); +SGCONF::CONFIG config; +SGCONF::COMMANDS commands; + +SGCONF::OPTION_BLOCKS blocks; +blocks.Add("General options") + .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), ""), "override default config file") + .Add("h", "help", SGCONF::MakeFunc0Action(bind0(Method1Adapt(&SGCONF::OPTION_BLOCKS::Help, blocks), 0)), "\t\tshow this help and exit") + //.Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "\t\tshow full help and exit") + .Add("v", "version", SGCONF::MakeFunc0Action(bind0(Func1Adapt(Version), self)), "\t\tshow version information and exit"); +SGCONF::OPTION_BLOCK & block = blocks.Add("Connection options") + .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "
"), "\t\thost to connect") + .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), ""), "\t\tport to connect") + .Add("local-address", SGCONF::MakeParamAction(config.localAddress, std::string(""), "
"), "\tlocal address to bind") + .Add("local-port", SGCONF::MakeParamAction(config.localPort, uint16_t(0), ""), "\t\tlocal port to bind") + .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), ""), "\tadministrative login") + .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, ""), "\tpassword for the administrative login") + .Add("a", "address", SGCONF::MakeParamAction(config, ""), "connection params as a single string in format: :@:"); +blocks.Add("Debug options") + .Add("show-config", SGCONF::MakeParamAction(config.showConfig), "\tshow config and exit"); +SGCONF::AppendXMLOptionBlock(commands, blocks); +SGCONF::AppendServerInfoBlock(commands, blocks); +SGCONF::AppendAdminsOptionBlock(commands, blocks); +SGCONF::AppendTariffsOptionBlock(commands, blocks); +SGCONF::AppendUsersOptionBlock(commands, blocks); +SGCONF::AppendServicesOptionBlock(commands, blocks); +SGCONF::AppendCorpsOptionBlock(commands, blocks); + +SGCONF::PARSER_STATE state(false, argc, argv); + +try +{ +state = blocks.Parse(--argc, ++argv); // Skipping self name +} +catch (const SGCONF::OPTION::ERROR& ex) +{ +std::cerr << ex.what() << "\n"; +return -1; +} -if (!req->group.empty()) - { - string group; - Encode12str(group, req->group.const_data()); - sprintf(str, "", group.c_str()); - strcat(r, str); - } +if (state.stop) + return 0; -for (int i = 0; i < USERDATA_NUM; i++) +if (state.argc > 0) { - if (!req->ud[i].empty()) - { - string ud; - Encode12str(ud, req->ud[i].const_data()); - sprintf(str, "", i, ud.c_str()); - strcat(r, str); - } + std::cerr << "Unknown option: '" << *state.argv << "'\n"; + return -1; } -strcat(r, "\n"); -} -//----------------------------------------------------------------------------- -int CheckParameters(REQUEST * req) +try { -int u = false; -int d = false; -int ud = false; -int a = !req->admLogin.empty() - && !req->admPasswd.empty() - && !req->server.empty() - && !req->port.empty() - && !req->login.empty(); - -int b = !req->cash.empty() - || !req->setCash.empty() - || !req->credit.empty() - || !req->prepaidTraff.empty() - || !req->tariff.empty() - || !req->usrMsg.empty() - || !req->usrPasswd.empty() - - || !req->note.empty() - || !req->name.empty() - || !req->address.empty() - || !req->email.empty() - || !req->phone.empty() - || !req->group.empty() - || !req->ips.empty() // IP-address of user - - || !req->createUser - || !req->deleteUser; - +SGCONF::CONFIG configOverride(config); -for (int i = 0; i < DIR_NUM; i++) +if (config.configFile.empty()) { - if (req->u[i].empty()) - { - u = true; - break; - } + const char * mainConfigFile = "/etc/sgconf/sgconf.conf"; + if (access(mainConfigFile, R_OK) == 0) + block.ParseFile(mainConfigFile); + ReadUserConfigFile(block); } - -for (int i = 0; i < DIR_NUM; i++) +else { - if (req->d[i].empty()) - { - d = true; - break; - } + block.ParseFile(config.configFile.data()); } -for (int i = 0; i < DIR_NUM; i++) +config = configOverride; + +if (!config.showConfig.empty() && config.showConfig.data()) { - if (req->ud[i].empty()) - { - ud = true; - break; - } + std::cout << config.Serialize() << std::endl; + return 0; } - - -//printf("a=%d, b=%d, u=%d, d=%d ud=%d\n", a, b, u, d, ud); -return a && (b || u || d || ud); +return commands.Execute(config) ? 0 : -1; } -//----------------------------------------------------------------------------- -int CheckParametersGet(REQUEST * req) +catch (const std::exception& ex) { -return CheckParameters(req); +std::cerr << ex.what() << "\n"; +return -1; } -//----------------------------------------------------------------------------- -int CheckParametersSet(REQUEST * req) -{ -return CheckParameters(req); } //----------------------------------------------------------------------------- -int mainGet(int argc, char **argv) -{ -int c; -REQUEST req; -RESETABLE t1; -int missedOptionArg = false; - -const char * short_options_get = "s:p:a:w:u:crtmodieNADLPGISOE"; -int option_index = -1; - -while (1) - { - option_index = -1; - c = getopt_long(argc, argv, short_options_get, long_options_get, &option_index); - if (c == -1) - break; - - switch (c) - { - case 's': //server - req.server = optarg; - break; - - case 'p': //port - req.port = ParseServerPort(optarg); - //req.portReq = 1; - break; - - case 'a': //admin - req.admLogin = ParseAdminLogin(optarg); - break; - - case 'w': //admin password - req.admPasswd = ParsePassword(optarg); - break; - - case 'o': //change user password - req.usrPasswd = " "; - break; - - case 'u': //user - req.login = ParseUser(optarg); - break; - - case 'c': //get cash - req.cash = 1; - break; - - case 'r': //credit - req.credit = 1; - break; - - case 'E': //credit expire - req.creditExpire = 1; - break; - case 'd': //down - req.down = 1; - break; - - case 'i': //passive - req.passive = 1; - break; - - case 't': //tariff - req.tariff = " "; - break; - - case 'e': //Prepaid Traffic - req.prepaidTraff = 1; - break; - - case 'N': //Note - req.note = " "; - break; - - case 'A': //nAme - req.name = " "; - break; - - case 'D': //aDdress - req.address =" "; - break; - - case 'L': //emaiL - req.email = " "; - break; - - case 'P': //phone - req.phone = " "; - break; - - case 'G': //Group - req.group = " "; - break; - - case 'I': //IP-address of user - req.ips = " "; - break; - - case 'S': //Detail stat status - req.disableDetailStat = " "; - break; - - case 'O': //Always online status - req.alwaysOnline = " "; - break; - - case 500: //U - case 501: - case 502: - case 503: - case 504: - case 505: - case 506: - case 507: - case 508: - case 509: - //printf("U%d\n", c - 500); - req.u[c - 500] = 1; - break; - - case 600: //D - case 601: - case 602: - case 603: - case 604: - case 605: - case 606: - case 607: - case 608: - case 609: - //printf("D%d\n", c - 600); - req.d[c - 600] = 1; - break; - - case 700: //UserData - case 701: - case 702: - case 703: - case 704: - case 705: - case 706: - case 707: - case 708: - case 709: - //printf("UD%d\n", c - 700); - req.ud[c - 700] = " "; - break; - - case 800: - req.authBy = true; - break; - - case '?': - case ':': - //printf ("Unknown option \n"); - missedOptionArg = true; - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - -if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - UsageInfo(); - exit(PARAMETER_PARSING_ERR_CODE); - } - -if (missedOptionArg || !CheckParametersGet(&req)) - { - //printf("Parameter needed\n"); - UsageInfo(); - exit(PARAMETER_PARSING_ERR_CODE); - } +namespace +{ -if (req.authBy) - return ProcessAuthBy(req.server.const_data(), req.port.const_data(), req.admLogin.const_data(), req.admPasswd.const_data(), req.login.const_data(), &req); -else - return ProcessGetUser(req.server.const_data(), req.port.const_data(), req.admLogin.const_data(), req.admPasswd.const_data(), req.login.const_data(), &req); +/*void UsageTariffs(bool full) +{ +std::cout << "Tariffs management options:\n" + << "\t--get-tariffs\t\t\t\tget a list of tariffs (subsequent options will define what to show)\n"; +if (full) + std::cout << "\t\t--name\t\t\t\tshow tariff's name\n" + << "\t\t--fee\t\t\t\tshow tariff's fee\n" + << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n" + << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n" + << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n" + << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n"; +std::cout << "\t--get-tariff\t\t\t\tget the information about tariff\n"; +if (full) + std::cout << "\t\t--name \t\t\tname of the tariff to show\n" + << "\t\t--fee\t\t\t\tshow tariff's fee\n" + << "\t\t--free\t\t\t\tshow tariff's prepaid traffic in terms of cost\n" + << "\t\t--passive-cost\t\t\tshow tariff's cost of \"freeze\"\n" + << "\t\t--traff-type\t\t\tshow what type of traffix will be accounted by the tariff\n" + << "\t\t--dirs\t\t\t\tshow tarification rules for directions\n\n"; +std::cout << "\t--add-tariff\t\t\t\tadd a new tariff\n"; +if (full) + std::cout << "\t\t--name \t\t\tname of the tariff to add\n" + << "\t\t--fee \t\t\tstariff's fee\n" + << "\t\t--free \t\t\ttariff's prepaid traffic in terms of cost\n" + << "\t\t--passive-cost \t\ttariff's cost of \"freeze\"\n" + << "\t\t--traff-type \t\twhat type of traffi will be accounted by the tariff\n" + << "\t\t--times \t\t\tslash-separated list of \"day\" time-spans (in form \"hh:mm-hh:mm\") for each direction\n" + << "\t\t--prices-day-a \t\tslash-separated list of prices for \"day\" traffic before threshold for each direction\n" + << "\t\t--prices-night-a \tslash-separated list of prices for \"night\" traffic before threshold for each direction\n" + << "\t\t--prices-day-b \t\tslash-separated list of prices for \"day\" traffic after threshold for each direction\n" + << "\t\t--prices-night-b \tslash-separated list of prices for \"night\" traffic after threshold for each direction\n" + << "\t\t--single-prices \tslash-separated list of \"single price\" flags for each direction\n" + << "\t\t--no-discounts \t\tslash-separated list of \"no discount\" flags for each direction\n" + << "\t\t--thresholds \tslash-separated list of thresholds (in Mb) for each direction\n\n"; +std::cout << "\t--del-tariff\t\t\t\tdelete an existing tariff\n"; +if (full) + std::cout << "\t\t--name \t\t\tname of the tariff to delete\n\n"; +std::cout << "\t--chg-tariff\t\t\t\tchange an existing tariff\n"; +if (full) + std::cout << "\t\t--name \t\t\tname of the tariff to change\n" + << "\t\t--fee \t\t\tstariff's fee\n" + << "\t\t--free \t\t\ttariff's prepaid traffic in terms of cost\n" + << "\t\t--passive-cost \t\ttariff's cost of \"freeze\"\n" + << "\t\t--traff-type \t\twhat type of traffix will be accounted by the tariff\n" + << "\t\t--dir \t\t\tnumber of direction data to change\n" + << "\t\t\t--time