]> git.stg.codes - stg.git/commitdiff
Merge branch 'stg-2.409'
authorMaxim Mamontov <faust.madf@gmail.com>
Thu, 22 Dec 2016 20:25:24 +0000 (22:25 +0200)
committerMaxim Mamontov <faust.madf@gmail.com>
Thu, 22 Dec 2016 20:25:24 +0000 (22:25 +0200)
136 files changed:
functest/build.sh [new file with mode: 0755]
functest/clone.sh [new file with mode: 0755]
functest/do.sh [new file with mode: 0755]
functest/functions [new file with mode: 0644]
functest/stuff/OnChange [new file with mode: 0755]
functest/stuff/OnConnect [new file with mode: 0755]
functest/stuff/OnDisconnect [new file with mode: 0755]
functest/stuff/db-stub/admins/admin.adm [new file with mode: 0644]
functest/stuff/db-stub/tariffs/tariff.tf [new file with mode: 0644]
functest/stuff/db-stub/users/test/conf [new file with mode: 0644]
functest/stuff/db-stub/users/test/stat [new file with mode: 0644]
functest/stuff/rules [new file with mode: 0644]
functest/stuff/stargazer-files.conf [new file with mode: 0644]
functest/test.sh [new file with mode: 0755]
functest/test_admins.sh [new file with mode: 0755]
functest/test_server_info.sh [new file with mode: 0755]
functest/test_services.sh [new file with mode: 0755]
include/stg/admin_conf.h
include/stg/array.h [new file with mode: 0644]
include/stg/corp_conf.h
include/stg/corporations.h
include/stg/user_conf.h
include/stg/user_stat.h
include/stg/user_traff.h
include/stg/version.h
projects/sgconf/Makefile
projects/sgconf/README.txt
projects/sgconf/TODO [new file with mode: 0644]
projects/sgconf/action.h [new file with mode: 0644]
projects/sgconf/actions.cpp [new file with mode: 0644]
projects/sgconf/actions.h [new file with mode: 0644]
projects/sgconf/admins.cpp [new file with mode: 0644]
projects/sgconf/admins.h [new file with mode: 0644]
projects/sgconf/api_action.cpp [new file with mode: 0644]
projects/sgconf/api_action.h [new file with mode: 0644]
projects/sgconf/common_sg.cpp [deleted file]
projects/sgconf/common_sg.h [deleted file]
projects/sgconf/config.h [new file with mode: 0644]
projects/sgconf/corps.cpp [new file with mode: 0644]
projects/sgconf/corps.h [new file with mode: 0644]
projects/sgconf/info.cpp [new file with mode: 0644]
projects/sgconf/info.h [new file with mode: 0644]
projects/sgconf/main.cpp
projects/sgconf/options.cpp [new file with mode: 0644]
projects/sgconf/options.h [new file with mode: 0644]
projects/sgconf/parser.cpp [deleted file]
projects/sgconf/parser_state.h [new file with mode: 0644]
projects/sgconf/request.h [deleted file]
projects/sgconf/services.cpp [new file with mode: 0644]
projects/sgconf/services.h [new file with mode: 0644]
projects/sgconf/sg_error_codes.h [deleted file]
projects/sgconf/sgconfg [deleted file]
projects/sgconf/sgconfs [deleted file]
projects/sgconf/sginfo.cpp [deleted file]
projects/sgconf/tariffs.cpp [new file with mode: 0644]
projects/sgconf/tariffs.h [new file with mode: 0644]
projects/sgconf/users.cpp [new file with mode: 0644]
projects/sgconf/users.h [new file with mode: 0644]
projects/sgconf/utils.h [new file with mode: 0644]
projects/sgconf/version_sg.h [deleted file]
projects/sgconf/xml.cpp [new file with mode: 0644]
projects/sgconf/xml.h [new file with mode: 0644]
projects/sgconv/build
projects/stargazer/build
projects/stargazer/inst/freebsd/etc/stargazer/conf-available.d/mod_ia.conf
projects/stargazer/inst/freebsd/etc/stargazer/stargazer.conf
projects/stargazer/inst/linux/etc/stargazer/conf-available.d/mod_ia.conf
projects/stargazer/inst/linux/etc/stargazer/stargazer.conf
projects/stargazer/plugins/capture/pcap/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/pcap/pcap_cap.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/pcap/pcap_cap.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/Makefile
projects/stargazer/plugins/configuration/sgconfig/configproto.cpp
projects/stargazer/plugins/configuration/sgconfig/configproto.h
projects/stargazer/plugins/configuration/sgconfig/parser_services.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser_services.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser_user_info.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser_user_info.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/stgconfig.h
projects/stargazer/plugins/store/files/file_store.cpp
projects/stargazer/plugins/store/files/file_store.h
projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp
projects/stargazer/plugins/store/firebird/firebird_store_users.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp
projects/stargazer/settings_impl.cpp
projects/stargazer/settings_impl.h
projects/stargazer/user_impl.cpp
projects/stargazer/user_impl.h
projects/stargazer/users_impl.cpp
stglibs/common.lib/common.cpp
stglibs/common.lib/include/stg/common.h
stglibs/crypto.lib/include/stg/blowfish.h
stglibs/pinger.lib/Makefile
stglibs/srvconf.lib/Makefile
stglibs/srvconf.lib/include/stg/netunit.h [deleted file]
stglibs/srvconf.lib/include/stg/servconf.h
stglibs/srvconf.lib/include/stg/servconf_types.h [new file with mode: 0644]
stglibs/srvconf.lib/netunit.cpp
stglibs/srvconf.lib/netunit.h [new file with mode: 0644]
stglibs/srvconf.lib/parser.cpp [deleted file]
stglibs/srvconf.lib/parsers/auth_by.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/auth_by.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/base.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_admin.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_admin.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_corp.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_corp.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_service.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_service.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_tariff.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_tariff.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_user.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/chg_user.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_admin.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_admin.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_container.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_corp.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_corp.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_service.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_service.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_tariff.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_tariff.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_user.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/get_user.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/property.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/property.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/resetable_utils.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/server_info.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/server_info.h [new file with mode: 0644]
stglibs/srvconf.lib/parsers/simple.cpp [new file with mode: 0644]
stglibs/srvconf.lib/parsers/simple.h [new file with mode: 0644]
stglibs/srvconf.lib/servconf.cpp
stglibs/srvconf.lib/servconf.vpj [deleted file]
stglibs/srvconf.lib/servconf.vpw [deleted file]

diff --git a/functest/build.sh b/functest/build.sh
new file mode 100755 (executable)
index 0000000..a84e9e0
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+BASEPATH=$1
+
+if [ "$BASEPATH" == "" ]
+then
+    printf "Usage: $0 <path>\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 (executable)
index 0000000..e185a46
--- /dev/null
@@ -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 <path>\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 (executable)
index 0000000..652dbce
--- /dev/null
@@ -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 (file)
index 0000000..a90b9dc
--- /dev/null
@@ -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 (executable)
index 0000000..8feb93c
--- /dev/null
@@ -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 (executable)
index 0000000..d0f5a49
--- /dev/null
@@ -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 (executable)
index 0000000..7c80e5b
--- /dev/null
@@ -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 (file)
index 0000000..bfc6cde
--- /dev/null
@@ -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 (file)
index 0000000..2a6971f
--- /dev/null
@@ -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 (file)
index 0000000..f19c653
--- /dev/null
@@ -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 (file)
index 0000000..d69d07c
--- /dev/null
@@ -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 (file)
index 0000000..ad9faa1
--- /dev/null
@@ -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 (file)
index 0000000..c4e0bd3
--- /dev/null
@@ -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
+
+<DirNames>
+    DirName0 = dir
+    DirName1 = dir2
+    DirName2 = dir3
+    DirName3 =
+    DirName4 =
+    DirName5 = dir5
+    DirName6 =
+    DirName7 =
+    DirName8 =
+    DirName9 =
+</DirNames>
+
+<StoreModule store_files>
+    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
+</StoreModule>
+
+<Modules>
+    <Module auth_ao>
+    </Module>
+
+    <Module conf_sg>
+        Port = 5555
+        BindAddress = localhost
+    </Module>
+</Modules>
diff --git a/functest/test.sh b/functest/test.sh
new file mode 100755 (executable)
index 0000000..a463568
--- /dev/null
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+BASEPATH=$1
+
+source `dirname $0`/functions
+
+if [ "$BASEPATH" == "" ]
+then
+    printf "Usage: $0 <path>\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 (executable)
index 0000000..dae254b
--- /dev/null
@@ -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 (executable)
index 0000000..caf01bc
--- /dev/null
@@ -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 (executable)
index 0000000..0b8a2a8
--- /dev/null
@@ -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"
index f88ab0c8035bef250f5a9d7800bd8c5e03ccbe02..6e073d6fe972765609c25f7c914e60cb4ba36f49 100644 (file)
@@ -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 (file)
index 0000000..8550f16
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __STG_ARRAY_H__
+#define __STG_ARRAY_H__
+
+#include <cstddef> // size_t
+
+namespace STG
+{
+
+template <typename T, size_t S>
+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
index d6cc2ebbe626f5422de591c3f9e47f26d4e97a83..9bbc03d326941e2edce782663cbec4e3cbd15163 100644 (file)
@@ -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 <faust@stargazer.dp.ua>
+ */
+
 #ifndef CORP_CONF_H
 #define CORP_CONF_H
 
+#include "resetable.h"
+
 #include <string>
 
 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<std::string> name;
+RESETABLE<double>      cash;
+};
+
 inline
 bool operator==(const CORP_CONF & a, const CORP_CONF & b)
 {
index 2d07c6c659c704a28c532bec285247608e93ac2d..e167301b5d72fa1cf2fdc480ab13ebbf92728759 100644 (file)
 #ifndef CORPORATIONS_H
 #define CORPORATIONS_H
 
-#include <string>
-
 #include "corp_conf.h"
 
+#include <string>
+
 class ADMIN;
 
 class CORPORATIONS {
index 5987c4d8c6b9d51c93c980877b8b59da0558e7ed..a16b392984454fe0679baad959f7457492068331 100644 (file)
@@ -39,7 +39,7 @@ struct USER_CONF
     std::string              note;
     std::string              realName;
     std::string              corp;
-    std::vector<std::string> service;
+    std::vector<std::string> 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<std::string>               email;
     RESETABLE<std::string>               note;
     RESETABLE<std::string>               realName;
+    RESETABLE<std::string>               corp;
     RESETABLE<std::string>               group;
     RESETABLE<double>                    credit;
     RESETABLE<std::string>               nextTariff;
     std::vector<RESETABLE<std::string> > userdata;
+    RESETABLE<std::vector<std::string> > services;
     RESETABLE<time_t>                    creditExpire;
     RESETABLE<USER_IPS>                  ips;
 };
index 4c06155dfe82e47980a8e60a13341fac9c8be2ab..ff020dc7021195e8d3a921e3b52a72408f0fe6c8 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <ctime>
 #include <map>
+#include <utility>
+#include <string>
 
 #include "os_int.h"
 #include "resetable.h"
@@ -140,6 +142,8 @@ struct USER_STAT
 //-----------------------------------------------------------------------------
 typedef std::map<IP_DIR_PAIR, STAT_NODE> TRAFF_STAT;
 //-----------------------------------------------------------------------------
+typedef std::pair<double, std::string> CASH_INFO;
+//-----------------------------------------------------------------------------
 struct USER_STAT_RES
 {
     USER_STAT_RES()
@@ -186,6 +190,8 @@ struct USER_STAT_RES
     }
 
     RESETABLE<double>      cash;
+    RESETABLE<CASH_INFO>   cashAdd;
+    RESETABLE<CASH_INFO>   cashSet;
     RESETABLE<double>      freeMb;
     RESETABLE<double>      lastCashAdd;
     RESETABLE<time_t>      lastCashAddTime;
index eec4627669f6c8e8ee47797a695a1f0d3caf6304..8ef8e2608f8d3f2f569a7bb8cd4800e57a739b7b 100644 (file)
@@ -80,6 +80,7 @@ return o;
 class DIR_TRAFF_RES
 {
 public:
+    typedef RESETABLE<uint64_t> value_type;
     typedef RESETABLE<uint64_t> ValueType;
     typedef std::vector<ValueType> 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;
index 20538a7f62a1231777b40eb09c05c6e75e44c5ce..fb41a227160498821ccc49bafbe0570b3782e28b 100644 (file)
@@ -22,6 +22,6 @@
 #define __VERSION_H__
 
 // Stargazer version
-#define SERVER_VERSION "2.409"
+#define SERVER_VERSION "2.5"
 
 #endif
index 795c25222d481bfd0de5d88bf1a50c0de693605a..3a64cb6147e9358101bedeed0d8616975233054a 100644 (file)
@@ -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\
index cbdf9acae4bb76a4e1fa8d4daf92ce8baa9716b6..bb2db5b9fc917aa58424845d4af2abc8f27d683a 100644 (file)
@@ -1,3 +1,4 @@
 Compiling:
 > ./build
 
+
diff --git a/projects/sgconf/TODO b/projects/sgconf/TODO
new file mode 100644 (file)
index 0000000..19b51f5
--- /dev/null
@@ -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 (file)
index 0000000..940ea7f
--- /dev/null
@@ -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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_ACTION_H__
+#define __STG_SGCONF_ACTION_H__
+
+#include <string>
+#include <map>
+#include <stdexcept>
+
+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 (file)
index 0000000..afa5162
--- /dev/null
@@ -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 <faust@stargazer.dp.ua>
+ */
diff --git a/projects/sgconf/actions.h b/projects/sgconf/actions.h
new file mode 100644 (file)
index 0000000..08dc177
--- /dev/null
@@ -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 <faust@stargazer.dp.ua>
+ */
+
+#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 <string>
+
+#include <cassert>
+
+namespace SGCONF
+{
+
+typedef void (* FUNC0)();
+
+template <typename F>
+class FUNC0_ACTION : public ACTION
+{
+    public:
+        FUNC0_ACTION(const F & func) : m_func(func) {}
+
+        virtual ACTION * Clone() const { return new FUNC0_ACTION<F>(*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 <typename F>
+inline
+FUNC0_ACTION<F> * MakeFunc0Action(F func)
+{
+return new FUNC0_ACTION<F>(func);
+}
+
+template <typename T>
+class PARAM_ACTION : public ACTION
+{
+    public:
+        PARAM_ACTION(RESETABLE<T> & param,
+                     const T & defaultValue,
+                     const std::string & paramDescription)
+            : m_param(param),
+              m_defaltValue(defaultValue),
+              m_description(paramDescription),
+              m_hasDefault(true)
+        {}
+        PARAM_ACTION(RESETABLE<T> & param)
+            : m_param(param),
+              m_hasDefault(false)
+        {}
+        PARAM_ACTION(RESETABLE<T> & param,
+                     const std::string & paramDescription)
+            : m_param(param),
+              m_description(paramDescription),
+              m_hasDefault(false)
+        {}
+
+        virtual ACTION * Clone() const { return new PARAM_ACTION<T>(*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<T> & m_param;
+        T m_defaltValue;
+        std::string m_description;
+        bool m_hasDefault;
+        OPTION_BLOCK m_suboptions;
+};
+
+template <typename T>
+inline
+std::string PARAM_ACTION<T>::DefaultDescription() const
+{
+return m_hasDefault ? " (default: '" + x2str(m_defaltValue) + "')"
+                    : "";
+}
+
+template <>
+inline
+std::string PARAM_ACTION<std::string>::DefaultDescription() const
+{
+return m_hasDefault ? " (default: '" + m_defaltValue + "')"
+                    : "";
+}
+
+template <typename T>
+inline
+PARSER_STATE PARAM_ACTION<T>::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<bool>::Parse(int argc, char ** argv, void * /*data*/)
+{
+m_param = true;
+return PARSER_STATE(false, argc, argv);
+}
+
+template <typename T>
+inline
+void PARAM_ACTION<T>::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<std::string>::ParseValue(const std::string & stringValue)
+{
+m_param = stringValue;
+}
+
+template <>
+inline
+PARSER_STATE PARAM_ACTION<std::string>::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 <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(RESETABLE<T> & param,
+                                  const T & defaultValue,
+                                  const std::string & paramDescription)
+{
+return new PARAM_ACTION<T>(param, defaultValue, paramDescription);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(RESETABLE<T> & param)
+{
+return new PARAM_ACTION<T>(param);
+}
+
+template <typename T>
+inline
+PARAM_ACTION<T> * MakeParamAction(RESETABLE<T> & param,
+                                  const std::string & paramDescription)
+{
+return new PARAM_ACTION<T>(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<std::string, std::string> & kvs = *static_cast<std::map<std::string, std::string>*>(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 (file)
index 0000000..c16e6e2
--- /dev/null
@@ -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 <iostream>
+#include <string>
+#include <map>
+#include <cassert>
+
+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<SGCONF::API_ACTION::PARAM> GetAdminParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "password"));
+params.push_back(SGCONF::API_ACTION::PARAM("priv", "<priv>", "priviledges"));
+return params;
+}
+
+void ConvPriv(const std::string & value, RESETABLE<PRIV> & 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<STG::GET_ADMIN::INFO> & 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<STG::GET_ADMIN::INFO> & info,
+                      void * data)
+{
+assert(data != NULL && "Expecting pointer to std::string with the admin's login.");
+const std::string & login = *static_cast<const std::string *>(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<std::string, std::string> & /*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<std::string, std::string> & /*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 <GetAdmin login="..."/>.
+// 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<std::string, std::string> & /*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<std::string, std::string> & 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<std::string, std::string> & 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<API_ACTION::PARAM> params(GetAdminParams());
+blocks.Add("Admin management options")
+      .Add("get-admins", SGCONF::MakeAPIAction(commands, GetAdminsFunction), "\tget admin list")
+      .Add("get-admin", SGCONF::MakeAPIAction(commands, "<login>", GetAdminFunction), "get admin")
+      .Add("add-admin", SGCONF::MakeAPIAction(commands, "<login>", params, AddAdminFunction), "add admin")
+      .Add("del-admin", SGCONF::MakeAPIAction(commands, "<login>", DelAdminFunction), "del admin")
+      .Add("chg-admin", SGCONF::MakeAPIAction(commands, "<login>", params, ChgAdminFunction), "change admin");
+}
diff --git a/projects/sgconf/admins.h b/projects/sgconf/admins.h
new file mode 100644 (file)
index 0000000..6bc4738
--- /dev/null
@@ -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 (file)
index 0000000..d5b1e8e
--- /dev/null
@@ -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<PARAM> & params,
+                               API_FUNCTION funPtr)
+    : m_commands(commands),
+      m_description(paramDescription),
+      m_argument(needArgument ? "1" : ""), // Hack
+      m_funPtr(funPtr)
+{
+std::vector<PARAM>::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 (file)
index 0000000..f27715c
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef __STG_SGCONF_API_ACTION_H__
+#define __STG_SGCONF_API_ACTION_H__
+
+#include "action.h"
+
+#include "options.h"
+
+#include <string>
+#include <map>
+#include <vector>
+
+namespace SGCONF
+{
+
+typedef bool (* API_FUNCTION) (const CONFIG &,
+                               const std::string &,
+                               const std::map<std::string, std::string> &);
+
+class COMMAND
+{
+    public:
+        COMMAND(API_FUNCTION funPtr,
+                const std::string & arg,
+                const std::map<std::string, std::string> & 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<std::string, std::string> m_options;
+};
+
+class COMMANDS
+{
+    public:
+        void Add(API_FUNCTION funPtr,
+                 const std::string & arg,
+                 const std::map<std::string, std::string> & options) { m_commands.push_back(COMMAND(funPtr, arg, options)); }
+        bool Execute(const SGCONF::CONFIG & config) const
+        {
+            std::vector<COMMAND>::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<COMMAND> 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<PARAM> & 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<std::string, std::string> m_params;
+        API_FUNCTION m_funPtr;
+};
+
+inline
+ACTION * MakeAPIAction(COMMANDS & commands,
+                       const std::string & paramDescription,
+                       const std::vector<API_ACTION::PARAM> & params,
+                       API_FUNCTION funPtr)
+{
+return new API_ACTION(commands, paramDescription, true, params, funPtr);
+}
+
+inline
+ACTION * MakeAPIAction(COMMANDS & commands,
+                       const std::vector<API_ACTION::PARAM> & 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 (file)
index 9c1b728..0000000
+++ /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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: faust $
- $Revision: 1.12 $
- $Date: 2009/06/08 10:02:28 $
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <locale.h>
-#include <langinfo.h>
-#include <iostream>
-#include <iconv.h>
-
-#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 <server> -p <port> -a <admin> -w <admin_pass> -u <user> -c <add_cash[:log message]>\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -v <set_cash[:log message]>\n");
-printf("To get cash use:\n");
-printf("sgconf get -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -c\n\n");
-
-HelpParams hp[] =
-{
-    {"set tariff",              "get tariff",           "-t",   "<tariff:now|delayed>"},
-    {"set credit",              "get credit",           "-r",   "<credit>"},
-    {"set credit expire",       "get credit expire",    "-E",   "<credit_expire_date>"},
-    {"set password",            "get password",         "-o",   "<new_password>"},
-    {"set prepaid traffic",     "get prepaid traffic",  "-e",   "<prepaid>"},
-    {"set IP-addresses",       "get IP-addresses",     "-I",   "<*|ip_addr[,ip_addr...]>"},
-    {"set name",                "get name",             "-A",   "<name>"},
-    {"set note",                "get note",             "-N",   "<note>"},
-    {"set street address",      "get street address",   "-D",   "<address>"},
-    {"set email",               "get email",            "-L",   "<email>"},
-    {"set phone",               "get phone",            "-P",   "<phone>"},
-    {"set group",               "get group",            "-G",   "<group>"},
-    {"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 <server> -p <port> -a <admin> -w <admin_pass> -u <user> %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 <server> -p <port> -a <admin> -w <admin_pass> -u <user> %s\n\n",
-           hp[i].valueName.c_str());
-    }
-
-printf("To set user\'s upload traffic value use:\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --u0 <traff> [--u1<traff> ...]\n");
-printf("To get user\'s upload traffic value use:\n");
-printf("sgconf get -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --u0 [--u1 ...]\n\n");
-
-printf("To set user\'s download traffic value use:\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --d0 <traff> [--d1<traff> ...]\n");
-printf("To get user\'s download traffic value use:\n");
-printf("sgconf get -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --d0 [--d1 ...]\n\n");
-
-printf("To set userdata<0...9> use:\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --ud0 <userdata> [--ud1<userdata> ...]\n");
-printf("To get userdata<0...9> use:\n");
-printf("sgconf get -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --ud0 [--ud1 ...]\n\n");
-
-printf("To get user's authorizers list use:\n");
-printf("sgconf get -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> --authorized-by\n\n");
-
-printf("To send message use:\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -m <message>\n\n");
-
-printf("To create user use:\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -n\n\n");
-
-printf("To delete user use:\n");
-printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -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<string> 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<std::string> & list, void * d)
-{
-AuthByCbData * abcbd;
-abcbd = (AuthByCbData *)d;
-
-bool * result = abcbd->result;
-
-for (std::vector<std::string>::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 (file)
index a5cbffa..0000000
+++ /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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: faust $
- $Revision: 1.5 $
- $Date: 2009/06/08 10:02:28 $
- */
-
-
-#ifndef COMMON_SG_H
-#define COMMON_SG_H
-
-#include <string>
-
-#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 (file)
index 0000000..d3659a1
--- /dev/null
@@ -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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_CONFIG_H__
+#define __STG_SGCONF_CONFIG_H__
+
+#include "stg/common.h"
+#include "stg/resetable.h"
+#include "stg/os_int.h"
+
+#include <string>
+
+namespace SGCONF
+{
+
+struct CONFIG
+{
+    RESETABLE<std::string> configFile;
+    RESETABLE<std::string> server;
+    RESETABLE<uint16_t> port;
+    RESETABLE<std::string> localAddress;
+    RESETABLE<uint16_t> localPort;
+    RESETABLE<std::string> userName;
+    RESETABLE<std::string> userPass;
+    RESETABLE<bool> 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 (file)
index 0000000..4bd436d
--- /dev/null
@@ -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 <iostream>
+#include <string>
+#include <map>
+
+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<SGCONF::API_ACTION::PARAM> GetCorpParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("cash", "<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<STG::GET_CORP::INFO> & 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<std::string, std::string> & /*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<std::string, std::string> & /*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<std::string, std::string> & /*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<std::string, std::string> & 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<std::string, std::string> & 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<API_ACTION::PARAM> params(GetCorpParams());
+blocks.Add("Corporation management options")
+      .Add("get-corps", SGCONF::MakeAPIAction(commands, GetCorpsFunction), "\tget corporation list")
+      .Add("get-corp", SGCONF::MakeAPIAction(commands, "<name>", GetCorpFunction), "get corporation")
+      .Add("add-corp", SGCONF::MakeAPIAction(commands, "<name>", params, AddCorpFunction), "add corporation")
+      .Add("del-corp", SGCONF::MakeAPIAction(commands, "<name>", DelCorpFunction), "delete corporation")
+      .Add("chg-corp", SGCONF::MakeAPIAction(commands, "<name>", params, ChgCorpFunction), "change corporation");
+}
diff --git a/projects/sgconf/corps.h b/projects/sgconf/corps.h
new file mode 100644 (file)
index 0000000..de823b7
--- /dev/null
@@ -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 (file)
index 0000000..0e98d3d
--- /dev/null
@@ -0,0 +1,60 @@
+#include "info.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+
+#include "stg/servconf.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+#include <expat.h>
+
+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<std::string, std::string> & /*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 (file)
index 0000000..86e4a9e
--- /dev/null
@@ -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 <faust@stargazer.dp.ua>
+ */
+
+#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
index b107ee9515c1265e589ebfcd6924c8fc3ac77143..979081953464c40316b60c8b9708bef2098499a5 100644 (file)
 
 /*
  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
- /*
- $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 <unistd.h>
-#include <getopt.h>
-#include <iconv.h>
-#include <langinfo.h>
+#include "api_action.h"
+#include "options.h"
+#include "actions.h"
+#include "config.h"
 
-#include <cerrno>
-#include <clocale>
-#include <cstdio>
-#include <cstring>
 #include <string>
-#include <list>
-#include <sstream>
-
-#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<string> * ans);
-//int ParseReplySet(void * data, list<string> * 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 <iostream>
 
-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 <cstdlib> // getenv
+#include <cstring> // 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 <unistd.h> // access
+#include <libgen.h> // 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 <typename T>
+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 <typename F>
+class binder0 : public nullary_function<typename F::result_type>
 {
-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 <typename F>
+inline
+binder0<F> 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<F>(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 <typename A, typename R>
+class FUNC1_ADAPTER : public std::unary_function<A, R>
 {
-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 <typename C, typename A, typename R>
+class METHOD1_ADAPTER : public std::unary_function<A, R>
 {
-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 <typename C, typename A, typename R>
+class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
 {
-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 <typename A, typename R>
+FUNC1_ADAPTER<A, R> Func1Adapt(R (func)(A))
+{
+return FUNC1_ADAPTER<A, R>(func);
+}
 
-size_t nconv = 1;
+template <typename C, typename A, typename R>
+METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
+{
+return METHOD1_ADAPTER<C, A, R>(func, obj);
+}
 
-size_t insize = strlen(ib);
-size_t outsize = strlen(ib);
+template <typename C, typename A, typename R>
+CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
+{
+return CONST_METHOD1_ADAPTER<C, A, R>(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<std::string> 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<std::string>::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, "<Message login=\"%s\" msgver=\"1\" msgtype=\"1\" repeat=\"0\" repeatperiod=\"0\" showtime=\"0\" text=\"%s\"/>", req->login.const_data().c_str(), msg.c_str());
-    //sprintf(str, "<message login=\"%s\" priority=\"0\" text=\"%s\"/>\n", req->login, msg);
-    strcat(r, str);
-    return;
-    }
-
-if (req->deleteUser)
-    {
-    sprintf(str, "<DelUser login=\"%s\"/>", req->login.const_data().c_str());
-    strcat(r, str);
-    //printf("%s\n", r);
-    return;
-    }
-
-if (req->createUser)
-    {
-    sprintf(str, "<AddUser> <login value=\"%s\"/> </AddUser>", req->login.const_data().c_str());
-    strcat(r, str);
-    //printf("%s\n", r);
-    return;
-    }
-
-strcat(r, "<SetUser>\n");
-sprintf(str, "<login value=\"%s\"/>\n", req->login.const_data().c_str());
-strcat(r, str);
-if (!req->credit.empty())
-    {
-    sprintf(str, "<credit value=\"%f\"/>\n", req->credit.const_data());
-    strcat(r, str);
-    }
-
-if (!req->creditExpire.empty())
-    {
-    sprintf(str, "<creditExpire value=\"%ld\"/>\n", req->creditExpire.const_data());
-    strcat(r, str);
-    }
+namespace SGCONF
+{
 
-if (!req->prepaidTraff.empty())
-    {
-    sprintf(str, "<FreeMb value=\"%f\"/>\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, "<cash add=\"%f\" msg=\"%s\"/>\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, "<cash set=\"%f\" msg=\"%s\"/>\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, "<password value=\"%s\" />\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, "<down value=\"%d\" />\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, "<passive value=\"%d\" />\n", req->passive.const_data());
-    strcat(r, str);
-    }
 
-if (!req->disableDetailStat.empty())
-    {
-    sprintf(str, "<disableDetailStat value=\"%d\" />\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, "<aonline value=\"%d\" />\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, "<ip value=\"%s\" />\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, "<traff ");
-            strcat(r, str);
-            uPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->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, "<traff ");
-            strcat(r, str);
-            dPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->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, "<tariff now=\"%s\"/>\n", req->tariff.const_data().c_str());
-            strcat(r, str);
-            break;
-        case TARIFF_REC:
-            sprintf(str, "<tariff recalc=\"%s\"/>\n", req->tariff.const_data().c_str());
-            strcat(r, str);
-            break;
-        case TARIFF_DEL:
-            sprintf(str, "<tariff delayed=\"%s\"/>\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 value=\"%s\"/>", 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 value=\"%s\"/>", 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 value=\"%s\"/>", 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 value=\"%s\"/>", email.c_str());
-    strcat(r, str);
-    }
+} // namespace SGCONF
 
-if (!req->phone.empty())
-    {
-    string phone;
-    Encode12str(phone, req->phone.const_data());
-    sprintf(str, "<phone value=\"%s\"/>", 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"), "<config file>"), "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"), "<address>"), "\t\thost to connect")
+      .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "\t\tport to connect")
+      .Add("local-address", SGCONF::MakeParamAction(config.localAddress, std::string(""), "<address>"), "\tlocal address to bind")
+      .Add("local-port", SGCONF::MakeParamAction(config.localPort, uint16_t(0), "<port>"), "\t\tlocal port to bind")
+      .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "\tadministrative login")
+      .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "\tpassword for the administrative login")
+      .Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
+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 value=\"%s\"/>", 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, "<userdata%d value=\"%s\"/>", i, ud.c_str());
-        strcat(r, str);
-        }
+    std::cerr << "Unknown option: '" << *state.argv << "'\n";
+    return -1;
     }
 
-strcat(r, "</SetUser>\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<string>   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 <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 <name>\t\t\tname of the tariff to add\n"
+              << "\t\t--fee <fee>\t\t\tstariff's fee\n"
+              << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
+              << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
+              << "\t\t--traff-type <type>\t\twhat type of traffi will be accounted by the tariff\n"
+              << "\t\t--times <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 <prices>\t\tslash-separated list of prices for \"day\" traffic before threshold for each direction\n"
+              << "\t\t--prices-night-a <prices>\tslash-separated list of prices for \"night\" traffic before threshold for each direction\n"
+              << "\t\t--prices-day-b <prices>\t\tslash-separated list of prices for \"day\" traffic after threshold for each direction\n"
+              << "\t\t--prices-night-b <prices>\tslash-separated list of prices for \"night\" traffic after threshold for each direction\n"
+              << "\t\t--single-prices <yes|no>\tslash-separated list of \"single price\" flags for each direction\n"
+              << "\t\t--no-discounts <yes|no>\t\tslash-separated list of \"no discount\" flags for each direction\n"
+              << "\t\t--thresholds <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 <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 <name>\t\t\tname of the tariff to change\n"
+              << "\t\t--fee <fee>\t\t\tstariff's fee\n"
+              << "\t\t--free <free>\t\t\ttariff's prepaid traffic in terms of cost\n"
+              << "\t\t--passive-cost <cost>\t\ttariff's cost of \"freeze\"\n"
+              << "\t\t--traff-type <type>\t\twhat type of traffix will be accounted by the tariff\n"
+              << "\t\t--dir <N>\t\t\tnumber of direction data to change\n"
+              << "\t\t\t--time <time>\t\t\"day\" time-span (in form \"hh:mm-hh:mm\")\n"
+              << "\t\t\t--price-day-a <price>\tprice for \"day\" traffic before threshold\n"
+              << "\t\t\t--price-night-a <price>\tprice for \"night\" traffic before threshold\n"
+              << "\t\t\t--price-day-b <price>\tprice for \"day\" traffic after threshold\n"
+              << "\t\t\t--price-night-b <price>\tprice for \"night\" traffic after threshold\n"
+              << "\t\t\t--single-price <yes|no>\t\"single price\" flag\n"
+              << "\t\t\t--no-discount <yes|no>\t\"no discount\" flag\n"
+              << "\t\t\t--threshold <threshold>\tthreshold (in Mb)\n\n";
 }
 //-----------------------------------------------------------------------------
-int mainSet(int argc, char **argv)
+void UsageUsers(bool full)
 {
-string str;
-
-int c;
-bool isMessage = false;
-REQUEST req;
-
-RESETABLE<string>   t1;
-
-const char * short_options_set = "s:p:a:w:u:c:r:t:m:o:d:i:e:v:nlN:A:D:L:P:G:I:S:O:E:";
-
-int missedOptionArg = false;
-
-while (1)
-    {
-    int option_index = -1;
-
-    c = getopt_long(argc, argv, short_options_set, long_options_set, &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 = ParsePassword(optarg);
-            break;
-
-        case 'u': //user
-            req.login = ParseUser(optarg);
-            break;
-
-        case 'c': //add cash
-            req.cash = ParseCash(optarg, &req.message);
-            break;
-
-        case 'v': //set cash
-            req.setCash = ParseCash(optarg, &req.message);
-            break;
-
-        case 'r': //credit
-            req.credit = ParseCredit(optarg);
-            break;
-
-        case 'E': //credit expire
-            req.creditExpire = ParseCreditExpire(optarg);
-            break;
-
-        case 'd': //down
-            req.down = ParseDownPassive(optarg);
-            break;
-
-        case 'i': //passive
-            req.passive = ParseDownPassive(optarg);
-            break;
-
-        case 't': //tariff
-            req.tariff = ParseTariff(optarg, req.chgTariff);
-            break;
-
-        case 'm': //message
-            ParseAnyString(optarg, &str);
-            req.usrMsg = str;
-            isMessage = true;
-            break;
-
-        case 'e': //Prepaid Traffic
-            req.prepaidTraff = ParsePrepaidTraffic(optarg);
-            break;
-
-        case 'n': //Create User
-            req.createUser = true;
-            break;
-
-        case 'l': //Delete User
-            req.deleteUser = true;
-            break;
-
-        case 'N': //Note
-            ParseAnyString(optarg, &str, "koi8-ru");
-            req.note = str;
-            break;
-
-        case 'A': //nAme
-            ParseAnyString(optarg, &str, "koi8-ru");
-            req.name = str;
-            break;
-
-        case 'D': //aDdress
-            ParseAnyString(optarg, &str, "koi8-ru");
-            req.address = str;
-            break;
-
-        case 'L': //emaiL
-            ParseAnyString(optarg, &str, "koi8-ru");
-            req.email = str;
-            //printf("EMAIL=%s\n", optarg);
-            break;
-
-        case 'P': //phone
-            ParseAnyString(optarg, &str, "koi8-ru");
-            req.phone = str;
-            break;
-
-        case 'G': //Group
-            ParseAnyString(optarg, &str, "koi8-ru");
-            req.group = str;
-            break;
-
-        case 'I': //IP-address of user
-            ParseAnyString(optarg, &str);
-            req.ips = str;
-            break;
-
-        case 'S':
-            req.disableDetailStat = ParseDownPassive(optarg);
-            break;
-
-        case 'O':
-            req.alwaysOnline = ParseDownPassive(optarg);
-            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] = ParseTraff(optarg);
-            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] = ParseTraff(optarg);
-            break;
-
-        case 700: //UserData
-        case 701:
-        case 702:
-        case 703:
-        case 704:
-        case 705:
-        case 706:
-        case 707:
-        case 708:
-        case 709:
-            ParseAnyString(optarg, &str, "koi8-ru");
-            //printf("UD%d\n", c - 700);
-            req.ud[c - 700] = str;
-            break;
-
-        case '?':
-            //printf("Missing option argument\n");
-            missedOptionArg = true;
-            break;
-
-        case ':':
-            //printf("Missing option argument\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++]);
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-if (missedOptionArg || !CheckParametersSet(&req))
-    {
-    //printf("Parameter needed\n");
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-const int rLen = 20000;
-char rstr[rLen];
-memset(rstr, 0, rLen);
-
-CreateRequestSet(&req, rstr);
-return ProcessSetUser(req.server.const_data(), req.port.const_data(), req.admLogin.const_data(), req.admPasswd.const_data(), rstr, NULL, isMessage);
+std::cout << "Users management options:\n"
+          << "\t--get-users\t\t\t\tget a list of users (subsequent options will define what to show)\n";
+if (full)
+    std::cout << "\n\n";
+std::cout << "\t--get-user\t\t\t\tget the information about user\n";
+if (full)
+    std::cout << "\n\n";
+std::cout << "\t--add-user\t\t\t\tadd a new user\n";
+if (full)
+    std::cout << "\n\n";
+std::cout << "\t--del-user\t\t\t\tdelete an existing user\n";
+if (full)
+    std::cout << "\n\n";
+std::cout << "\t--chg-user\t\t\t\tchange an existing user\n";
+if (full)
+    std::cout << "\n\n";
+std::cout << "\t--check-user\t\t\t\tcheck credentials is valid\n";
+if (full)
+    std::cout << "\n\n";
+std::cout << "\t--send-message\t\t\t\tsend a message to a user\n";
+if (full)
+    std::cout << "\n\n";
 }
 //-----------------------------------------------------------------------------
-int main(int argc, char **argv)
+void UsageServices(bool full)
 {
-if (argc <= 2)
-    {
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-if (strcmp(argv[1], "get") == 0)
-    {
-    //printf("get\n");
-    return mainGet(argc - 1, argv + 1);
-    }
-else if (strcmp(argv[1], "set") == 0)
-    {
-    //printf("set\n");
-    return mainSet(argc - 1, argv + 1);
-    }
-else
-    {
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-return UNKNOWN_ERR_CODE;
+std::cout << "Services management options:\n"
+          << "\t--get-services\t\t\t\tget a list of services (subsequent options will define what to show)\n";
+if (full)
+    std::cout << "\t\t--name\t\t\t\tshow service's name\n"
+              << "\t\t--comment\t\t\tshow a comment to the service\n"
+              << "\t\t--cost\t\t\t\tshow service's cost\n"
+              << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
+std::cout << "\t--get-service\t\t\t\tget the information about service\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the service to show\n"
+              << "\t\t--comment\t\t\tshow a comment to the service\n"
+              << "\t\t--cost\t\t\t\tshow service's cost\n"
+              << "\t\t--pay-day\t\t\tshow service's pay day\n\n";
+std::cout << "\t--add-service\t\t\t\tadd a new service\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the service to add\n"
+              << "\t\t--comment <comment>\t\ta comment to the service\n"
+              << "\t\t--cost <cost>\t\t\tservice's cost\n"
+              << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
+std::cout << "\t--del-service\t\t\t\tdelete an existing service\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the service to delete\n\n";
+std::cout << "\t--chg-service\t\t\t\tchange an existing service\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the service to change\n"
+              << "\t\t--comment <comment>\t\ta comment to the service\n"
+              << "\t\t--cost <cost>\t\t\tservice's cost\n"
+              << "\t\t--pay-day <day>\t\t\tservice's pay day\n\n";
 }
 //-----------------------------------------------------------------------------
-
+void UsageCorporations(bool full)
+{
+std::cout << "Corporations management options:\n"
+          << "\t--get-corporations\t\t\tget a list of corporations (subsequent options will define what to show)\n";
+if (full)
+    std::cout << "\t\t--name\t\t\t\tshow corporation's name\n"
+              << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
+std::cout << "\t--get-corp\t\t\t\tget the information about corporation\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the corporation to show\n"
+              << "\t\t--cash\t\t\t\tshow corporation's cash\n\n";
+std::cout << "\t--add-corp\t\t\t\tadd a new corporation\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the corporation to add\n"
+              << "\t\t--cash <cash>\t\t\tinitial corporation's cash (default: \"0\")\n\n";
+std::cout << "\t--del-corp\t\t\t\tdelete an existing corporation\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the corporation to delete\n\n";
+std::cout << "\t--chg-corp\t\t\t\tchange an existing corporation\n";
+if (full)
+    std::cout << "\t\t--name <name>\t\t\tname of the corporation to change\n"
+              << "\t\t--add-cash <amount>[:<message>]\tadd cash to the corporation's account and optional comment message\n"
+              << "\t\t--set-cash <cash>[:<message>]\tnew corporation's cash and optional comment message\n\n";
+}*/
+
+} // namespace anonymous
diff --git a/projects/sgconf/options.cpp b/projects/sgconf/options.cpp
new file mode 100644 (file)
index 0000000..49e04d6
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "options.h"
+
+#include "action.h"
+#include "parser_state.h"
+
+#include "stg/common.h"
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include <functional>
+#include <algorithm>
+
+#include <unistd.h>
+
+namespace
+{
+
+template <class C>
+void ReadConfigFile(const std::string & filePath, void (C::* callback)(const std::string&, const std::string&), C * obj)
+{
+std::ifstream stream(filePath.c_str());
+std::string line;
+size_t num = 0;
+while (std::getline(stream, line))
+    {
+    ++num;
+    line = Trim(line);
+    std::string::size_type pos = line.find_first_of('#');
+    if (pos != std::string::npos)
+        line = line.substr(0, pos);
+    if (line.empty())
+        continue;
+    pos = line.find_first_of('=');
+    if (pos == std::string::npos)
+        {
+        std::ostringstream error;
+        error << "Bad file format, missing '=' in '" << filePath << ":" << num << "'.";
+        throw std::runtime_error(error.str().c_str());
+        }
+    (obj->*callback)(Trim(line.substr(0, pos)), Trim(line.substr(pos + 1, line.length() - pos - 1)));
+    }
+}
+
+} // namespace anonymous
+
+using SGCONF::OPTION;
+using SGCONF::OPTION_BLOCK;
+using SGCONF::OPTION_BLOCKS;
+using SGCONF::ACTION;
+using SGCONF::PARSER_STATE;
+
+OPTION::OPTION(const std::string & shortName,
+               const std::string & longName,
+               ACTION * action,
+               const std::string & description)
+    : m_shortName(shortName),
+      m_longName(longName),
+      m_action(action),
+      m_description(description)
+{
+}
+
+OPTION::OPTION(const std::string & longName,
+               ACTION * action,
+               const std::string & description)
+    : m_longName(longName),
+      m_action(action),
+      m_description(description)
+{
+}
+
+OPTION::OPTION(const OPTION & rhs)
+    : m_shortName(rhs.m_shortName),
+      m_longName(rhs.m_longName),
+      m_action(rhs.m_action->Clone()),
+      m_description(rhs.m_description)
+{
+}
+
+OPTION::~OPTION()
+{
+delete m_action;
+}
+
+OPTION & OPTION::operator=(const OPTION & rhs)
+{
+m_shortName = rhs.m_shortName;
+m_longName = rhs.m_longName;
+m_action = rhs.m_action->Clone();
+m_description = rhs.m_description;
+return *this;
+}
+
+void OPTION::Help(size_t level) const
+{
+if (!m_action)
+    throw ERROR("Option is not defined.");
+std::string indent(level, '\t');
+std::cout << indent;
+if (!m_shortName.empty())
+    std::cout << "-" << m_shortName << ", ";
+std::cout << "--" << m_longName << " " << m_action->ParamDescription()
+          << "\t" << m_description << m_action->DefaultDescription() << "\n";
+m_action->Suboptions().Help(level);
+}
+
+bool OPTION::Check(const char * arg) const
+{
+if (arg == NULL)
+    return false;
+
+if (*arg++ != '-')
+    return false;
+
+if (*arg == '-')
+{
+    return m_longName == arg + 1;
+}
+
+return m_shortName == arg;
+}
+
+PARSER_STATE OPTION::Parse(int argc, char ** argv, void * data)
+{
+if (!m_action)
+    throw ERROR("Option is not defined.");
+try
+    {
+    return m_action->Parse(argc, argv, data);
+    }
+catch (const ACTION::ERROR & ex)
+    {
+    if (m_longName.empty())
+        throw ERROR("-" + m_shortName + ": " + ex.what());
+    else
+        throw m_shortName.empty() ? ERROR("--" + m_longName + ": " + ex.what())
+                                  : ERROR("--" + m_longName + ", -" + m_shortName + ": " + ex.what());
+    }
+}
+
+void OPTION::ParseValue(const std::string & value)
+{
+if (!m_action)
+    throw ERROR("Option is not defined.");
+try
+    {
+    return m_action->ParseValue(value);
+    }
+catch (const ACTION::ERROR & ex)
+    {
+    throw ERROR(m_longName + ": " + ex.what());
+    }
+}
+
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & shortName,
+                                 const std::string & longName,
+                                 ACTION * action,
+                                 const std::string & description)
+{
+m_options.push_back(OPTION(shortName, longName, action, description));
+return *this;
+}
+
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & longName,
+                                 ACTION * action,
+                                 const std::string & description)
+{
+m_options.push_back(OPTION(longName, action, description));
+return *this;
+}
+
+void OPTION_BLOCK::Help(size_t level) const
+{
+if (m_options.empty())
+    return;
+if (!m_description.empty())
+    std::cout << m_description << ":\n";
+std::for_each(m_options.begin(),
+              m_options.end(),
+              std::bind2nd(std::mem_fun_ref(&OPTION::Help), level + 1));
+}
+
+PARSER_STATE OPTION_BLOCK::Parse(int argc, char ** argv, void * data)
+{
+PARSER_STATE state(false, argc, argv);
+if (state.argc == 0)
+    return state;
+while (state.argc > 0 && !state.stop)
+    {
+    std::vector<OPTION>::iterator it = std::find_if(m_options.begin(), m_options.end(), std::bind2nd(std::mem_fun_ref(&OPTION::Check), *state.argv));
+    if (it != m_options.end())
+        state = it->Parse(--state.argc, ++state.argv, data);
+    else
+        break;
+    ++it;
+    }
+return state;
+}
+
+void OPTION_BLOCK::ParseFile(const std::string & filePath)
+{
+if (access(filePath.c_str(), R_OK))
+    throw ERROR("File '" + filePath + "' does not exists.");
+ReadConfigFile(filePath, &OPTION_BLOCK::OptionCallback, this);
+}
+
+void OPTION_BLOCK::OptionCallback(const std::string & key, const std::string & value)
+{
+for (std::vector<OPTION>::iterator it = m_options.begin(); it != m_options.end(); ++it)
+    if (it->Name() == key)
+        it->ParseValue(value);
+}
+
+void OPTION_BLOCKS::Help(size_t level) const
+{
+std::list<OPTION_BLOCK>::const_iterator it(m_blocks.begin());
+while (it != m_blocks.end())
+    {
+    it->Help(level);
+    std::cout << "\n";
+    ++it;
+    }
+}
+
+PARSER_STATE OPTION_BLOCKS::Parse(int argc, char ** argv)
+{
+PARSER_STATE state(false, argc, argv);
+std::list<OPTION_BLOCK>::iterator it(m_blocks.begin());
+while (state.argc > 0 && !state.stop && it != m_blocks.end())
+    {
+    state = it->Parse(state.argc, state.argv);
+    ++it;
+    }
+return state;
+}
diff --git a/projects/sgconf/options.h b/projects/sgconf/options.h
new file mode 100644 (file)
index 0000000..c00707b
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_OPTIONS_H__
+#define __STG_SGCONF_OPTIONS_H__
+
+#include <string>
+#include <vector>
+#include <list>
+#include <utility>
+#include <stdexcept>
+#include <cstddef> // size_t
+
+namespace SGCONF
+{
+
+class ACTION;
+struct PARSER_STATE;
+
+class OPTION
+{
+    public:
+        OPTION(const std::string & shortName,
+               const std::string & longName,
+               ACTION * action,
+               const std::string & description);
+        OPTION(const std::string & longName,
+               ACTION * action,
+               const std::string & description);
+        OPTION(const OPTION & rhs);
+        ~OPTION();
+
+        OPTION & operator=(const OPTION & rhs);
+
+        void Help(size_t level = 0) const;
+        PARSER_STATE Parse(int argc, char ** argv, void * data);
+        void ParseValue(const std::string & value);
+        bool Check(const char * arg) const;
+        const std::string & Name() const { return m_longName; }
+
+        class ERROR : public std::runtime_error
+        {
+            public:
+                ERROR(const std::string & message)
+                    : std::runtime_error(message.c_str()) {}
+        };
+
+    private:
+        std::string m_shortName;
+        std::string m_longName;
+        ACTION * m_action;
+        std::string m_description;
+};
+
+class OPTION_BLOCK
+{
+    public:
+        OPTION_BLOCK() {}
+        OPTION_BLOCK(const std::string & description)
+            : m_description(description) {}
+        OPTION_BLOCK & Add(const std::string & shortName,
+                           const std::string & longName,
+                           ACTION * action,
+                           const std::string & description);
+        OPTION_BLOCK & Add(const std::string & longName,
+                           ACTION * action,
+                           const std::string & description);
+
+        void Help(size_t level) const;
+
+        PARSER_STATE Parse(int argc, char ** argv, void * data = NULL);
+        void ParseFile(const std::string & filePath);
+
+        class ERROR : public std::runtime_error
+        {
+            public:
+                ERROR(const std::string & message)
+                    : std::runtime_error(message.c_str()) {}
+        };
+
+    private:
+        std::vector<OPTION> m_options;
+        std::string m_description;
+
+        void OptionCallback(const std::string & key, const std::string & value);
+};
+
+class OPTION_BLOCKS
+{
+    public:
+        OPTION_BLOCK & Add(const std::string & description)
+        { m_blocks.push_back(OPTION_BLOCK(description)); return m_blocks.back(); }
+        void Add(const OPTION_BLOCK & block) { m_blocks.push_back(block); }
+        void Help(size_t level) const;
+        PARSER_STATE Parse(int argc, char ** argv);
+
+    private:
+        std::list<OPTION_BLOCK> m_blocks;
+};
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/parser.cpp b/projects/sgconf/parser.cpp
deleted file mode 100644 (file)
index 9d340e8..0000000
+++ /dev/null
@@ -1,126 +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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: nobunaga $
- $Revision: 1.4 $
- $Date: 2008/05/11 08:15:07 $
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <expat.h>
-#include <string.h>
-
-#include <string>
-#include <list>
-
-#include "stg/common.h"
-#include "stg/netunit.h"
-#include "stg/request.h"
-
-using namespace std;
-
-int parse_depth = 0;
-XML_Parser parser;
-//---------------------------------------------------------------------------
-int ParseAns(void * data, const char *el, const char **attr)
-{
-if (strcasecmp(attr[1], "ok") == 0)
-    {
-    return 0;
-    }
-if (strcasecmp(attr[1], "error") == 0)
-    {
-    return 1;
-    }
-if (strcasecmp(attr[1], "err") == 0)
-    {
-    return 1;
-    }
-return -1;
-}
-//---------------------------------------------------------------------------
-void StartElement(void *data, const char *el, const char **attr)
-{
-parse_depth++;
-if (parse_depth == 1)
-    {
-    if (ParseAns(data, el, attr) < 0)
-        {
-        printf("Unexpected token\n");
-        exit(UNKNOWN_ERR_CODE);
-        }
-    if (ParseAns(data, el, attr) == 1)
-        {
-        printf("User not found\n");
-        exit(USER_NOT_FOUND_ERR_CODE);
-        }
-    return;
-    }
-}
-//-----------------------------------------------------------------------------
-void EndElement(void *data, const char *el)
-{
-parse_depth--;
-}
-//---------------------------------------------------------------------------
-int ParseReply(void * data, list<string> * ans)
-{
-int done = 0;
-
-parse_depth = 0;
-parser = XML_ParserCreate(NULL);
-
-if (!parser)
-    {
-    printf("Couldn't allocate memory for parser\n");
-    exit(UNKNOWN_ERR_CODE);
-    }
-
-XML_ParserReset(parser, NULL);
-XML_SetElementHandler(parser, StartElement, EndElement);
-
-list<string>::iterator n = ans->begin();
-while (n != ans->end())
-    {
-    size_t len = strlen(n->c_str());
-
-    if (++n == ans->end())
-        done = 1;
-    --n;
-
-    if (XML_Parse(parser, n->c_str(), len, done) == XML_STATUS_ERROR)
-        {
-        printf("Parse error at line %d:\n%s\n",
-               XML_GetCurrentLineNumber(parser),
-               XML_ErrorString(XML_GetErrorCode(parser)));
-        exit(UNKNOWN_ERR_CODE);
-        }
-
-    ++n;
-    }
-
-XML_ParserFree(parser);
-return 0;
-}
-//-----------------------------------------------------------------------------
-
diff --git a/projects/sgconf/parser_state.h b/projects/sgconf/parser_state.h
new file mode 100644 (file)
index 0000000..22ad794
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_PARSER_STATE_H__
+#define __STG_SGCONF_PARSER_STATE_H__
+
+namespace SGCONF
+{
+
+struct PARSER_STATE
+{
+    PARSER_STATE(bool s, int c, char ** v) : stop(s), argc(c), argv(v) {}
+    bool stop;
+    int argc;
+    char ** argv;
+};
+
+}
+
+#endif
diff --git a/projects/sgconf/request.h b/projects/sgconf/request.h
deleted file mode 100644 (file)
index 6122212..0000000
+++ /dev/null
@@ -1,108 +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
- */
-
-/*
- *    Date: 27.10.2002
- */
-
-/*
- *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: faust $
- $Revision: 1.14 $
- $Date: 2009/06/08 10:02:28 $
- */
-
-#ifndef request_h
-#define request_h
-
-#include <string>
-
-#include "stg/resetable.h"
-#include "stg/const.h"
-#include "stg/os_int.h"
-
-#define TARIFF_NOW  (0)
-#define TARIFF_DEL  (1)
-#define TARIFF_REC  (2)
-
-using namespace std;
-//-----------------------------------------------------------------------------
-struct REQUEST
-{
-
-REQUEST()
-    : chgTariff(false),
-      createUser(false),
-      deleteUser(false),
-      authBy(false)
-{
-    for (int i = 0; i < DIR_NUM; i++)
-        {
-        u[i].reset();
-        d[i].reset();
-        }
-
-    for (int i = 0; i < USERDATA_NUM; i++)
-        ud[i].reset();
-}
-
-RESETABLE<string>   server;
-RESETABLE<short>    port;
-RESETABLE<string>   admLogin;
-RESETABLE<string>   admPasswd;
-RESETABLE<string>   login;
-
-RESETABLE<string>   tariff;
-int                 chgTariff;
-
-RESETABLE<double>   cash;
-RESETABLE<double>   setCash;
-string              message;
-bool                createUser;
-bool                deleteUser;
-bool                authBy;
-
-RESETABLE<string>   usrMsg;
-RESETABLE<double>   credit;
-RESETABLE<time_t>   creditExpire;
-RESETABLE<string>   usrPasswd;
-RESETABLE<bool>     down;
-RESETABLE<bool>     passive;
-RESETABLE<bool>     disableDetailStat;
-RESETABLE<bool>     alwaysOnline;
-RESETABLE<double>   prepaidTraff;
-
-RESETABLE<int64_t>  u[DIR_NUM];
-RESETABLE<int64_t>  d[DIR_NUM];
-
-RESETABLE<string>   ud[USERDATA_NUM];
-
-RESETABLE<string>   note;
-RESETABLE<string>   name;
-RESETABLE<string>   address;
-RESETABLE<string>   email;
-RESETABLE<string>   phone;
-RESETABLE<string>   group;
-RESETABLE<string>   ips; // IP-address of user
-};
-//-----------------------------------------------------------------------------
-
-#endif
-
-
diff --git a/projects/sgconf/services.cpp b/projects/sgconf/services.cpp
new file mode 100644 (file)
index 0000000..e2bf9bf
--- /dev/null
@@ -0,0 +1,170 @@
+#include "services.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/service_conf.h"
+#include "stg/common.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+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 PrintService(const STG::GET_SERVICE::INFO & info, size_t level = 0)
+{
+std::cout << Indent(level, true) << "name: " << info.name << "\n"
+          << Indent(level)       << "cost: " << info.cost << "\n"
+          << Indent(level)       << "payment day: " << static_cast<unsigned>(info.payDay) << "\n"
+          << Indent(level)       << "comment: " << info.comment << "\n";
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetServiceParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("cost", "<cost>", "\tcost of the service"));
+params.push_back(SGCONF::API_ACTION::PARAM("pay-day", "<month day>", "payment day"));
+params.push_back(SGCONF::API_ACTION::PARAM("comment", "<text>", "comment"));
+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 GetServicesCallback(bool result,
+                         const std::string & reason,
+                         const std::vector<STG::GET_SERVICE::INFO> & info,
+                         void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get service list. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+std::cout << "Services:\n";
+for (size_t i = 0; i < info.size(); ++i)
+    PrintService(info[i], 1);
+}
+
+void GetServiceCallback(bool result,
+                        const std::string & reason,
+                        const STG::GET_SERVICE::INFO & info,
+                        void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get service. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+PrintService(info);
+}
+
+bool GetServicesFunction(const SGCONF::CONFIG & config,
+                         const std::string & /*arg*/,
+                         const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.GetServices(GetServicesCallback, NULL) == STG::st_ok;
+}
+
+bool GetServiceFunction(const SGCONF::CONFIG & config,
+                        const std::string & arg,
+                        const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.GetService(arg, GetServiceCallback, NULL) == STG::st_ok;
+}
+
+bool DelServiceFunction(const SGCONF::CONFIG & config,
+                        const std::string & arg,
+                        const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.DelService(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddServiceFunction(const SGCONF::CONFIG & config,
+                        const std::string & arg,
+                        const std::map<std::string, std::string> & options)
+{
+SERVICE_CONF_RES conf;
+conf.name = arg;
+SGCONF::MaybeSet(options, "cost", conf.cost);
+SGCONF::MaybeSet(options, "pay-day", conf.payDay);
+SGCONF::MaybeSet(options, "comment", conf.comment);
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.AddService(arg, conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgServiceFunction(const SGCONF::CONFIG & config,
+                        const std::string & arg,
+                        const std::map<std::string, std::string> & options)
+{
+SERVICE_CONF_RES conf;
+conf.name = arg;
+SGCONF::MaybeSet(options, "cost", conf.cost);
+SGCONF::MaybeSet(options, "pay-day", conf.payDay);
+SGCONF::MaybeSet(options, "comment", conf.comment);
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.ChgService(conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendServicesOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetServiceParams());
+blocks.Add("Service management options")
+      .Add("get-services", SGCONF::MakeAPIAction(commands, GetServicesFunction), "\tget service list")
+      .Add("get-service", SGCONF::MakeAPIAction(commands, "<name>", GetServiceFunction), "get service")
+      .Add("add-service", SGCONF::MakeAPIAction(commands, "<name>", params, AddServiceFunction), "add service")
+      .Add("del-service", SGCONF::MakeAPIAction(commands, "<name>", DelServiceFunction), "delete service")
+      .Add("chg-service", SGCONF::MakeAPIAction(commands, "<name>", params, ChgServiceFunction), "change service");
+}
diff --git a/projects/sgconf/services.h b/projects/sgconf/services.h
new file mode 100644 (file)
index 0000000..c504527
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __STG_SGCONF_SERVICES_H__
+#define __STG_SGCONF_SERVICES_H__
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendServicesOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/sg_error_codes.h b/projects/sgconf/sg_error_codes.h
deleted file mode 100644 (file)
index 250bd47..0000000
+++ /dev/null
@@ -1,51 +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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: nobunaga $
- $Revision: 1.2 $
- $Date: 2008/05/11 08:15:08 $
- */
-
-
-
-#ifndef STG_ERROR_CODES_H
-#define STG_ERROR_CODES_H
-
-#ifndef ENODATA
-#define ENODATA 61
-#endif
-
-#ifndef EBADMSG
-#define EBADMSG 74
-#endif
-
-#define NETWORK_ERR_CODE            (1)
-#define LOGIN_OR_PASS_ERR_CODE      (2)
-#define USER_NOT_FOUND_ERR_CODE     (3)
-#define TARIFF_NOT_FOUND_ERR_CODE   (4)
-#define PARAMETER_PARSING_ERR_CODE  (5)
-#define UNKNOWN_ERR_CODE            (6)
-#define ICONV_ERR_CODE              (7)
-
-
-#endif
-
-
diff --git a/projects/sgconf/sgconfg b/projects/sgconf/sgconfg
deleted file mode 100755 (executable)
index fbd3283..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-LD_LIBRARY_PATH=../../lib ./sgconf get -s localhost -p5555 -aadmin -w123456 $*
-
diff --git a/projects/sgconf/sgconfs b/projects/sgconf/sgconfs
deleted file mode 100755 (executable)
index e27108e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-LD_LIBRARY_PATH=../../lib ./sgconf set -s localhost -p5555 -aadmin -w123456 $*
-
diff --git a/projects/sgconf/sginfo.cpp b/projects/sgconf/sginfo.cpp
deleted file mode 100644 (file)
index 6879cb0..0000000
+++ /dev/null
@@ -1,1086 +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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: faust $
- $Revision: 1.3 $
- $Date: 2009/06/22 15:57:49 $
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <iconv.h>
-#include <string>
-#include <list>
-#include <errno.h>
-
-#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<string> * ans);
-int ParseReplySet(void * data, list<string> * 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
-{"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
-
-{0, 0, 0, 0}};
-
-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
-{"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
-
-{"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
-
-{"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
-
-{0, 0, 0, 0}};
-
-//-----------------------------------------------------------------------------
-void CreateRequestGet(REQUEST * req, char * r)
-{
-string r1;
-r1 = "<GetUser login=\"" + req->login.const_data() + "\"/>\n";
-strcpy(r, r1.c_str());
-}
-//-----------------------------------------------------------------------------
-double ParseCash(const char * c, string * message)
-{
-//-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)
-{
-double credit;
-if (strtodouble2(c, credit) != 0)
-    {
-    printf("Incorrect credit value %s\n", c);
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-return credit;
-}
-//-----------------------------------------------------------------------------
-double ParsePrepaidTraffic(const char * c)
-{
-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)
-{
-int64_t traff;
-if (str2x(c, traff) != 0)
-    {
-    printf("Incorrect credit value %s\n", c);
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-return traff;
-}
-//-----------------------------------------------------------------------------
-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)
-{
-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;
-}
-//-----------------------------------------------------------------------------
-void ParseAnyString(const char * c, string * msg)
-{
-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);
-
-char * charsetT = "koi8-ru";
-
-size_t nconv = 1;
-
-size_t insize = strlen(ib);
-size_t outsize = strlen(ib);
-
-insize = strlen(c);
-
-cd = iconv_open(charsetT, charsetF);
-if (cd == (iconv_t) -1)
-    {
-    if (errno == EINVAL)
-        {
-        printf("Warning: iconv from %s to %s failed\n", charsetF, charsetT);
-        *msg = c;
-        return;
-        }
-    else
-        printf("error iconv_open\n");
-
-    exit(ICONV_ERR_CODE);
-    }
-
-nconv = iconv (cd, &inbuf, &insize, &outbuf, &outsize);
-//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);
-*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;
-
-if (!req->usrMsg.res_empty())
-    {
-    int len = req->usrMsg.const_data().length() * 2 + 1;
-    char * msg = new char[len];
-    memset(msg, 0, len);
-    Encode12(msg, req->usrMsg.const_data().c_str(), req->usrMsg.const_data().length());
-
-    sprintf(str, "<Message login=\"%s\" msgver=\"1\" msgtype=\"1\" repeat=\"0\" repeatperiod=\"0\" showtime=\"0\" text=\"%s\"/>", req->login.const_data().c_str(), msg);
-    //sprintf(str, "<message login=\"%s\" priority=\"0\" text=\"%s\"/>\n", req->login, msg);
-    strcat(r, str);
-
-    delete[] msg;
-    return;
-    }
-
-if (req->deleteUser)
-    {
-    sprintf(str, "<DelUser login=\"%s\"/>", req->login.const_data().c_str());
-    strcat(r, str);
-    //printf("%s\n", r);
-    return;
-    }
-
-if (req->createUser)
-    {
-    sprintf(str, "<AddUser> <login value=\"%s\"/> </AddUser>", req->login.const_data().c_str());
-    strcat(r, str);
-    //printf("%s\n", r);
-    return;
-    }
-
-strcat(r, "<SetUser>\n");
-sprintf(str, "<login value=\"%s\"/>\n", req->login.const_data().c_str());
-strcat(r, str);
-if (!req->credit.res_empty())
-    {
-    sprintf(str, "<credit value=\"%f\"/>\n", req->credit.const_data());
-    strcat(r, str);
-    }
-
-if (!req->prepaidTraff.res_empty())
-    {
-    sprintf(str, "<FreeMb value=\"%f\"/>\n", req->prepaidTraff.const_data());
-    strcat(r, str);
-    }
-
-if (!req->cash.res_empty())
-    {
-    int len = req->message.length() * 2 + 1;
-    char * msg = new char[len];
-    memset(msg, 0, len);
-
-    Encode12(msg, req->message.c_str(), req->message.length());
-    sprintf(str, "<cash add=\"%f\" msg=\"%s\"/>\n", req->cash.const_data(), msg);
-    strcat(r, str);
-    delete[] msg;
-    }
-
-if (!req->setCash.res_empty())
-    {
-    int len = req->message.length() * 2 + 1;
-    char * msg = new char[len];
-    memset(msg, 0, len);
-    Encode12(msg, req->message.c_str(), req->message.length());
-    sprintf(str, "<cash set=\"%f\" msg=\"%s\"/>\n", req->setCash.const_data(), msg);
-    strcat(r, str);
-    delete[] msg;
-    }
-
-if (!req->usrPasswd.res_empty())
-    {
-    sprintf(str, "<password value=\"%s\" />\n", req->usrPasswd.const_data().c_str());
-    strcat(r, str);
-    }
-
-if (!req->down.res_empty())
-    {
-    sprintf(str, "<down value=\"%d\" />\n", req->down.const_data());
-    strcat(r, str);
-    }
-
-if (!req->passive.res_empty())
-    {
-    sprintf(str, "<passive value=\"%d\" />\n", req->passive.const_data());
-    strcat(r, str);
-    }
-
-int uPresent = false;
-int dPresent = false;
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (!req->u[i].res_empty())
-        {
-        if (!uPresent && !dPresent)
-            {
-            sprintf(str, "<traff ");
-            strcat(r, str);
-            uPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->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].res_empty())
-        {
-        if (!uPresent && !dPresent)
-            {
-            sprintf(str, "<traff ");
-            strcat(r, str);
-            dPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->d[i].const_data();
-        sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str());
-        strcat(r, str);
-        }
-    }
-if (uPresent || dPresent)
-    {
-    strcat(r, "/>");
-    }
-
-//printf("%s\n", r);
-
-if (!req->tariff.res_empty())
-    {
-    switch (req->chgTariff)
-        {
-        case TARIFF_NOW:
-            sprintf(str, "<tariff now=\"%s\"/>\n", req->tariff.const_data().c_str());
-            strcat(r, str);
-            break;
-        case TARIFF_REC:
-            sprintf(str, "<tariff recalc=\"%s\"/>\n", req->tariff.const_data().c_str());
-            strcat(r, str);
-            break;
-        case TARIFF_DEL:
-            sprintf(str, "<tariff delayed=\"%s\"/>\n", req->tariff.const_data().c_str());
-            strcat(r, str);
-            break;
-        }
-
-    }
-
-if (!req->note.res_empty())
-    {
-    int len = req->note.const_data().length() * 2 + 1;
-    char * note = new char[len];
-    memset(note, 0, len);
-
-    Encode12(note, req->note.const_data().c_str(), req->note.const_data().length());
-
-    sprintf(str, "<note value=\"%s\"/>", note);
-    strcat(r, str);
-    delete[] note;
-    }
-
-if (!req->name.res_empty())
-    {
-    int len = req->note.const_data().length() * 2 + 1;
-    char * name = new char[len];
-    memset(name, 0, len);
-
-    Encode12(name, req->name.const_data().c_str(), req->name.const_data().length());
-
-    sprintf(str, "<name value=\"%s\"/>", name);
-    strcat(r, str);
-    delete[] name;
-    }
-
-if (!req->address.res_empty())
-    {
-    int len = req->note.const_data().length() * 2 + 1;
-    char * address = new char[len];
-    memset(address, 0, len);
-
-    Encode12(address, req->address.const_data().c_str(), req->address.const_data().length());
-
-    sprintf(str, "<address value=\"%s\"/>", address);
-    strcat(r, str);
-    delete[] address;
-    }
-
-if (!req->email.res_empty())
-    {
-    int len = req->note.const_data().length() * 2 + 1;
-    char * email = new char[len];
-    memset(email, 0, len);
-
-    Encode12(email, req->email.const_data().c_str(), req->email.const_data().length());
-
-    sprintf(str, "<email value=\"%s\"/>", email);
-    strcat(r, str);
-    delete[] email;
-    }
-
-if (!req->phone.res_empty())
-    {
-    int len = req->note.const_data().length() * 2 + 1;
-    char * phone = new char[len];
-    memset(phone, 0, len);
-
-    Encode12(phone, req->phone.const_data().c_str(), req->phone.const_data().length());
-
-    sprintf(str, "<phone value=\"%s\"/>", phone);
-    strcat(r, str);
-    delete[] phone;
-    }
-
-if (!req->group.res_empty())
-    {
-    int len = req->note.const_data().length() * 2 + 1;
-    char * group = new char[len];
-    memset(group, 0, len);
-
-    Encode12(group, req->group.const_data().c_str(), req->group.const_data().length());
-
-    sprintf(str, "<group value=\"%s\"/>", group);
-    strcat(r, str);
-    delete[] group;
-    }
-
-for (int i = 0; i < USERDATA_NUM; i++)
-    {
-    if (!req->ud[i].res_empty())
-        {
-        int len = req->ud[i].const_data().length() * 2 + 1;
-        char * ud = new char[len];
-        memset(ud, 0, len);
-
-        Encode12(ud, req->ud[i].const_data().c_str(), req->ud[i].const_data().length());
-
-        sprintf(str, "<userdata%d value=\"%s\"/>", i, ud);
-        strcat(r, str);
-        delete[] ud;
-        }
-    }
-
-strcat(r, "</SetUser>\n");
-}
-//-----------------------------------------------------------------------------
-int CheckParameters(REQUEST * req)
-{
-int u = false;
-int d = false;
-int ud = false;
-int a = !req->admLogin.res_empty()
-    && !req->admPasswd.res_empty()
-    && !req->server.res_empty()
-    && !req->port.res_empty()
-    && !req->login.res_empty();
-
-int b = !req->cash.res_empty()
-    || !req->setCash.res_empty()
-    || !req->credit.res_empty()
-    || !req->prepaidTraff.res_empty()
-    || !req->tariff.res_empty()
-    || !req->usrMsg.res_empty()
-    || !req->usrPasswd.res_empty()
-
-    || !req->note.res_empty()
-    || !req->name.res_empty()
-    || !req->address.res_empty()
-    || !req->email.res_empty()
-    || !req->phone.res_empty()
-    || !req->group.res_empty();
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->u[i].res_empty())
-        {
-        u = true;
-        break;
-        }
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->d[i].res_empty())
-        {
-        d = true;
-        break;
-        }
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->ud[i].res_empty())
-        {
-        ud = true;
-        break;
-        }
-    }
-
-
-//printf("a=%d, b=%d, u=%d, d=%d ud=%d\n", a, b, u, d, ud);
-return a && (b || u || d || ud);
-}
-//-----------------------------------------------------------------------------
-int CheckParametersGet(REQUEST * req)
-{
-return CheckParameters(req);
-}
-//-----------------------------------------------------------------------------
-int CheckParametersSet(REQUEST * req)
-{
-return CheckParameters(req);
-}
-//-----------------------------------------------------------------------------
-int mainGet(int argc, char **argv)
-{
-int c;
-REQUEST req;
-RESETABLE<string>   t1;
-
-char * short_options_get = "s:p:a:w:u:crtmodieNADLPG";
-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 = ParsePassword(optarg);
-            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 '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 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 '?':
-            //printf ("Unknown option \n");
-            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 (CheckParametersGet(&req) == 0)
-    {
-    //printf("Parameter needed\n");
-    UsageInfo();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-
-const int rLen = 20000;
-char rstr[rLen];
-memset(rstr, 0, rLen);
-
-CreateRequestGet(&req, rstr);
-Process(req.server, req.port, req.admLogin, req.admPasswd, rstr, ParseReplyGet);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int mainSet(int argc, char **argv)
-{
-string str;
-
-int c;
-REQUEST req;
-
-RESETABLE<string>   t1;
-
-char * short_options_set = "s:p:a:w:u:c:r:t:m:o:d:i:e:v:nlN:A:D:L:P:G:";
-
-while (1)
-    {
-    int option_index = -1;
-
-    c = getopt_long(argc, argv, short_options_set, long_options_set, &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 = ParsePassword(optarg);
-            break;
-
-        case 'u': //user
-            req.login = ParseUser(optarg);
-            break;
-
-        case 'c': //add cash
-            req.cash = ParseCash(optarg, &req.message);
-            break;
-
-        case 'v': //set cash
-            req.setCash = ParseCash(optarg, &req.message);
-            break;
-
-        case 'r': //credit
-            req.credit = ParseCredit(optarg);
-            break;
-
-        case 'd': //down
-            req.down = ParseDownPassive(optarg);
-            break;
-
-        case 'i': //passive
-            req.passive = ParseDownPassive(optarg);
-            break;
-
-        case 't': //tariff
-            req.tariff = ParseTariff(optarg, req.chgTariff);
-            break;
-
-        case 'm': //message
-            //ParseMessage(optarg, &req.usrMsg);
-            req.usrMsg = optarg;
-            break;
-
-        case 'e': //Prepaid Traffic
-            req.prepaidTraff = ParsePrepaidTraffic(optarg);
-            break;
-
-        case 'n': //Create User
-            req.createUser = true;
-            break;
-
-        case 'l': //Delete User
-            req.deleteUser = true;
-            break;
-
-        case 'N': //Note
-            ParseAnyString(optarg, &str);
-            req.note = str;
-            break;
-
-        case 'A': //nAme
-            ParseAnyString(optarg, &str);
-            req.name = str;
-            break;
-
-        case 'D': //aDdress
-            ParseAnyString(optarg, &str);
-            req.address = str;
-            break;
-
-        case 'L': //emaiL
-            ParseAnyString(optarg, &str);
-            req.email = str;
-            break;
-
-        case 'P': //phone
-            ParseAnyString(optarg, &str);
-            req.phone = str;
-            break;
-
-        case 'G': //Group
-            ParseAnyString(optarg, &str);
-            req.group = str;
-            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] = ParseTraff(optarg);
-            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] = ParseTraff(optarg);
-            break;
-
-        case 700: //UserData
-        case 701:
-        case 702:
-        case 703:
-        case 704:
-        case 705:
-        case 706:
-        case 707:
-        case 708:
-        case 709:
-            ParseAnyString(optarg, &str);
-            //printf("UD%d\n", c - 700);
-            req.ud[c - 700] = str;
-            break;
-
-        case '?':
-            //printf ("Unknown option \n");
-            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++]);
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-if (CheckParametersSet(&req) == 0)
-    {
-    //printf("Parameter needed\n");
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-const int rLen = 20000;
-char rstr[rLen];
-memset(rstr, 0, rLen);
-
-CreateRequestGet(&req, rstr);
-Process(req.server, req.port, req.admLogin, req.admPasswd, rstr, ParseReplySet);
-//Process(&req);
-
-return 0;
-}
-//-----------------------------------------------------------------------------
-int main(int argc, char **argv)
-{
-if (argc <= 2)
-    {
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-if (strcmp(argv[1], "get"))
-    {
-    return mainGet(argc - 1, argv + 1);
-    }
-else if (strcmp(argv[1], "set"))
-    {
-    return mainGet(argc - 1, argv + 1);
-    }
-else
-    {
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-return UNKNOWN_ERR_CODE;
-}
-//-----------------------------------------------------------------------------
-
diff --git a/projects/sgconf/tariffs.cpp b/projects/sgconf/tariffs.cpp
new file mode 100644 (file)
index 0000000..6ab4e87
--- /dev/null
@@ -0,0 +1,449 @@
+#include "tariffs.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/tariff_conf.h"
+#include "stg/common.h"
+#include "stg/os_int.h"
+
+#include <iostream>
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <map>
+#include <cassert>
+
+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 ChangePolicyToString(TARIFF::CHANGE_POLICY changePolicy)
+{
+switch (changePolicy)
+    {
+    case TARIFF::ALLOW: return "allow";
+    case TARIFF::TO_CHEAP: return "to_cheap";
+    case TARIFF::TO_EXPENSIVE: return "to_expensive";
+    case TARIFF::DENY: return "deny";
+    }
+return "unknown";
+}
+
+std::string PeriodToString(TARIFF::PERIOD period)
+{
+switch (period)
+    {
+    case TARIFF::DAY:
+        return "daily";
+    case TARIFF::MONTH:
+        return "monthly";
+    }
+return "unknown";
+}
+
+std::string TraffTypeToString(TARIFF::TRAFF_TYPE traffType)
+{
+switch (traffType)
+    {
+    case TARIFF::TRAFF_UP:
+        return "upload";
+    case TARIFF::TRAFF_DOWN:
+        return "download";
+    case TARIFF::TRAFF_UP_DOWN:
+        return "upload + download";
+    case TARIFF::TRAFF_MAX:
+        return "max(upload, download)";
+    }
+return "unknown";
+}
+
+void ConvPeriod(const std::string & value, RESETABLE<TARIFF::PERIOD> & res)
+{
+std::string lowered = ToLower(value);
+if (lowered == "daily")
+    res = TARIFF::DAY;
+else if (lowered == "monthly")
+    res = TARIFF::MONTH;
+else
+    throw SGCONF::ACTION::ERROR("Period should be 'daily' or 'monthly'. Got: '" + value + "'");
+}
+
+void ConvChangePolicy(const std::string & value, RESETABLE<TARIFF::CHANGE_POLICY> & res)
+{
+std::string lowered = ToLower(value);
+if (lowered == "allow")
+    res = TARIFF::ALLOW;
+else if (lowered == "to_cheap")
+    res = TARIFF::TO_CHEAP;
+else if (lowered == "to_expensive")
+    res = TARIFF::TO_EXPENSIVE;
+else if (lowered == "deny")
+    res = TARIFF::DENY;
+else
+    throw SGCONF::ACTION::ERROR("Change policy should be 'allow', 'to_cheap', 'to_expensive' or 'deny'. Got: '" + value + "'");
+}
+
+void ConvChangePolicyTimeout(const std::string & value, RESETABLE<time_t> & res)
+{
+struct tm brokenTime;
+if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
+    throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
+res = stg_timegm(&brokenTime);
+}
+
+void ConvTraffType(const std::string & value, RESETABLE<TARIFF::TRAFF_TYPE> & res)
+{
+std::string lowered = ToLower(value);
+lowered.erase(std::remove(lowered.begin(), lowered.end(), ' '), lowered.end());
+if (lowered == "upload")
+    res = TARIFF::TRAFF_UP;
+else if (lowered == "download")
+    res = TARIFF::TRAFF_DOWN;
+else if (lowered == "upload+download")
+    res = TARIFF::TRAFF_UP_DOWN;
+else if (lowered.substr(0, 3) == "max")
+    res = TARIFF::TRAFF_MAX;
+else
+    throw SGCONF::ACTION::ERROR("Traff type should be 'upload', 'download', 'upload + download' or 'max'. Got: '" + value + "'");
+}
+
+DIRPRICE_DATA_RES ConvTimeSpan(const std::string & value)
+{
+size_t dashPos = value.find_first_of('-');
+if (dashPos == std::string::npos)
+    throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
+size_t fromColon = value.find_first_of(':');
+if (fromColon == std::string::npos || fromColon > dashPos)
+    throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
+size_t toColon = value.find_first_of(':', dashPos);
+if (toColon == std::string::npos)
+    throw SGCONF::ACTION::ERROR("Time span should be in format 'hh:mm-hh:mm'. Got: '" + value + "'");
+DIRPRICE_DATA_RES res;
+res.hDay = FromString<int>(value.substr(0, fromColon));
+if (res.hDay.data() < 0 || res.hDay.data() > 23)
+    throw SGCONF::ACTION::ERROR("Invalid 'from' hours. Got: '" + value.substr(0, fromColon) + "'");
+res.mDay = FromString<int>(value.substr(fromColon + 1, dashPos - fromColon - 1));
+if (res.mDay.data() < 0 || res.mDay.data() > 59)
+    throw SGCONF::ACTION::ERROR("Invalid 'from' minutes. Got: '" + value.substr(fromColon + 1, dashPos - fromColon - 1) + "'");
+res.hNight = FromString<int>(value.substr(dashPos + 1, toColon - dashPos - 1));
+if (res.hNight.data() < 0 || res.hNight.data() > 23)
+    throw SGCONF::ACTION::ERROR("Invalid 'to' hours. Got: '" + value.substr(dashPos + 1, toColon - dashPos - 1) + "'");
+res.mNight = FromString<int>(value.substr(toColon + 1, value.length() - toColon));
+if (res.mNight.data() < 0 || res.mNight.data() > 59)
+    throw SGCONF::ACTION::ERROR("Invalid 'to' minutes. Got: '" + value.substr(toColon + 1, value.length() - toColon) + "'");
+return res;
+}
+
+void Splice(std::vector<DIRPRICE_DATA_RES> & lhs, const std::vector<DIRPRICE_DATA_RES> & rhs)
+{
+for (size_t i = 0; i < lhs.size() && i < rhs.size(); ++i)
+    lhs[i].Splice(rhs[i]);
+}
+
+void ConvTimes(std::string value, std::vector<DIRPRICE_DATA_RES> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+Splice(res, Split<std::vector<DIRPRICE_DATA_RES> >(value, ',', ConvTimeSpan));
+}
+
+struct ConvPrice : public std::unary_function<std::string, DIRPRICE_DATA_RES>
+{
+    typedef RESETABLE<double> (DIRPRICE_DATA_RES::* MemPtr);
+    ConvPrice(MemPtr before, MemPtr after)
+        : m_before(before), m_after(after)
+    {}
+
+    DIRPRICE_DATA_RES operator()(const std::string & value)
+    {
+    DIRPRICE_DATA_RES res;
+    size_t slashPos = value.find_first_of('/');
+    if (slashPos == std::string::npos)
+        {
+        double price = 0;
+        if (str2x(value, price) < 0)
+            throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value + "'");
+        (res.*m_before) = (res.*m_after) = price;
+        res.noDiscount = true;
+        }
+    else
+        {
+        double price = 0;
+        if (str2x(value.substr(0, slashPos), price) < 0)
+            throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value.substr(0, slashPos) + "'");
+        (res.*m_before) = price;
+        if (str2x(value.substr(slashPos + 1, value.length() - slashPos), price) < 0)
+            throw SGCONF::ACTION::ERROR("Price should be a floating point number. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
+        (res.*m_after) = price;
+        res.noDiscount = false;
+        }
+    return res;
+    }
+
+    MemPtr m_before;
+    MemPtr m_after;
+};
+
+void ConvDayPrices(std::string value, std::vector<DIRPRICE_DATA_RES> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+Splice(res, Split<std::vector<DIRPRICE_DATA_RES> >(value, ',', ConvPrice(&DIRPRICE_DATA_RES::priceDayA, &DIRPRICE_DATA_RES::priceDayB)));
+}
+
+void ConvNightPrices(std::string value, std::vector<DIRPRICE_DATA_RES> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+Splice(res, Split<std::vector<DIRPRICE_DATA_RES> >(value, ',', ConvPrice(&DIRPRICE_DATA_RES::priceNightA, &DIRPRICE_DATA_RES::priceNightB)));
+}
+
+DIRPRICE_DATA_RES ConvThreshold(std::string value)
+{
+DIRPRICE_DATA_RES res;
+double threshold = 0;
+if (str2x(value, threshold) < 0)
+    throw SGCONF::ACTION::ERROR("Threshold should be a floating point value. Got: '" + value + "'");
+res.threshold = threshold;
+return res;
+}
+
+void ConvThresholds(std::string value, std::vector<DIRPRICE_DATA_RES> & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+Splice(res, Split<std::vector<DIRPRICE_DATA_RES> >(value, ',', ConvThreshold));
+}
+
+std::string TimeToString(int h, int m)
+{
+std::ostringstream stream;
+stream << (h < 10 ? "0" : "") << h << ":"
+       << (m < 10 ? "0" : "") << m;
+return stream.str();
+}
+
+void PrintDirPriceData(size_t dir, const DIRPRICE_DATA & data, size_t level)
+{
+std::string night = TimeToString(data.hNight, data.mNight);
+std::string day = TimeToString(data.hDay, data.mDay);
+std::cout << Indent(level, true) << "dir: " << dir << "\n"
+          << Indent(level)       << "'" << night << "' - '" << day << "': " << data.priceDayA << "/" << data.priceDayB << "\n"
+          << Indent(level)       << "'" << day << "' - '" << night << "': " << data.priceNightA << "/" << data.priceNightB << "\n"
+          << Indent(level)       << "threshold: " << data.threshold << "\n"
+          << Indent(level)       << "single price: " << (data.singlePrice ? "yes" : "no") << "\n"
+          << Indent(level)       << "discount: " << (data.noDiscount ? "no" : "yes") << "\n"; // Attention!
+}
+
+void PrintTariffConf(const TARIFF_CONF & conf, size_t level)
+{
+std::cout << Indent(level, true) << "name: " << conf.name << "\n"
+          << Indent(level)       << "fee: " << conf.fee << "\n"
+          << Indent(level)       << "free mb: " << conf.free << "\n"
+          << Indent(level)       << "passive cost: " << conf.passiveCost << "\n"
+          << Indent(level)       << "traff type: " << TraffTypeToString(conf.traffType) << "\n"
+          << Indent(level)       << "period: " << PeriodToString(conf.period) << "\n"
+          << Indent(level)       << "change policy: " << ChangePolicyToString(conf.changePolicy) << "\n"
+          << Indent(level)       << "change policy timeout: " << formatTime(conf.changePolicyTimeout) << "\n";
+}
+
+void PrintTariff(const STG::GET_TARIFF::INFO & info, size_t level = 0)
+{
+PrintTariffConf(info.tariffConf, level);
+std::cout << Indent(level) << "dir prices:\n";
+for (size_t i = 0; i < info.dirPrice.size(); ++i)
+    PrintDirPriceData(i, info.dirPrice[i], level + 1);
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetTariffParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("fee", "<fee>", "\t\ttariff fee"));
+params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traffic"));
+params.push_back(SGCONF::API_ACTION::PARAM("passive-cost", "<cost>", "\tpassive cost"));
+params.push_back(SGCONF::API_ACTION::PARAM("traff-type", "<type>", "\ttraffic type (up, down, up+down, max)"));
+params.push_back(SGCONF::API_ACTION::PARAM("period", "<period>", "\ttarification period (daily, monthly)"));
+params.push_back(SGCONF::API_ACTION::PARAM("change-policy", "<policy>", "tariff change policy (allow, to_cheap, to_expensive, deny)"));
+params.push_back(SGCONF::API_ACTION::PARAM("change-policy-timeout", "<yyyy-mm-dd hh:mm:ss>", "tariff change policy timeout"));
+params.push_back(SGCONF::API_ACTION::PARAM("times", "<hh:mm-hh:mm, ...>", "coma-separated day time-spans for each direction"));
+params.push_back(SGCONF::API_ACTION::PARAM("day-prices", "<price/price, ...>", "coma-separated day prices for each direction"));
+params.push_back(SGCONF::API_ACTION::PARAM("night-prices", "<price/price, ...>", "coma-separated night prices for each direction"));
+params.push_back(SGCONF::API_ACTION::PARAM("thresholds", "<threshold, ...>", "coma-separated thresholds for each direction"));
+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 GetTariffsCallback(bool result,
+                        const std::string & reason,
+                        const std::vector<STG::GET_TARIFF::INFO> & info,
+                        void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get tariff list. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+std::cout << "Tariffs:\n";
+for (size_t i = 0; i < info.size(); ++i)
+    PrintTariff(info[i], 1);
+}
+
+void GetTariffCallback(bool result,
+                       const std::string & reason,
+                       const std::vector<STG::GET_TARIFF::INFO> & info,
+                       void * data)
+{
+assert(data != NULL && "Expecting pointer to std::string with the tariff's name.");
+const std::string & name = *static_cast<const std::string *>(data);
+if (!result)
+    {
+    std::cerr << "Failed to get tariff. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+for (size_t i = 0; i < info.size(); ++i)
+    if (info[i].tariffConf.name == name)
+        PrintTariff(info[i]);
+}
+
+bool GetTariffsFunction(const SGCONF::CONFIG & config,
+                        const std::string & /*arg*/,
+                        const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.GetTariffs(GetTariffsCallback, NULL) == STG::st_ok;
+}
+
+bool GetTariffFunction(const SGCONF::CONFIG & config,
+                       const std::string & arg,
+                       const std::map<std::string, std::string> & /*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 <GetTariff name="..."/>.
+// So get a list of tariffs and filter it. 'data' param holds a pointer to 'name'.
+std::string name(arg);
+return proto.GetTariffs(GetTariffCallback, &name) == STG::st_ok;
+}
+
+bool DelTariffFunction(const SGCONF::CONFIG & config,
+                       const std::string & arg,
+                       const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.DelTariff(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddTariffFunction(const SGCONF::CONFIG & config,
+                       const std::string & arg,
+                       const std::map<std::string, std::string> & options)
+{
+TARIFF_DATA_RES conf;
+conf.tariffConf.name = arg;
+SGCONF::MaybeSet(options, "fee", conf.tariffConf.fee);
+SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
+SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
+SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
+SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
+SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
+SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
+SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
+SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
+SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
+SGCONF::MaybeSet(options, "thresholds", conf.dirPrice, ConvThresholds);
+for (size_t i = 0; i < conf.dirPrice.size(); ++i)
+    {
+    if (!conf.dirPrice[i].priceDayA.empty() &&
+        !conf.dirPrice[i].priceNightA.empty() &&
+        !conf.dirPrice[i].priceDayB.empty() &&
+        !conf.dirPrice[i].priceNightB.empty())
+        conf.dirPrice[i].singlePrice = conf.dirPrice[i].priceDayA.data() == conf.dirPrice[i].priceNightA.data() &&
+                                       conf.dirPrice[i].priceDayB.data() == conf.dirPrice[i].priceNightB.data();
+    }
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.AddTariff(arg, conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgTariffFunction(const SGCONF::CONFIG & config,
+                       const std::string & arg,
+                       const std::map<std::string, std::string> & options)
+{
+TARIFF_DATA_RES conf;
+conf.tariffConf.name = arg;
+SGCONF::MaybeSet(options, "fee", conf.tariffConf.fee);
+SGCONF::MaybeSet(options, "free", conf.tariffConf.free);
+SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost);
+SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType);
+SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod);
+SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy);
+SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout);
+SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes);
+SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices);
+SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices);
+SGCONF::MaybeSet(options, "thresholds", conf.dirPrice, ConvThresholds);
+for (size_t i = 0; i < conf.dirPrice.size(); ++i)
+    {
+    if (!conf.dirPrice[i].priceDayA.empty() &&
+        !conf.dirPrice[i].priceNightA.empty() &&
+        !conf.dirPrice[i].priceDayB.empty() &&
+        !conf.dirPrice[i].priceNightB.empty())
+        conf.dirPrice[i].singlePrice = conf.dirPrice[i].priceDayA.data() == conf.dirPrice[i].priceNightA.data() &&
+                                       conf.dirPrice[i].priceDayB.data() == conf.dirPrice[i].priceNightB.data();
+    }
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.ChgTariff(conf, SimpleCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendTariffsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetTariffParams());
+blocks.Add("Tariff management options")
+      .Add("get-tariffs", SGCONF::MakeAPIAction(commands, GetTariffsFunction), "\tget tariff list")
+      .Add("get-tariff", SGCONF::MakeAPIAction(commands, "<name>", GetTariffFunction), "get tariff")
+      .Add("add-tariff", SGCONF::MakeAPIAction(commands, "<name>", params, AddTariffFunction), "add tariff")
+      .Add("del-tariff", SGCONF::MakeAPIAction(commands, "<name>", DelTariffFunction), "delete tariff")
+      .Add("chg-tariff", SGCONF::MakeAPIAction(commands, "<name>", params, ChgTariffFunction), "change tariff");
+}
diff --git a/projects/sgconf/tariffs.h b/projects/sgconf/tariffs.h
new file mode 100644 (file)
index 0000000..cde906b
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __STG_SGCONF_TARIFFS_H__
+#define __STG_SGCONF_TARIFFS_H__
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendTariffsOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/users.cpp b/projects/sgconf/users.cpp
new file mode 100644 (file)
index 0000000..8ee4a3f
--- /dev/null
@@ -0,0 +1,469 @@
+#include "users.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/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/user_ips.h"
+#include "stg/common.h"
+
+#include <iostream>
+#include <algorithm>
+#include <string>
+#include <map>
+
+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 PrintUser(const STG::GET_USER::INFO & info, size_t level = 0)
+{
+std::cout << Indent(level, true) << "login: " << info.login << "\n"
+          << Indent(level)       << "password: " << info.password << "\n"
+          << Indent(level)       << "cash: " << info.cash << "\n"
+          << Indent(level)       << "credit: " << info.credit << "\n"
+          << Indent(level)       << "credit expire: " << TimeToString(info.creditExpire) << "\n"
+          << Indent(level)       << "last cash add: " << info.lastCashAdd << "\n"
+          << Indent(level)       << "last cash add time: " << TimeToString(info.lastCashAddTime) << "\n"
+          << Indent(level)       << "prepaid traffic: " << info.prepaidTraff << "\n"
+          << Indent(level)       << "disabled: " << (info.disabled ? "t" : "f") << "\n"
+          << Indent(level)       << "passive: " << (info.passive ? "t" : "f") << "\n"
+          << Indent(level)       << "disabled detail stat: " << (info.disableDetailStat ? "t" : "f") << "\n"
+          << Indent(level)       << "connected: " << (info.connected ? "t" : "f") << "\n"
+          << Indent(level)       << "always on-line: " << (info.alwaysOnline ? "t" : "f") << "\n"
+          << Indent(level)       << "IP: " << inet_ntostring(info.ip) << "\n"
+          << Indent(level)       << "IPs: " << info.ips << "\n"
+          << Indent(level)       << "tariff: " << info.tariff << "\n"
+          << Indent(level)       << "group: " << info.group << "\n"
+          << Indent(level)       << "note: " << info.note << "\n"
+          << Indent(level)       << "email: " << info.email << "\n"
+          << Indent(level)       << "name: " << info.name << "\n"
+          << Indent(level)       << "address: " << info.address << "\n"
+          << Indent(level)       << "phone: " << info.phone << "\n"
+          << Indent(level)       << "corporation: " << info.corp << "\n"
+          << Indent(level)       << "last ping time: " << TimeToString(info.pingTime) << "\n"
+          << Indent(level)       << "last activity time: " << TimeToString(info.lastActivityTime) << "\n"
+          << Indent(level)       << "traffic:\n";
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    std::cout << Indent(level + 1, true) << "dir: " << i << "\n"
+              << Indent(level + 1)       << "session upload: " << info.stat.su[i] << "\n"
+              << Indent(level + 1)       << "session download: " << info.stat.sd[i] << "\n"
+              << Indent(level + 1)       << "month upload: " << info.stat.mu[i] << "\n"
+              << Indent(level + 1)       << "month download: " << info.stat.md[i] << "\n";
+    }
+std::cout << Indent(level)       << "user data:\n";
+for (size_t i = 0; i < USERDATA_NUM; ++i)
+    std::cout << Indent(level + 1, true) << "user data " << i << ": " << info.userData[i] << "\n";
+if (!info.services.empty())
+    {
+    std::cout << Indent(level) << "services:\n";
+    for (size_t i = 0; i < info.services.size(); ++i)
+        std::cout << Indent(level + 1, true) << info.services[i] << "\n";
+    }
+if (!info.authBy.empty())
+    {
+    std::cout << Indent(level) << "auth by:\n";
+    for (size_t i = 0; i < info.authBy.size(); ++i)
+        std::cout << Indent(level + 1, true) << info.authBy[i] << "\n";
+    }
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetUserParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "\tuser's password"));
+params.push_back(SGCONF::API_ACTION::PARAM("cash-add", "<cash[:message]>", "cash to add (with optional comment)"));
+params.push_back(SGCONF::API_ACTION::PARAM("cash-set", "<cash[:message]>", "cash to set (with optional comment)"));
+params.push_back(SGCONF::API_ACTION::PARAM("credit", "<amount>", "\tuser's credit"));
+params.push_back(SGCONF::API_ACTION::PARAM("credit-expire", "<date>", "\tcredit expiration"));
+params.push_back(SGCONF::API_ACTION::PARAM("free", "<free mb>", "\tprepaid traffic"));
+params.push_back(SGCONF::API_ACTION::PARAM("disabled", "<flag>", "\tdisable user (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("passive", "<flag>", "\tmake user passive (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("disable-detail-stat", "<flag>", "disable detail stat (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("always-online", "<flag>", "\tmake user always online (y|n)"));
+params.push_back(SGCONF::API_ACTION::PARAM("ips", "<ips>", "\t\tcoma-separated list of ips"));
+params.push_back(SGCONF::API_ACTION::PARAM("tariff", "<tariff name>", "\tcurrent tariff"));
+params.push_back(SGCONF::API_ACTION::PARAM("next-tariff", "<tariff name>", "tariff starting from the next month"));
+params.push_back(SGCONF::API_ACTION::PARAM("group", "<group>", "\t\tuser's group"));
+params.push_back(SGCONF::API_ACTION::PARAM("note", "<note>", "\t\tuser's note"));
+params.push_back(SGCONF::API_ACTION::PARAM("email", "<email>", "\t\tuser's email"));
+params.push_back(SGCONF::API_ACTION::PARAM("name", "<real name>", "\tuser's real name"));
+params.push_back(SGCONF::API_ACTION::PARAM("address", "<address>", "\tuser's postal address"));
+params.push_back(SGCONF::API_ACTION::PARAM("phone", "<phone>", "\t\tuser's phone number"));
+params.push_back(SGCONF::API_ACTION::PARAM("corp", "<corp name>", "\tcorporation name"));
+params.push_back(SGCONF::API_ACTION::PARAM("session-traffic", "<up/dn, ...>", "coma-separated session upload and download"));
+params.push_back(SGCONF::API_ACTION::PARAM("month-traffic", "<up/dn, ...>", "coma-separated month upload and download"));
+params.push_back(SGCONF::API_ACTION::PARAM("user-data", "<value, ...>", "coma-separated user data values"));
+return params;
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetCheckParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("password", "<password>", "\tuser's password"));
+return params;
+}
+
+std::vector<SGCONF::API_ACTION::PARAM> GetMessageParams()
+{
+std::vector<SGCONF::API_ACTION::PARAM> params;
+params.push_back(SGCONF::API_ACTION::PARAM("logins", "<login, ...>", "\tlist of logins to send a message"));
+params.push_back(SGCONF::API_ACTION::PARAM("text", "<text>", "\t\tmessage text"));
+return params;
+}
+
+void ConvBool(const std::string & value, RESETABLE<int> & res)
+{
+res = !value.empty() && value[0] == 'y';
+}
+
+void Splice(std::vector<RESETABLE<std::string> > & lhs, const std::vector<RESETABLE<std::string> > & rhs)
+{
+for (size_t i = 0; i < lhs.size() && i < rhs.size(); ++i)
+    lhs[i].splice(rhs[i]);
+}
+
+RESETABLE<std::string> ConvString(const std::string & value)
+{
+return value;
+}
+
+void ConvStringList(std::string value, std::vector<RESETABLE<std::string> > & res)
+{
+Splice(res, Split<std::vector<RESETABLE<std::string> > >(value, ',', ConvString));
+}
+
+void ConvServices(std::string value, RESETABLE<std::vector<std::string> > & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+res = Split<std::vector<std::string> >(value, ',');
+}
+
+void ConvCreditExpire(const std::string & value, RESETABLE<time_t> & res)
+{
+struct tm brokenTime;
+if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
+    throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
+res = stg_timegm(&brokenTime);
+}
+
+void ConvIPs(const std::string & value, RESETABLE<USER_IPS> & res)
+{
+res = StrToIPS(value);
+}
+
+struct TRAFF
+{
+    uint64_t up;
+    uint64_t down;
+};
+
+TRAFF ConvTraff(const std::string & value)
+{
+TRAFF res;
+size_t slashPos = value.find_first_of('/');
+if (slashPos == std::string::npos)
+    throw SGCONF::ACTION::ERROR("Traffic record should be in format 'upload/download'. Got: '" + value + "'");
+
+if (str2x(value.substr(0, slashPos), res.up) < 0)
+    throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(0, slashPos) + "'");
+if (str2x(value.substr(slashPos + 1, value.length() - slashPos), res.down) < 0)
+    throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
+return res;
+}
+
+void ConvSessionTraff(std::string value, USER_STAT_RES & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
+if (traff.size() != DIR_NUM)
+    throw SGCONF::ACTION::ERROR("There should be prcisely " + x2str(DIR_NUM) + " records of session traffic.");
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    res.sessionUp[i] = traff[i].up;
+    res.sessionDown[i] = traff[i].down;
+    }
+}
+
+void ConvMonthTraff(std::string value, USER_STAT_RES & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
+if (traff.size() != DIR_NUM)
+    throw SGCONF::ACTION::ERROR("There should be prcisely " + x2str(DIR_NUM) + " records of month traffic.");
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    res.monthUp[i] = traff[i].up;
+    res.monthDown[i] = traff[i].down;
+    }
+}
+
+void ConvCashInfo(const std::string & value, RESETABLE<CASH_INFO> & res)
+{
+CASH_INFO info;
+size_t pos = value.find_first_of(':');
+if (pos == std::string::npos)
+    {
+    if (str2x(value, info.first) < 0)
+        throw SGCONF::ACTION::ERROR("Cash should be a double value. Got: '" + value + "'");
+    }
+else
+    {
+    if (str2x(value.substr(0, pos), info.first) < 0)
+        throw SGCONF::ACTION::ERROR("Cash should be a double value. Got: '" + value + "'");
+    info.second = value.substr(pos + 1);
+    }
+res = info;
+}
+
+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 GetUsersCallback(bool result,
+                      const std::string & reason,
+                      const std::vector<STG::GET_USER::INFO> & info,
+                      void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get user list. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+std::cout << "Users:\n";
+for (size_t i = 0; i < info.size(); ++i)
+    PrintUser(info[i], 1);
+}
+
+void GetUserCallback(bool result,
+                     const std::string & reason,
+                     const STG::GET_USER::INFO & info,
+                     void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get user. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+PrintUser(info);
+}
+
+void AuthByCallback(bool result,
+                    const std::string & reason,
+                    const std::vector<std::string> & info,
+                    void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get authorizer list. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+std::cout << "Authorized by:\n";
+for (size_t i = 0; i < info.size(); ++i)
+    std::cout << Indent(1, true) << info[i] << "\n";
+}
+
+bool GetUsersFunction(const SGCONF::CONFIG & config,
+                      const std::string & /*arg*/,
+                      const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.GetUsers(GetUsersCallback, NULL) == STG::st_ok;
+}
+
+bool GetUserFunction(const SGCONF::CONFIG & config,
+                     const std::string & arg,
+                     const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.GetUser(arg, GetUserCallback, NULL) == STG::st_ok;
+}
+
+bool DelUserFunction(const SGCONF::CONFIG & config,
+                     const std::string & arg,
+                     const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.DelUser(arg, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AddUserFunction(const SGCONF::CONFIG & config,
+                     const std::string & arg,
+                     const std::map<std::string, std::string> & options)
+{
+USER_CONF_RES conf;
+SGCONF::MaybeSet(options, "password", conf.password);
+SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
+SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
+SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
+SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
+SGCONF::MaybeSet(options, "tariff", conf.tariffName);
+SGCONF::MaybeSet(options, "address", conf.address);
+SGCONF::MaybeSet(options, "phone", conf.phone);
+SGCONF::MaybeSet(options, "email", conf.email);
+SGCONF::MaybeSet(options, "note", conf.note);
+SGCONF::MaybeSet(options, "name", conf.realName);
+SGCONF::MaybeSet(options, "corp", conf.corp);
+SGCONF::MaybeSet(options, "services", conf.services, ConvServices);
+SGCONF::MaybeSet(options, "group", conf.group);
+SGCONF::MaybeSet(options, "credit", conf.credit);
+SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
+SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
+SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
+SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
+USER_STAT_RES stat;
+SGCONF::MaybeSet(options, "cash-set", stat.cashSet, ConvCashInfo);
+SGCONF::MaybeSet(options, "free", stat.freeMb);
+SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
+SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.AddUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool ChgUserFunction(const SGCONF::CONFIG & config,
+                     const std::string & arg,
+                     const std::map<std::string, std::string> & options)
+{
+USER_CONF_RES conf;
+SGCONF::MaybeSet(options, "password", conf.password);
+SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
+SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
+SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
+SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
+SGCONF::MaybeSet(options, "tariff", conf.tariffName);
+SGCONF::MaybeSet(options, "address", conf.address);
+SGCONF::MaybeSet(options, "phone", conf.phone);
+SGCONF::MaybeSet(options, "email", conf.email);
+SGCONF::MaybeSet(options, "note", conf.note);
+SGCONF::MaybeSet(options, "name", conf.realName);
+SGCONF::MaybeSet(options, "corp", conf.corp);
+SGCONF::MaybeSet(options, "services", conf.services, ConvServices);
+SGCONF::MaybeSet(options, "group", conf.group);
+SGCONF::MaybeSet(options, "credit", conf.credit);
+SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
+SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
+SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
+SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
+USER_STAT_RES stat;
+SGCONF::MaybeSet(options, "cash-add", stat.cashAdd, ConvCashInfo);
+SGCONF::MaybeSet(options, "cash-set", stat.cashSet, ConvCashInfo);
+SGCONF::MaybeSet(options, "free", stat.freeMb);
+SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
+SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.ChgUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool CheckUserFunction(const SGCONF::CONFIG & config,
+                       const std::string & arg,
+                       const std::map<std::string, std::string> & options)
+{
+std::map<std::string, std::string>::const_iterator it(options.find("password"));
+if (it == options.end())
+    throw SGCONF::ACTION::ERROR("Password is not specified.");
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.CheckUser(arg, it->second, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool SendMessageFunction(const SGCONF::CONFIG & config,
+                         const std::string & /*arg*/,
+                         const std::map<std::string, std::string> & options)
+{
+std::map<std::string, std::string>::const_iterator it(options.find("logins"));
+if (it == options.end())
+    throw SGCONF::ACTION::ERROR("Logins are not specified.");
+std::string logins = it->second;
+for (size_t i = 0; i < logins.length(); ++i)
+    if (logins[i] == ',')
+        logins[i] = ':';
+it = options.find("text");
+if (it == options.end())
+    throw SGCONF::ACTION::ERROR("Message text is not specified.");
+std::string text = it->second;
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.SendMessage(logins, text, SimpleCallback, NULL) == STG::st_ok;
+}
+
+bool AuthByFunction(const SGCONF::CONFIG & config,
+                    const std::string & arg,
+                    const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.AuthBy(arg, AuthByCallback, NULL) == STG::st_ok;
+}
+
+} // namespace anonymous
+
+void SGCONF::AppendUsersOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+std::vector<API_ACTION::PARAM> params(GetUserParams());
+blocks.Add("User management options")
+      .Add("get-users", SGCONF::MakeAPIAction(commands, GetUsersFunction), "\tget user list")
+      .Add("get-user", SGCONF::MakeAPIAction(commands, "<login>", GetUserFunction), "get user")
+      .Add("add-user", SGCONF::MakeAPIAction(commands, "<login>", params, AddUserFunction), "add user")
+      .Add("del-user", SGCONF::MakeAPIAction(commands, "<login>", DelUserFunction), "delete user")
+      .Add("chg-user", SGCONF::MakeAPIAction(commands, "<login>", params, ChgUserFunction), "change user")
+      .Add("check-user", SGCONF::MakeAPIAction(commands, "<login>", GetCheckParams(), CheckUserFunction), "check user existance and credentials")
+      .Add("send-message", SGCONF::MakeAPIAction(commands, GetMessageParams(), SendMessageFunction), "send message")
+      .Add("auth-by", SGCONF::MakeAPIAction(commands, "<login>", AuthByFunction), "a list of authorizers user authorized by");
+}
diff --git a/projects/sgconf/users.h b/projects/sgconf/users.h
new file mode 100644 (file)
index 0000000..a757fe1
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __STG_SGCONF_USERS_H__
+#define __STG_SGCONF_USERS_H__
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendUsersOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+}
+
+#endif
diff --git a/projects/sgconf/utils.h b/projects/sgconf/utils.h
new file mode 100644 (file)
index 0000000..3793c9c
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __STG_SGCONF_UTILS_H__
+#define __STG_SGCONF_UTILS_H__
+
+#include "stg/common.h"
+#include "stg/resetable.h"
+
+#include <string>
+#include <map>
+
+namespace SGCONF
+{
+
+template <typename T>
+inline
+void MaybeSet(const std::map<std::string, std::string> & options, const std::string & name, RESETABLE<T> & res)
+{
+std::map<std::string, std::string>::const_iterator it(options.find(name));
+if (it == options.end())
+    return;
+T value;
+if (str2x(it->second, value) < 0)
+    return;
+res = value;
+}
+
+template <typename T, typename F>
+inline
+void MaybeSet(const std::map<std::string, std::string> & options, const std::string & name, T & res, F conv)
+{
+std::map<std::string, std::string>::const_iterator it(options.find(name));
+if (it == options.end())
+    return;
+conv(it->second, res);
+}
+
+template <>
+inline
+void MaybeSet<std::string>(const std::map<std::string, std::string> & options, const std::string & name, RESETABLE<std::string> & res)
+{
+std::map<std::string, std::string>::const_iterator it(options.find(name));
+if (it == options.end())
+    return;
+res = it->second;
+}
+
+} // namespace SGCONF
+
+#endif
diff --git a/projects/sgconf/version_sg.h b/projects/sgconf/version_sg.h
deleted file mode 100644 (file)
index f9664eb..0000000
+++ /dev/null
@@ -1,35 +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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Author: faust $
- $Revision: 1.3 $
- $Date: 2009/08/05 09:29:35 $
- */
-
-
-#ifndef VERSION_SG_H
-#define VERSION_SG_H
-
-#define VERSION_SG "1.08.9"
-
-#endif
-
-
diff --git a/projects/sgconf/xml.cpp b/projects/sgconf/xml.cpp
new file mode 100644 (file)
index 0000000..abf2ccc
--- /dev/null
@@ -0,0 +1,105 @@
+#include "xml.h"
+
+#include "api_action.h"
+#include "options.h"
+#include "config.h"
+
+#include "stg/servconf.h"
+
+#include <iostream>
+#include <string>
+#include <map>
+
+#include <expat.h>
+
+namespace
+{
+
+struct ParserState
+{
+size_t level;
+};
+
+std::string Indent(size_t level)
+{
+return std::string(level * 4, ' ');
+}
+
+std::string PrintAttr(const char ** attr)
+{
+std::string res;
+if (attr == NULL)
+    return res;
+while (*attr)
+    {
+    if (*(attr + 1) == NULL)
+        return res;
+    res += std::string(" ") + *attr + "=\"" + *(attr + 1) + "\"";
+    ++attr; ++attr;
+    }
+return res;
+}
+
+void Start(void * data, const char * el, const char ** attr)
+{
+ParserState * state = static_cast<ParserState *>(data);
+if (el != NULL)
+    std::cout << Indent(state->level) << "<" << el << PrintAttr(attr) << ">\n";
+++state->level;
+}
+
+void End(void * data, const char * el)
+{
+ParserState * state = static_cast<ParserState *>(data);
+--state->level;
+if (el != NULL)
+    std::cout << Indent(state->level) << "</" << el << ">\n";
+}
+
+void PrintXML(const std::string& xml)
+{
+ParserState state = { 0 };
+
+XML_Parser parser = XML_ParserCreate(NULL);
+XML_ParserReset(parser, NULL);
+XML_SetElementHandler(parser, Start, End);
+XML_SetUserData(parser, &state);
+
+if (XML_Parse(parser, xml.c_str(), xml.length(), true) == XML_STATUS_ERROR)
+    std::cerr << "XML parse error at line " << XML_GetCurrentLineNumber(parser)
+              << ": '" << XML_ErrorString(XML_GetErrorCode(parser)) << "'"
+              << std::endl;
+
+XML_ParserFree(parser);
+}
+
+void RawXMLCallback(bool result, const std::string & reason, const std::string & response, void * /*data*/)
+{
+if (!result)
+    {
+    std::cerr << "Failed to get raw XML response. Reason: '" << reason << "'." << std::endl;
+    return;
+    }
+PrintXML(response);
+}
+
+bool RawXMLFunction(const SGCONF::CONFIG & config,
+                    const std::string & arg,
+                    const std::map<std::string, std::string> & /*options*/)
+{
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.localAddress.data(),
+                    config.localPort.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.RawXML(arg, RawXMLCallback, NULL) == STG::st_ok;
+}
+
+}
+
+void SGCONF::AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks)
+{
+blocks.Add("Raw XML")
+      .Add("r", "raw", SGCONF::MakeAPIAction(commands, "<xml>", RawXMLFunction), "\tmake raw XML request");
+}
diff --git a/projects/sgconf/xml.h b/projects/sgconf/xml.h
new file mode 100644 (file)
index 0000000..453d5eb
--- /dev/null
@@ -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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONF_XML_H__
+#define __STG_SGCONF_XML_H__
+
+namespace SGCONF
+{
+
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
+
+}
+
+#endif
index 5fa0f23c6c92830099a9485c5873c4c3fefadae0..676bf74ef4614fb3ce2b20767e27c2012c27ea63 100755 (executable)
@@ -72,7 +72,6 @@ printf "       Building sgconv for $sys $release\n"
 printf "#############################################################################\n"
 
 STG_LIBS="logger.lib
-          locker.lib
           crypto.lib
           common.lib
           conffiles.lib
index 1fbb8a98d86b21b618c235ee9bcc87463215baa6..92935c0537aceb25c85219ccc8dee7e03ab6e9ef 100755 (executable)
@@ -390,6 +390,19 @@ else
     fi
 fi
 
+printf "Checking for -lpcap... "
+printf "#include <pcap.h>\nint main() { return 0; }\n" > build_check.c
+$CC $CFLAGS $LDFLAGS build_check.c -lpcap -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_PCAP=no
+    printf "no\n"
+else
+    CHECK_PCAP=yes
+    printf "yes\n"
+fi
+rm -f fake
+
 printf "Checking for -lnfnetlink... "
 printf "#include <stdint.h>\n#include <netinet/in.h>\n#include <linux/netfilter.h>\nint main() { return 0; }\n" > build_check.c
 $CC $CFLAGS $LDFLAGS build_check.c -lnfnetlink -o fake > /dev/null 2> /dev/null
@@ -473,6 +486,12 @@ then
              configuration/rpcconfig"
 fi
 
+if [ "$CHECK_PCAP" = "yes" ]
+then
+    PLUGINS="$PLUGINS
+             capture/pcap"
+fi
+
 if [ "$CHECK_NFNETLINK" = "yes" -a "$CHECK_NFQ" = "yes" ]
 then
     PLUGINS="$PLUGINS
@@ -514,6 +533,7 @@ then
     printf "XMLRPC_CFLAGS=$XMLRPC_CFLAGS\n" >> $CONFFILE
     printf "XMLRPC_LDFLAGS=$XMLRPC_LDFLAGS\n" >> $CONFFILE
 fi
+printf "CHECK_PCAP=$CHECK_PCAP\n" >> $CONFFILE
 printf "CHECK_NFNETLINK=$CHECK_NFNETLINK\n" >> $CONFFILE
 if [ "$CHECK_NFNETLINK" = "yes" ]
 then
index 69b5eae323f9ab5060489cfe15e590daeb67d4fd..df170dd089203f1e806d100cbe468b732c6c57da 100644 (file)
@@ -8,14 +8,14 @@
 
     # The time interval between sending an alive query to the user
     # and updating statistics
-    # Parameter: required 
+    # Parameter: required
     # Values: 5 ... 600 (seconds)
     # Default: 60
     UserDelay = 60
 
-    # User timeout. If authorizer does not respond during this time, 
+    # User timeout. If authorizer does not respond during this time,
     # the user will be disconnected
-    # Parameter: required 
+    # Parameter: required
     # Values: 5 ... 600
     # Default: 60
     UserTimeout = 65
     # FreeMb = cash - amount of money for which the user can download for free
     # FreeMb = none - no transfer
     # Default: cash
-    # Parameter: required 
+    # Parameter: required
     # Values: different, see above
     # Default: cash
     FreeMb = cash
+
+    # Enable protocol errors logging
+    # Parameter: optional
+    # Values: yes, no
+    # Default: no
+    # LogProtocolErrors = no
 </Module>
index c1f4fe929bfcb2deae10b5eab7f4c763ea12d067..bb8ee7c47e4ec7f3ada0ec6fee5f9dff8a6db6e4 100644 (file)
@@ -41,6 +41,12 @@ StatWritePeriod = 10
 # Default: 1
 DayFee = 1
 
+# When set to 'no' Stargazer will continue reading database after error and show all of them.
+# Parameter: optional
+# Values: yes, no
+# Default: yes
+# StopOnError = yes
+
 # Fee charged at the last (yes) or first (no) day of tariffication period.
 # Defines how the fee will be charged in the transition to the new tariff.
 # User has tariff A with fee 100. Changing it to tariff B with fee 200
index 69b5eae323f9ab5060489cfe15e590daeb67d4fd..df170dd089203f1e806d100cbe468b732c6c57da 100644 (file)
@@ -8,14 +8,14 @@
 
     # The time interval between sending an alive query to the user
     # and updating statistics
-    # Parameter: required 
+    # Parameter: required
     # Values: 5 ... 600 (seconds)
     # Default: 60
     UserDelay = 60
 
-    # User timeout. If authorizer does not respond during this time, 
+    # User timeout. If authorizer does not respond during this time,
     # the user will be disconnected
-    # Parameter: required 
+    # Parameter: required
     # Values: 5 ... 600
     # Default: 60
     UserTimeout = 65
     # FreeMb = cash - amount of money for which the user can download for free
     # FreeMb = none - no transfer
     # Default: cash
-    # Parameter: required 
+    # Parameter: required
     # Values: different, see above
     # Default: cash
     FreeMb = cash
+
+    # Enable protocol errors logging
+    # Parameter: optional
+    # Values: yes, no
+    # Default: no
+    # LogProtocolErrors = no
 </Module>
index c1f4fe929bfcb2deae10b5eab7f4c763ea12d067..bb8ee7c47e4ec7f3ada0ec6fee5f9dff8a6db6e4 100644 (file)
@@ -41,6 +41,12 @@ StatWritePeriod = 10
 # Default: 1
 DayFee = 1
 
+# When set to 'no' Stargazer will continue reading database after error and show all of them.
+# Parameter: optional
+# Values: yes, no
+# Default: yes
+# StopOnError = yes
+
 # Fee charged at the last (yes) or first (no) day of tariffication period.
 # Defines how the fee will be charged in the transition to the new tariff.
 # User has tariff A with fee 100. Changing it to tariff B with fee 200
diff --git a/projects/stargazer/plugins/capture/pcap/Makefile b/projects/stargazer/plugins/capture/pcap/Makefile
new file mode 100644 (file)
index 0000000..3eff306
--- /dev/null
@@ -0,0 +1,13 @@
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_pcap.so
+
+SRCS = ./pcap_cap.cpp
+
+LIBS += -lpcap $(LIB_THREAD)
+
+STGLIBS = common \
+          logger
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/pcap/pcap_cap.cpp b/projects/stargazer/plugins/capture/pcap/pcap_cap.cpp
new file mode 100644 (file)
index 0000000..d085df6
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+*/
+
+#include "pcap_cap.h"
+
+#include "stg/traffcounter.h"
+#include "stg/plugin_creator.h"
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+
+#include <signal.h>
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+namespace
+{
+PLUGIN_CREATOR<PCAP_CAP> pcc;
+
+const size_t SNAP_LEN = 1518;
+const size_t ETHER_ADDR_LEN = 6;
+
+struct ETH
+{
+u_char     ether_dhost[ETHER_ADDR_LEN];    /* destination host address */
+u_char     ether_shost[ETHER_ADDR_LEN];    /* source host address */
+u_short    ether_type;                     /* IP? ARP? RARP? etc */
+};
+
+}
+
+extern "C" PLUGIN * GetPlugin();
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PLUGIN * GetPlugin()
+{
+return pcc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string PCAP_CAP::GetVersion() const
+{
+return "pcap_cap v.1.0";
+}
+//-----------------------------------------------------------------------------
+PCAP_CAP::PCAP_CAP()
+    : nonstop(false),
+      isRunning(false),
+      traffCnt(NULL),
+      logger(GetPluginLogger(GetStgLogger(), "pcap_cap"))
+{
+}
+//-----------------------------------------------------------------------------
+int PCAP_CAP::ParseSettings()
+{
+devices.erase(devices.begin(), devices.end());
+
+if (settings.moduleParams.empty())
+    {
+    devices.push_back(DEV());
+    logger("Defaulting to pseudo-device 'any'.");
+    return 0;
+    }
+
+for (size_t i = 0; i < settings.moduleParams.size(); i++)
+    if (settings.moduleParams[i].param == "interfaces")
+        for (size_t j = 0; j < settings.moduleParams[i].value.size(); j++)
+            devices.push_back(DEV(settings.moduleParams[i].value[j]));
+
+for (size_t i = 0; i < settings.moduleParams.size(); i++)
+    if (settings.moduleParams[i].param == "filters")
+        for (size_t j = 0; j < settings.moduleParams[i].value.size(); j++)
+            if (j < devices.size())
+                devices[j].filterExpression = settings.moduleParams[i].value[j];
+
+if (devices.empty())
+    {
+    devices.push_back(DEV());
+    logger("Defaulting to pseudo-device 'all'.");
+    return 0;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PCAP_CAP::Start()
+{
+if (isRunning)
+    return 0;
+
+DEV_MAP::iterator it(devices.begin());
+while (it != devices.end())
+    {
+    bpf_u_int32 mask;
+    bpf_u_int32 net;
+    char errbuf[PCAP_ERRBUF_SIZE];
+
+    /* get network number and mask associated with capture device */
+    if (pcap_lookupnet(it->device.c_str(), &net, &mask, errbuf) == -1)
+        {
+        errorStr = "Couldn't get netmask for device " + it->device + ": " + errbuf;
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    /* open capture device */
+    it->handle = pcap_open_live(it->device.c_str(), SNAP_LEN, 1, 1000, errbuf);
+    if (it->handle == NULL)
+        {
+        errorStr = "Couldn't open device " + it->device + ": " + errbuf;
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    if (pcap_setnonblock(it->handle, true, errbuf) == -1)
+        {
+        errorStr = "Couldn't put device " + it->device + " into non-blocking mode: " + errbuf;
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    /* make sure we're capturing on an Ethernet device [2] */
+    if (pcap_datalink(it->handle) != DLT_EN10MB)
+        {
+        errorStr = it->device + " is not an Ethernet";
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    /* compile the filter expression */
+    if (pcap_compile(it->handle, &it->filter, it->filterExpression.c_str(), 0, net) == -1)
+        {
+        errorStr = "Couldn't parse filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    /* apply the compiled filter */
+    if (pcap_setfilter(it->handle, &it->filter) == -1)
+        {
+        errorStr = "Couldn't install filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    it->fd = pcap_get_selectable_fd(it->handle);
+    if (it->fd == -1)
+        {
+        errorStr = "Couldn't get a file descriptor for " + it->device + ": " + pcap_geterr(it->handle);
+        logger(errorStr);
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+    ++it;
+    }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    errorStr = "Cannot create thread.";
+    logger("Cannot create thread.");
+    printfd(__FILE__, "Cannot create thread\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PCAP_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && isRunning; i++)
+    {
+    struct timespec ts = {0, 200000000};
+    nanosleep(&ts, NULL);
+    }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    if (pthread_kill(thread, SIGUSR1))
+        {
+        errorStr = "Cannot kill thread.";
+        logger("Cannot send signal to thread.");
+        return -1;
+        }
+    for (int i = 0; i < 25 && isRunning; ++i)
+        {
+        struct timespec ts = {0, 200000000};
+        nanosleep(&ts, NULL);
+        }
+    if (isRunning)
+        {
+        errorStr = "PCAP_CAP not stopped.";
+        logger("Cannot stop thread.");
+        printfd(__FILE__, "Cannot stop thread\n");
+        return -1;
+        }
+    }
+
+pthread_join(thread, NULL);
+
+for (DEV_MAP::iterator it(devices.begin()); it != devices.end(); ++it)
+    {
+    pcap_freecode(&it->filter);
+    pcap_close(it->handle);
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * PCAP_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+PCAP_CAP * dc = static_cast<PCAP_CAP *>(d);
+dc->isRunning = true;
+
+fd_set fds;
+FD_ZERO(&fds);
+int maxFd = 0;
+for (DEV_MAP::const_iterator it(dc->devices.begin()); it != dc->devices.end(); ++it)
+    {
+    FD_SET(it->fd, &fds);
+    maxFd = std::max(maxFd, it->fd);
+    }
+
+while (dc->nonstop)
+    {
+    fd_set rfds = fds;
+    struct timeval tv = {0, 500000};
+
+    if (select(maxFd + 1, &rfds, NULL, NULL, &tv) > 0)
+        dc->TryRead(rfds);
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+
+void PCAP_CAP::TryRead(const fd_set & set)
+{
+for (DEV_MAP::const_iterator it(devices.begin()); it != devices.end(); ++it)
+    if (FD_ISSET(it->fd, &set))
+        TryReadDev(*it);
+}
+
+void PCAP_CAP::TryReadDev(const DEV & dev)
+{
+struct pcap_pkthdr * header;
+const u_char * packet;
+if (pcap_next_ex(dev.handle, &header, &packet) == -1)
+    {
+    printfd(__FILE__, "Failed to read data from '%s': %s\n", dev.device.c_str(), pcap_geterr(dev.handle));
+    return;
+    }
+
+const ETH * eth = reinterpret_cast<const ETH *>(packet);
+if (eth->ether_type != 0x8)
+    return;
+
+RAW_PACKET ip;
+memcpy(&ip.rawPacket, packet + 14, sizeof(ip.rawPacket));
+traffCnt->Process(ip);
+}
diff --git a/projects/stargazer/plugins/capture/pcap/pcap_cap.h b/projects/stargazer/plugins/capture/pcap/pcap_cap.h
new file mode 100644 (file)
index 0000000..3bdfd55
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+*/
+
+#ifndef PCAP_CAP_H
+#define PCAP_CAP_H
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+
+#include <pcap.h>
+#include <pthread.h>
+#include <sys/select.h>
+
+class USERS;
+class TARIFFS;
+class ADMINS;
+class TRAFFCOUNTER;
+class SETTINGS;
+
+class TRAFFCOUNTER;
+
+struct DEV
+{
+    DEV() : device("any"), filterExpression("ip"), handle(NULL), fd(-1) {}
+    DEV(const std::string & d) : device(d), filterExpression("ip"), handle(NULL), fd(-1) {}
+    DEV(const std::string & d, const std::string & f)
+        : device(d), filterExpression(f), handle(NULL), fd(-1) {}
+
+    std::string device;
+    std::string filterExpression;
+    pcap_t * handle;
+    struct bpf_program filter;
+    int fd;
+};
+
+typedef std::vector<DEV> DEV_MAP;
+
+class PCAP_CAP : public PLUGIN {
+public:
+    PCAP_CAP();
+    virtual ~PCAP_CAP() {}
+
+    void                SetTraffcounter(TRAFFCOUNTER * tc) { traffCnt = tc; }
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload(const MODULE_SETTINGS & /*ms*/) { return 0; }
+    bool                IsRunning() { return isRunning; }
+
+    void                SetSettings(const MODULE_SETTINGS & s) { settings = s; }
+    int                 ParseSettings();
+
+    const std::string & GetStrError() const { return errorStr; }
+    std::string         GetVersion() const;
+    uint16_t            GetStartPosition() const { return 40; }
+    uint16_t            GetStopPosition() const { return 40; }
+
+private:
+    PCAP_CAP(const PCAP_CAP & rvalue);
+    PCAP_CAP & operator=(const PCAP_CAP & rvalue);
+
+    void TryRead(const fd_set & set);
+    void TryReadDev(const DEV & dev);
+
+    static void *       Run(void *);
+
+    mutable std::string errorStr;
+
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+    MODULE_SETTINGS     settings;
+    DEV_MAP             devices;
+
+    TRAFFCOUNTER *      traffCnt;
+
+    PLUGIN_LOGGER       logger;
+};
+//-----------------------------------------------------------------------------
+
+#endif
index 2e5c8c60195d5c76e7e23c9f07b8322228b9cb63..a83bb86c7a2d85a4465e2c6fe302e306eb45d96f 100644 (file)
@@ -13,8 +13,10 @@ SRCS = ./stgconfig.cpp \
        ./parser_tariffs.cpp \
        ./parser_admins.cpp \
        ./parser_users.cpp \
+       ./parser_services.cpp \
        ./parser_message.cpp \
        ./parser_auth_by.cpp \
+       ./parser_user_info.cpp \
        ./parser_server_info.cpp
 
 LIBS += -lexpat \
index 567c537ae7f6a5aaef04ef641ff1ff77da829db6..f5a57a48ca11a6c377620b0892481335d4e3f7ef 100644 (file)
@@ -27,7 +27,9 @@
 #include "parser_admins.h"
 #include "parser_tariffs.h"
 #include "parser_users.h"
+#include "parser_services.h"
 #include "parser_message.h"
+#include "parser_user_info.h"
 #include "parser_auth_by.h"
 
 #include "stg/common.h"
@@ -53,6 +55,8 @@ CONFIGPROTO::CONFIGPROTO(PLUGIN_LOGGER & l)
       m_admins(NULL),
       m_tariffs(NULL),
       m_users(NULL),
+      m_services(NULL),
+      m_corporations(NULL),
       m_store(NULL),
       m_port(0),
       m_bindAddress("0.0.0.0"),
@@ -79,7 +83,6 @@ int CONFIGPROTO::Prepare()
     sigaddset(&sigmask, SIGUSR1);
     sigaddset(&sigmask, SIGHUP);
     pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
-
     m_listenSocket = socket(PF_INET, SOCK_STREAM, 0);
 
     if (m_listenSocket < 0)
@@ -207,6 +210,8 @@ void CONFIGPROTO::RegisterParsers()
     assert(m_admins != NULL);
     assert(m_users != NULL);
     assert(m_tariffs != NULL);
+    assert(m_services != NULL);
+    assert(m_corporations != NULL);
 
     SP::GET_SERVER_INFO::FACTORY::Register(m_registry, *m_settings, *m_users, *m_tariffs);
 
@@ -227,9 +232,17 @@ void CONFIGPROTO::RegisterParsers()
     SP::CHG_USER::FACTORY::Register(m_registry, *m_users, *m_store, *m_tariffs);
     SP::CHECK_USER::FACTORY::Register(m_registry, *m_users);
 
+    SP::GET_SERVICES::FACTORY::Register(m_registry, *m_services);
+    SP::GET_SERVICE::FACTORY::Register(m_registry, *m_services);
+    SP::ADD_SERVICE::FACTORY::Register(m_registry, *m_services);
+    SP::DEL_SERVICE::FACTORY::Register(m_registry, *m_services);
+    SP::CHG_SERVICE::FACTORY::Register(m_registry, *m_services);
+
     SP::SEND_MESSAGE::FACTORY::Register(m_registry, *m_users);
 
     SP::AUTH_BY::FACTORY::Register(m_registry, *m_users);
+
+    SP::USER_INFO::FACTORY::Register(m_registry, *m_users);
 }
 
 int CONFIGPROTO::MaxFD() const
index 2119bc675214c22aae0eb2f1c3589f659e592c81..c464e95ee5c3b76481d0e50e37dfe9cc2f66f2cc 100644 (file)
@@ -38,6 +38,8 @@ class SETTINGS;
 class ADMINS;
 class TARIFFS;
 class USERS;
+class SERVICES;
+class CORPORATIONS;
 class STORE;
 class PLUGIN_LOGGER;
 
@@ -53,18 +55,20 @@ public:
     CONFIGPROTO(PLUGIN_LOGGER & l);
     ~CONFIGPROTO();
 
-    void            SetPort(uint16_t port) { m_port = port; }
-    void            SetBindAddress(const std::string & address) { m_bindAddress = address; }
-    void            SetSettings(const SETTINGS * settings) { m_settings = settings; }
-    void            SetAdmins(ADMINS * admins) { m_admins = admins; }
-    void            SetTariffs(TARIFFS * tariffs) { m_tariffs = tariffs; }
-    void            SetUsers(USERS * users) { m_users = users; }
-    void            SetStore(STORE * store) { m_store = store; }
-
-    int             Prepare();
-    int             Stop();
+    void SetPort(uint16_t port) { m_port = port; }
+    void SetBindAddress(const std::string & address) { m_bindAddress = address; }
+    void SetSettings(const SETTINGS * settings) { m_settings = settings; }
+    void SetAdmins(ADMINS * admins) { m_admins = admins; }
+    void SetTariffs(TARIFFS * tariffs) { m_tariffs = tariffs; }
+    void SetUsers(USERS * users) { m_users = users; }
+    void SetStore(STORE * store) { m_store = store; }
+    void SetServices(SERVICES * services) { m_services = services; }
+    void SetCorporations(CORPORATIONS * corporations) { m_corporations = corporations; }
+
+    int Prepare();
+    int Stop();
     const std::string & GetStrError() const { return m_errorStr; }
-    void            Run();
+    void Run();
 
 private:
     CONFIGPROTO(const CONFIGPROTO & rvalue);
@@ -74,6 +78,8 @@ private:
     ADMINS *         m_admins;
     TARIFFS *        m_tariffs;
     USERS *          m_users;
+    SERVICES *       m_services;
+    CORPORATIONS *   m_corporations;
     STORE *          m_store;
 
     uint16_t         m_port;
@@ -97,8 +103,6 @@ private:
     void CleanupConns();
     void HandleEvents(const fd_set & fds);
     void AcceptConnection();
-
-    //void WriteLogAccessFailed(uint32_t ip);
 };
 
 #endif //CONFIGPROTO_H
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_services.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser_services.cpp
new file mode 100644 (file)
index 0000000..a9599d5
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "parser_services.h"
+
+#include "stg/services.h"
+
+#include <strings.h> // strcasecmp
+
+using STG::PARSER::GET_SERVICES;
+using STG::PARSER::GET_SERVICE;
+using STG::PARSER::ADD_SERVICE;
+using STG::PARSER::DEL_SERVICE;
+using STG::PARSER::CHG_SERVICE;
+
+const char * GET_SERVICES::tag = "GetServices";
+const char * GET_SERVICE::tag  = "AddService";
+const char * ADD_SERVICE::tag  = "AddService";
+const char * DEL_SERVICE::tag  = "DelService";
+const char * CHG_SERVICE::tag  = "SetService";
+
+void GET_SERVICES::CreateAnswer()
+{
+    // TODO: no priviledges implemented yet
+    /*const PRIV * priv = m_currAdmin.GetPriv();
+    if (!priv->serviceChg)
+    {
+        m_answer = "<Error Result=\"Error. Access denied.\"/>";
+        return;
+    }*/
+
+    m_answer = "<Services>";
+    SERVICE_CONF conf;
+    int h = m_services.OpenSearch();
+    while (m_services.SearchNext(h, &conf) == 0)
+    {
+        m_answer += "<Service name=\"" + conf.name +
+                    "\" comment=\"" + Encode12str(conf.comment) +
+                    "\" cost=\"" + x2str(conf.cost) +
+                    "\" payDay=\"" + x2str(conf.payDay) + "\"/>";
+    }
+    m_services.CloseSearch(h);
+    m_answer += "</Services>";
+}
+
+int GET_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+    if (strcasecmp(el, m_tag.c_str()) == 0)
+    {
+        m_name = attr[1];
+        return 0;
+    }
+    return -1;
+}
+
+void GET_SERVICE::CreateAnswer()
+{
+    // TODO: no priviledges implemented yet
+    /*const PRIV * priv = m_currAdmin.GetPriv();
+    if (!priv->serviceChg)
+    {
+        m_answer = "<Error Result=\"Error. Access denied.\"/>";
+        return;
+    }*/
+
+    SERVICE_CONF conf;
+    if (!m_services.Find(m_name, &conf))
+        m_answer = "<Error result=\"Service '" + m_name + "' does not exist.\"/>";
+    else
+        m_answer += "<" + m_tag + " name=\"" + conf.name +
+                    "\" comment=\"" + Encode12str(conf.comment) +
+                    "\" cost=\"" + x2str(conf.cost) +
+                    "\" payDay=\"" + x2str(conf.payDay) + "\"/>";
+}
+
+int ADD_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+    if (strcasecmp(el, m_tag.c_str()) == 0)
+    {
+        m_name = attr[1];
+        return 0;
+    }
+    return -1;
+}
+
+void ADD_SERVICE::CreateAnswer()
+{
+    SERVICE_CONF conf(m_name);
+    if (m_services.Add(conf, &m_currAdmin) == 0)
+        m_answer = "<" + m_tag + " result=\"Ok\"/>";
+    else
+        m_answer = "<" + m_tag + " result=\"" + m_services.GetStrError() + "\"/>";
+}
+
+int DEL_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+    if (strcasecmp(el, m_tag.c_str()) == 0)
+    {
+        m_name = attr[1];
+        return 0;
+    }
+    return -1;
+}
+
+void DEL_SERVICE::CreateAnswer()
+{
+    if (m_services.Del(m_name, &m_currAdmin) == 0)
+        m_answer = "<" + m_tag + " result=\"Ok\"/>";
+    else
+        m_answer = "<" + m_tag + " result=\"" + m_services.GetStrError() + "\"/>";
+}
+
+int CHG_SERVICE::Start(void *, const char * el, const char ** attr)
+{
+    if (strcasecmp(el, m_tag.c_str()) == 0)
+    {
+        for (size_t i = 0; i < 8; i += 2)
+        {
+            if (attr[i] == NULL)
+                break;
+
+            if (strcasecmp(attr[i], "name") == 0)
+            {
+                m_service.name = attr[i + 1];
+                continue;
+            }
+
+            if (strcasecmp(attr[i], "comment") == 0)
+            {
+                m_service.comment = Decode21str(attr[i + 1]);
+                continue;
+            }
+
+            if (strcasecmp(attr[i], "cost") == 0)
+            {
+                double cost = 0;
+                if (str2x(attr[i + 1], cost) == 0)
+                    m_service.cost = cost;
+                else
+                    printfd(__FILE__, "Bad cast from '%s' to double\n", attr[i + 1]);
+                // TODO: log it
+                continue;
+            }
+
+            if (strcasecmp(attr[i], "payDay") == 0)
+            {
+                unsigned payDay;
+                if (str2x(attr[i + 1], payDay) == 0)
+                    m_service.payDay = payDay;
+                else
+                    printfd(__FILE__, "Bad cast from '%s' to unsigned\n", attr[i + 1]);
+                // TODO: log it
+                continue;
+            }
+        }
+
+        return 0;
+    }
+    return -1;
+}
+
+void CHG_SERVICE::CreateAnswer()
+{
+    if (m_service.name.empty())
+    {
+        m_answer = "<" + m_tag + " result=\"Empty service name.\"/>";
+        return;
+    }
+
+    if (!m_services.Exists(m_service.name.const_data()))
+    {
+        m_answer = "<" + m_tag + " result = \"Service '" + m_service.name.const_data() + "' does not exist.\"/>";
+        return;
+    }
+
+    SERVICE_CONF orig;
+    m_services.Find(m_service.name.const_data(), &orig);
+
+    SERVICE_CONF_RES conf(orig);
+    conf.Splice(m_service);
+
+    if (m_services.Change(conf.GetData(), &m_currAdmin) != 0)
+        m_answer = "<" + m_tag + " result = \"" + m_services.GetStrError() + "\"/>";
+    else
+        m_answer = "<" + m_tag + " result = \"Ok\"/>";
+}
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_services.h b/projects/stargazer/plugins/configuration/sgconfig/parser_services.h
new file mode 100644 (file)
index 0000000..f4d87fe
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONFIG_PARSER_SERVICES_H__
+#define __STG_SGCONFIG_PARSER_SERVICES_H__
+
+#include "parser.h"
+
+#include "stg/service_conf.h"
+
+#include "stg/common.h"
+
+#include <string>
+
+class SERVICES;
+
+namespace STG
+{
+namespace PARSER
+{
+
+class GET_SERVICES: public BASE_PARSER
+{
+    public:
+        class FACTORY : public BASE_PARSER::FACTORY
+        {
+            public:
+                FACTORY(const SERVICES & services) : m_services(services) {}
+                virtual BASE_PARSER * create(const ADMIN & admin) { return new GET_SERVICES(admin, m_services); }
+                static void Register(REGISTRY & registry, const SERVICES & services)
+                { registry[ToLower(tag)] = new FACTORY(services); }
+            private:
+                const SERVICES & m_services;
+        };
+
+        static const char * tag;
+
+        GET_SERVICES(const ADMIN & admin, const SERVICES & services)
+            : BASE_PARSER(admin, tag), m_services(services) {}
+
+    private:
+        const SERVICES & m_services;
+
+        void CreateAnswer();
+};
+
+class GET_SERVICE: public BASE_PARSER
+{
+    public:
+        class FACTORY : public BASE_PARSER::FACTORY
+        {
+            public:
+                FACTORY(const SERVICES & services) : m_services(services) {}
+                virtual BASE_PARSER * create(const ADMIN & admin) { return new GET_SERVICE(admin, m_services); }
+                static void Register(REGISTRY & registry, SERVICES & services)
+                { registry[ToLower(tag)] = new FACTORY(services); }
+            private:
+                const SERVICES & m_services;
+        };
+
+        static const char * tag;
+
+        GET_SERVICE(const ADMIN & admin, const SERVICES & services)
+            : BASE_PARSER(admin, tag), m_services(services) {}
+        int Start(void * data, const char * el, const char ** attr);
+
+    private:
+        std::string m_name;
+        const SERVICES & m_services;
+
+        void CreateAnswer();
+};
+
+class ADD_SERVICE: public BASE_PARSER
+{
+    public:
+        class FACTORY : public BASE_PARSER::FACTORY
+        {
+            public:
+                FACTORY(SERVICES & services) : m_services(services) {}
+                virtual BASE_PARSER * create(const ADMIN & admin) { return new ADD_SERVICE(admin, m_services); }
+                static void Register(REGISTRY & registry, SERVICES & services)
+                { registry[ToLower(tag)] = new FACTORY(services); }
+            private:
+                SERVICES & m_services;
+        };
+
+        static const char * tag;
+
+        ADD_SERVICE(const ADMIN & admin, SERVICES & services)
+            : BASE_PARSER(admin, tag), m_services(services) {}
+        int Start(void * data, const char * el, const char ** attr);
+
+    private:
+        std::string m_name;
+        SERVICES & m_services;
+
+        void CreateAnswer();
+};
+
+class DEL_SERVICE: public BASE_PARSER
+{
+    public:
+        class FACTORY : public BASE_PARSER::FACTORY
+        {
+            public:
+                FACTORY(SERVICES & services) : m_services(services) {}
+                virtual BASE_PARSER * create(const ADMIN & admin) { return new DEL_SERVICE(admin, m_services); }
+                static void Register(REGISTRY & registry, SERVICES & services)
+                { registry[ToLower(tag)] = new FACTORY(services); }
+            private:
+                SERVICES & m_services;
+        };
+
+        static const char * tag;
+
+        DEL_SERVICE(const ADMIN & admin, SERVICES & services)
+            : BASE_PARSER(admin, tag), m_services(services) {}
+        int Start(void * data, const char * el, const char ** attr);
+
+    private:
+        std::string m_name;
+        SERVICES & m_services;
+
+        void CreateAnswer();
+};
+
+class CHG_SERVICE: public BASE_PARSER
+{
+    public:
+        class FACTORY : public BASE_PARSER::FACTORY
+        {
+            public:
+                FACTORY(SERVICES & services) : m_services(services) {}
+                virtual BASE_PARSER * create(const ADMIN & admin) { return new CHG_SERVICE(admin, m_services); }
+                static void Register(REGISTRY & registry, SERVICES & services)
+                { registry[ToLower(tag)] = new FACTORY(services); }
+            private:
+                SERVICES & m_services;
+        };
+
+        static const char * tag;
+
+        CHG_SERVICE(const ADMIN & admin, SERVICES & services)
+            : BASE_PARSER(admin, tag), m_services(services) {}
+        int Start(void * data, const char * el, const char ** attr);
+
+    private:
+        SERVICE_CONF_RES m_service;
+        SERVICES & m_services;
+
+        void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_user_info.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser_user_info.cpp
new file mode 100644 (file)
index 0000000..89dd388
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "parser_user_info.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+
+#include <strings.h> // strcasecmp
+
+using STG::PARSER::USER_INFO;
+
+const char * USER_INFO::tag = "GetUserInfo";
+
+int USER_INFO::Start(void * /*data*/, const char *el, const char **attr)
+{
+    if (strcasecmp(el, m_tag.c_str()) != 0)
+        return -1;
+
+    if (!attr[1])
+        return -1;
+
+    m_login = attr[1];
+    return 0;
+}
+
+void USER_INFO::CreateAnswer()
+{
+    CONST_USER_PTR u;
+    if (m_users.FindByName(m_login, &u))
+    {
+        m_answer = "<UserInfo result=\"error\"/>";
+        return;
+    }
+
+    m_answer = "<UserInfo lastAuthTime=\"" + x2str(u->GetAuthorizedModificationTime()) + "\"" +
+             " lastDisconnectTime=\"" + x2str(u->GetConnectedModificationTime()) + "\"" +
+             " connected=\"" + (u->GetConnected() ? "true" : "false") + "\"" +
+             " lastDisconnectReason=\"" + u->GetLastDisconnectReason() + "\">";
+    std::vector<std::string> list(u->GetAuthorizers());
+    for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
+        m_answer += "<Auth name=\"" + *it + "\"/>";
+    m_answer += "</UserInfo>";
+}
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_user_info.h b/projects/stargazer/plugins/configuration/sgconfig/parser_user_info.h
new file mode 100644 (file)
index 0000000..76153f5
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_PARSER_USER_INFO_H__
+#define __STG_PARSER_USER_INFO_H__
+
+#include "parser.h"
+
+#include "stg/common.h"
+
+#include <string>
+
+class USERS;
+
+namespace STG
+{
+namespace PARSER
+{
+
+class USER_INFO : public BASE_PARSER
+{
+    public:
+        class FACTORY : public BASE_PARSER::FACTORY
+        {
+            public:
+                FACTORY(const USERS & users) : m_users(users) {}
+                virtual BASE_PARSER * create(const ADMIN & admin) { return new USER_INFO(admin, m_users); }
+                static void Register(REGISTRY & registry, const USERS & users)
+                { registry[ToLower(tag)] = new FACTORY(users); }
+            private:
+                const USERS & m_users;
+        };
+
+        static const char * tag;
+
+        USER_INFO(const ADMIN & admin, const USERS & users)
+            : BASE_PARSER(admin, tag), m_users(users) {}
+        int Start(void * data, const char * el, const char ** attr);
+
+    private:
+        const USERS & m_users;
+        std::string m_login;
+
+        void CreateAnswer();
+};
+
+} // namespace PARSER
+} // namespace STG
+
+#endif
index d1fbf24c36a271a93d69bdd035c430722f7ea07b..bf4f619559a942863044e876ad9af676d59121c6 100644 (file)
@@ -53,6 +53,8 @@ class STG_CONFIG : public PLUGIN
         void                SetUsers(USERS * users) { config.SetUsers(users); }
         void                SetTariffs(TARIFFS * tariffs) { config.SetTariffs(tariffs); }
         void                SetAdmins(ADMINS * admins) { config.SetAdmins(admins); }
+        void                SetServices(SERVICES * services) { config.SetServices(services); }
+        void                SetCorporations(CORPORATIONS * corporations) { config.SetCorporations( corporations); }
         void                SetStore(STORE * store) { config.SetStore(store); }
         void                SetStgSettings(const SETTINGS * s) { config.SetSettings(s); }
         void                SetSettings(const MODULE_SETTINGS & s) { settings = s; }
index d5cfefaba6fb799bfa5e5f7070871660e63acd54..359b55e218bab974f07f2bb56a31d0c7695321fc 100644 (file)
@@ -67,6 +67,16 @@ const int pt_mega = 1024 * 1024;
 namespace
 {
 PLUGIN_CREATOR<FILES_STORE> fsc;
+
+bool CheckAndCreate(const std::string & dir, mode_t mode)
+{
+if (access(dir.c_str(), F_OK) == 0)
+    return true;
+if (mkdir(dir.c_str(), mode) == 0)
+    return true;
+return false;
+}
+
 }
 
 extern "C" STORE * GetStore();
@@ -244,8 +254,33 @@ if (workDir.size() && workDir[workDir.size() - 1] == '/')
     workDir.resize(workDir.size() - 1);
     }
 usersDir = workDir + "/users/";
+if (!CheckAndCreate(usersDir, GetConfModeDir()))
+    {
+    errorStr = usersDir + " doesn't exist. Failed to create.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
 tariffsDir = workDir + "/tariffs/";
+if (!CheckAndCreate(tariffsDir, GetConfModeDir()))
+    {
+    errorStr = tariffsDir + " doesn't exist. Failed to create.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
 adminsDir = workDir + "/admins/";
+if (!CheckAndCreate(adminsDir, GetConfModeDir()))
+    {
+    errorStr = adminsDir + " doesn't exist. Failed to create.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+servicesDir = workDir + "/services/";
+if (!CheckAndCreate(servicesDir, GetConfModeDir()))
+    {
+    errorStr = servicesDir + " doesn't exist. Failed to create.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
 
 return 0;
 }
@@ -410,6 +445,24 @@ STG_LOCKER lock(&mutex);
 
 tariffList->swap(files);
 
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetServicesList(std::vector<std::string> * list) const
+{
+std::vector<std::string> files;
+
+if (GetFileList(&files, storeSettings.GetServicesDir(), S_IFREG, ".serv"))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Failed to open '" + storeSettings.GetServicesDir() + "': " + std::string(strerror(errno));
+    return -1;
+    }
+
+STG_LOCKER lock(&mutex);
+
+list->swap(files);
+
 return 0;
 }
 //-----------------------------------------------------------------------------
@@ -1540,6 +1593,116 @@ std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
     cf.WriteTime("ChangePolicyTimeout", td.tariffConf.changePolicyTimeout);
     }
 
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::AddService(const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
+
+if (Touch(fileName))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Cannot create file " + fileName;
+    printfd(__FILE__, "FILES_STORE::AddService - failed to add service '%s'\n", name.c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::DelService(const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
+if (unlink(fileName.c_str()))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "unlink failed. Message: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::SaveService(const SERVICE_CONF & conf) const
+{
+std::string fileName;
+
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), conf.name.c_str());
+
+    {
+    CONFIGFILE cf(fileName, true);
+
+    int e = cf.Error();
+
+    if (e)
+        {
+        STG_LOCKER lock(&mutex);
+        errorStr = "Cannot write service " + conf.name + ". " + fileName;
+        printfd(__FILE__, "FILES_STORE::SaveService - failed to save service '%s'\n", conf.name.c_str());
+        return -1;
+        }
+
+    cf.WriteString("name", conf.name);
+    cf.WriteString("comment", conf.comment);
+    cf.WriteDouble("cost", conf.cost);
+    cf.WriteInt("pay_day", conf.payDay);
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreService(SERVICE_CONF * conf, const std::string & name) const
+{
+std::string fileName;
+strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
+CONFIGFILE cf(fileName);
+
+if (cf.Error())
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Cannot open " + fileName;
+    printfd(__FILE__, "FILES_STORE::RestoreService - failed to restore service '%s'\n", name.c_str());
+    return -1;
+    }
+
+if (cf.ReadString("name", &conf->name, name))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Error in parameter 'name'";
+    printfd(__FILE__, "FILES_STORE::RestoreService - name read failed for service '%s'\n", name.c_str());
+    return -1;
+    }
+
+if (cf.ReadString("comment", &conf->comment, ""))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Error in parameter 'comment'";
+    printfd(__FILE__, "FILES_STORE::RestoreService - comment read failed for service '%s'\n", name.c_str());
+    return -1;
+    }
+
+if (cf.ReadDouble("cost", &conf->cost, 0.0))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Error in parameter 'cost'";
+    printfd(__FILE__, "FILES_STORE::RestoreService - cost read failed for service '%s'\n", name.c_str());
+    return -1;
+    }
+
+unsigned short value = 0;
+if (cf.ReadUShortInt("pay_day", &value, 0))
+    {
+    STG_LOCKER lock(&mutex);
+    errorStr = "Error in parameter 'pay_day'";
+    printfd(__FILE__, "FILES_STORE::RestoreService - pay day read failed for service '%s'\n", name.c_str());
+    return -1;
+    }
+conf->payDay = value;
+
 return 0;
 }
 //-----------------------------------------------------------------------------
index 1d72f287d01dac7e1108b4e69bf97a62db3ccd3a..2fe41326cfe14b35837ceb1a37d4204d11020e85 100644 (file)
@@ -50,6 +50,7 @@ public:
     std::string  GetUsersDir() const { return usersDir; }
     std::string  GetAdminsDir() const { return adminsDir; }
     std::string  GetTariffsDir() const { return tariffsDir; }
+    std::string  GetServicesDir() const { return servicesDir; }
 
     mode_t  GetStatMode() const { return statMode; }
     mode_t  GetStatModeDir() const;
@@ -88,6 +89,7 @@ private:
     std::string  usersDir;
     std::string  adminsDir;
     std::string  tariffsDir;
+    std::string  servicesDir;
 
     mode_t  statMode;
     uid_t   statUID;
@@ -175,11 +177,11 @@ public:
     virtual int DelCorp(const std::string &) const { return 0; }
 
     // Services
-    virtual int GetServicesList(std::vector<std::string> *) const { return 0; }
-    virtual int SaveService(const SERVICE_CONF &) const { return 0; }
-    virtual int RestoreService(SERVICE_CONF *, const std::string &) const { return 0; }
-    virtual int AddService(const std::string &) const { return 0; }
-    virtual int DelService(const std::string &) const { return 0; }
+    virtual int GetServicesList(std::vector<std::string> *) const;
+    virtual int SaveService(const SERVICE_CONF &) const;
+    virtual int RestoreService(SERVICE_CONF *, const std::string &) const;
+    virtual int AddService(const std::string &) const;
+    virtual int DelService(const std::string &) const;
 
     virtual void SetSettings(const MODULE_SETTINGS & s) { settings = s; }
     virtual int ParseSettings();
index 4e666794c90e62f97a07fd8482b3dc00e45dd38f..6f8177cab11bc04445b85d1503b090a0bdfd4124 100644 (file)
@@ -290,7 +290,6 @@ try
     st->Get(3, td->tariffConf.fee);
     st->Get(4, td->tariffConf.free);
     st->Get(5, td->tariffConf.passiveCost);
-    //st->Get(6, td->tariffConf.traffType);
     td->tariffConf.traffType = TARIFF::IntToTraffType(Get<int>(st, 6));
     if (schemaVersion > 0)
         td->tariffConf.period = TARIFF::StringToPeriod(Get<std::string>(st, 7));
index 2e92603ea3a201c5ab87c405bbc8637e40d77268..fbeacae5332e115fc6d7d3092fa78863eaea16b0 100644 (file)
@@ -302,7 +302,7 @@ try
     st->Prepare("insert into tb_users_services (fk_user, fk_service) \
                     values (?, (select pk_service from tb_services \
                                 where name = ?))");
-    for(std::vector<std::string>::const_iterator it = conf.service.begin(); it != conf.service.end(); ++it)
+    for(std::vector<std::string>::const_iterator it = conf.services.begin(); it != conf.services.end(); ++it)
         {
         st->Set(1, uid);
         st->Set(2, *it);
@@ -516,7 +516,7 @@ try
         {
         std::string name;
         st->Get(1, name);
-        conf->service.push_back(name);
+        conf->services.push_back(name);
         }
 
     // User data
index 35551c5db1ecf24bd509fe06ad3c4cd1a78e4a1c..a9836911b45ffec8e5b15ee377bde607f5f0ca9e 100644 (file)
  *
  */
 
-#include <string>
-#include <vector>
+#include "postgresql_store.h"
 
-#include <libpq-fe.h>
+#include "postgresql_store_utils.h"
+#include "postgresql_store.h"
 
 #include "stg/module_settings.h"
 #include "stg/plugin_creator.h"
-#include "postgresql_store_utils.h"
-#include "postgresql_store.h"
+
+#include <string>
+#include <vector>
+
+#include <libpq-fe.h>
 
 namespace
 {
@@ -89,13 +92,12 @@ pthread_mutex_destroy(&mutex);
 int POSTGRESQL_STORE::ParseSettings()
 {
 std::vector<PARAM_VALUE>::iterator i;
-std::string s;
 
 for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
     {
     if (i->value.empty())
         continue;
-    s = ToLower(i->param);
+    std::string s = ToLower(i->param);
     if (s == "server")
         {
         server = i->value.front();
index 519074b131707887647048d61e5b96fac8b8a657..1ab5d0e8c2c806e28974c30065975727efc9bfa4 100644 (file)
@@ -565,7 +565,7 @@ if (PQresultStatus(result) != PGRES_COMMAND_OK)
 
 PQclear(result);
 
-if (SaveUserServices(uid, conf.service))
+if (SaveUserServices(uid, conf.services))
     {
     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
     if (RollbackTransaction())
@@ -884,7 +884,7 @@ tuples = PQntuples(result);
 
 for (int i = 0; i < tuples; ++i)
     {
-    conf->service.push_back(PQgetvalue(result, i, 0));
+    conf->services.push_back(PQgetvalue(result, i, 0));
     }
 
 PQclear(result);
index 9845242991ab5e1f91f1706dffd6ab490adb5db9..9a5101e121c04a605e1698f08305445e31687818 100644 (file)
  *
  */
 
+#include "postgresql_store.h"
+
+#include "stg/common.h"
+
 #include <string>
 #include <ctime>
 
 #include <libpq-fe.h>
 
-#include "stg/common.h"
-#include "postgresql_store.h"
-
 extern volatile time_t stgTime;
 
 int POSTGRESQL_STORE::StartTransaction() const
@@ -93,10 +94,10 @@ int error = 0;
 char * buf = new char[(value.length() << 1) + 1];
 
 PQescapeStringConn(connection,
-                  buf,
-                  value.c_str(),
-                  value.length(),
-                  &error);
+                   buf,
+                   value.c_str(),
+                   value.length(),
+                   &error);
 
 if (error)
     {
@@ -131,8 +132,6 @@ if (year)
 else
     {
     time_t curTime = stgTime;
-    /*time(&curTime);*/
-
     localtime_r(&curTime, &brokenTime);
     }
 
@@ -144,4 +143,3 @@ strftime(buf, 32, "%Y-%m-%d", &brokenTime);
 
 date = buf;
 }
-
index 0cf9501bced5db222ec6413721f9cf70f1b51a6d..212ed6343c95bd8e289c044501b3c9dbfd37e539 100644 (file)
@@ -57,6 +57,7 @@ SETTINGS_IMPL::SETTINGS_IMPL(const std::string & cd)
       spreadFee(false),
       freeMbAllowInet(false),
       dayFeeIsLastDay(false),
+      stopOnError(true),
       writeFreeMbTraffCost(false),
       showFeeInCash(true),
       messageTimeout(0),
@@ -69,9 +70,7 @@ SETTINGS_IMPL::SETTINGS_IMPL(const std::string & cd)
 }
 //-----------------------------------------------------------------------------
 SETTINGS_IMPL::SETTINGS_IMPL(const SETTINGS_IMPL & rval)
-    : SETTINGS(),
-      strError(),
-      modulesPath(rval.modulesPath),
+    : modulesPath(rval.modulesPath),
       dirName(rval.dirName),
       confDir(rval.confDir),
       scriptsDir(rval.scriptsDir),
@@ -90,6 +89,7 @@ SETTINGS_IMPL::SETTINGS_IMPL(const SETTINGS_IMPL & rval)
       spreadFee(rval.spreadFee),
       freeMbAllowInet(rval.freeMbAllowInet),
       dayFeeIsLastDay(rval.dayFeeIsLastDay),
+      stopOnError(rval.stopOnError),
       writeFreeMbTraffCost(rval.writeFreeMbTraffCost),
       showFeeInCash(rval.showFeeInCash),
       messageTimeout(rval.messageTimeout),
@@ -125,6 +125,7 @@ SETTINGS_IMPL & SETTINGS_IMPL::operator=(const SETTINGS_IMPL & rhs)
     spreadFee = rhs.spreadFee;
     freeMbAllowInet = rhs.freeMbAllowInet;
     dayFeeIsLastDay = rhs.dayFeeIsLastDay;
+    stopOnError = rhs.stopOnError;
     writeFreeMbTraffCost = rhs.writeFreeMbTraffCost;
     showFeeInCash = rhs.showFeeInCash;
     messageTimeout = rhs.messageTimeout;
@@ -334,6 +335,15 @@ while (node)
             }
         }
 
+    if (strcasecmp(node->getName(), "StopOnError") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &stopOnError) != 0)
+            {
+            strError = "Incorrect StopOnError value: \'" + std::string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        }
+
     if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
         {
         if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
index cc35393b2d18fab8d21cc705f3d1687fa031f43c..de27b72884a8a46d5a3bceca78503f5bac3923f5 100644 (file)
@@ -84,6 +84,7 @@ public:
     bool                GetSpreadFee() const { return spreadFee; }
     bool                GetFreeMbAllowInet() const { return freeMbAllowInet; }
     bool                GetDayFeeIsLastDay() const { return dayFeeIsLastDay; }
+    bool                GetStopOnError() const { return stopOnError; }
     bool                GetWriteFreeMbTraffCost() const
         { return writeFreeMbTraffCost; }
     bool                GetShowFeeInCash() const { return showFeeInCash; }
@@ -132,6 +133,7 @@ private:
     bool        spreadFee;
     bool        freeMbAllowInet;
     bool        dayFeeIsLastDay;
+    bool        stopOnError;
     bool        writeFreeMbTraffCost;
     bool        showFeeInCash;
     unsigned    messageTimeout;
index 36c0f84f01f02abb6e082d47d31e246c4eeef4b1..0e92975c2c0c064e97d1f8497cd78148aa27b086 100644 (file)
@@ -1342,6 +1342,75 @@ switch (settings->GetFeeChargeType())
 ResetPassiveTime();
 }
 //-----------------------------------------------------------------------------
+void USER_IMPL::ProcessServices()
+{
+struct tm tms;
+time_t t = stgTime;
+localtime_r(&t, &tms);
+
+double passiveTimePart = 1.0;
+if (!settings->GetFullFee())
+    {
+    passiveTimePart = GetPassiveTimePart();
+    }
+else
+    {
+    if (passive.ConstData())
+        {
+        printfd(__FILE__, "Don't charge fee `cause we are passive\n");
+        return;
+        }
+    }
+
+for (size_t i = 0; i < property.Conf().services.size(); ++i)
+    {
+    SERVICE_CONF conf;
+    if (m_services.Find(property.Conf().services[i], &conf))
+        continue;
+    if (conf.payDay == tms.tm_mday ||
+        (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
+        {
+        double c = cash;
+        double fee = conf.cost * passiveTimePart;
+        printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
+                login.c_str(),
+                cash.ConstData(),
+                credit.ConstData(),
+                tariff->GetFee(),
+                passiveTimePart,
+                fee);
+        switch (settings->GetFeeChargeType())
+            {
+            case 0:
+                property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
+                SetPrepaidTraff();
+                break;
+            case 1:
+                if (c + credit >= 0)
+                    {
+                    property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
+                    SetPrepaidTraff();
+                    }
+                break;
+            case 2:
+                if (c + credit >= fee)
+                    {
+                    property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
+                    SetPrepaidTraff();
+                    }
+                break;
+            case 3:
+                if (c >= 0)
+                    {
+                    property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
+                    SetPrepaidTraff();
+                    }
+                break;
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
 void USER_IMPL::SetPrepaidTraff()
 {
 if (tariff != NULL)
index 77887514b272b2603d5a3422b028562479736a73..75f02a0e180c6d6db6611ab7f759f9aef71e34d1 100644 (file)
@@ -219,6 +219,7 @@ public:
     void            ProcessDayFeeSpread();
     void            ProcessNewMonth();
     void            ProcessDailyFee();
+    void            ProcessServices();
 
     bool            IsInetable();
     std::string     GetEnabledDirs() const;
index 18d1abaf163dd4758d3113fa068c7d0fd723326a..9985615f85d06c58c9d3ba766cb668a224964379 100644 (file)
@@ -345,6 +345,7 @@ if (store->GetUsersList(&usersList) < 0)
 
 user_iter ui;
 
+unsigned errors = 0;
 for (unsigned int i = 0; i < usersList.size(); i++)
     {
     USER_IMPL u(settings, store, tariffs, sysAdmin, this, m_services);
@@ -355,13 +356,26 @@ for (unsigned int i = 0; i < usersList.size(); i++)
 
     AddUserIntoIndexes(ui);
 
-    if (ui->ReadConf() < 0)
-        return -1;
+    if (settings->GetStopOnError())
+        {
+        if (ui->ReadConf() < 0)
+            return -1;
 
-    if (ui->ReadStat() < 0)
-        return -1;
+        if (ui->ReadStat() < 0)
+            return -1;
+        }
+    else
+        {
+        if (ui->ReadConf() < 0)
+            errors++;
+
+        if (ui->ReadStat() < 0)
+            errors++;
+        }
     }
 
+if (errors > 0)
+    return -1;
 return 0;
 }
 //-----------------------------------------------------------------------------
@@ -503,6 +517,7 @@ else
     }
 
 std::for_each(users.begin(), users.end(), std::mem_fun_ref(&USER_IMPL::ProcessDailyFee));
+std::for_each(users.begin(), users.end(), std::mem_fun_ref(&USER_IMPL::ProcessServices));
 
 if (settings->GetDayFeeIsLastDay())
     {
index fc7c35ce86c5b19eebc1a569c3120ae2e1fc2ce2..a4722a00f3e301b9bc84dc6a500552d802dfefbb 100644 (file)
@@ -514,6 +514,22 @@ uint32_t inet_strington(const std::string & value)
     return result;
 }
 //-----------------------------------------------------------------------------
+std::string TimeToString(time_t time)
+{
+struct tm brokenTime;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+gmtime_r(&time, &brokenTime);
+
+char buf[32];
+strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
+
+return buf;
+}
+//-----------------------------------------------------------------------------
 int ParseTariffTimeStr(const char * str, int &h1, int &m1, int &h2, int &m2)
 {
 char hs1[10], ms1[10], hs2[10], ms2[10];
@@ -784,11 +800,6 @@ if (errno == ERANGE)
 
 return 0;
 }
-//---------------------------------------------------------------------------
-int str2x(const std::string & str, double & x)
-{
-return strtodouble2(str.c_str(), x);
-}
 #ifndef WIN32
 //---------------------------------------------------------------------------
 int str2x(const std::string & str, int64_t & x)
@@ -859,6 +870,12 @@ std::string & Trim(std::string & val)
 return TrimR(TrimL(val));
 }
 //---------------------------------------------------------------------------
+std::string Trim(const std::string & val)
+{
+std::string res(val);
+return TrimR(TrimL(res));
+}
+//---------------------------------------------------------------------------
 std::string ToLower(std::string value)
 {
     std::transform(value.begin(), value.end(), value.begin(), ::tolower);
index 8e82d2a84e17b099ef63a8b0ad288cc3bdc66c06..a9cc05b1f94e8df0e40e720810023741344fbbca 100644 (file)
@@ -58,9 +58,8 @@ const char    * IntToKMG(int64_t a, int statType = ST_F);
 const char    * LogDate(time_t t);
 int             ParesTimeStat(const char * str);
 int             IsTimeStat(struct tm * t, int statTime);
-/*bool            IsDigit(char c);
-bool            IsAlpha(char c);*/
-int             strtodouble2(const char * s, double &a);
+int             strtodouble2(const char * str, double & value);
+inline int      strtodouble2(const std::string & str, double & value) { return strtodouble2(str.c_str(), value); }
 int             printfd(const char * __file__, const char * fmt, ...);
 void            Encode12(char * dst, const char * src, size_t srcLen);
 void            Decode21(char * dst, const char * src);
@@ -78,9 +77,9 @@ void            WinToKOI(const std::string & s1, std::string * s2);
 int             DaysInMonth(unsigned year, unsigned mon);
 int             DaysInCurrentMonth();
 int             Min8(int a);
-//char          * inet_ntostr(unsigned long);
 std::string     inet_ntostring(uint32_t);
 uint32_t        inet_strington(const std::string & value);
+std::string     TimeToString(time_t time);
 int             strprintf(std::string * str, const char * fmt, ...);
 int             ParseTariffTimeStr(const char * str, int &h1, int &m1, int &h2, int &m2);
 uint32_t        CalcMask(uint32_t msk);
@@ -99,11 +98,13 @@ void            SwapBytes(int64_t & value);
 std::string &   TrimL(std::string & val);
 std::string &   TrimR(std::string & val);
 std::string &   Trim(std::string & val);
+std::string     Trim(const std::string & val);
 
-std::string ToLower(std::string value);
-std::string ToUpper(std::string value);
+std::string     ToLower(std::string value);
+std::string     ToUpper(std::string value);
 
 template <typename C, typename F>
+inline
 C Split(const std::string & value, char delim, F conv)
 {
 C res;
@@ -120,6 +121,7 @@ return res;
 }
 
 template <typename T>
+inline
 T FromString(const std::string & value)
 {
 T res;
@@ -128,10 +130,18 @@ stream >> res;
 return res;
 }
 
+template <>
+inline
+std::string FromString<std::string>(const std::string & value)
+{
+return value;
+}
+
 template <typename C>
+inline
 C Split(const std::string & value, char delim)
 {
-    return Split<C>(value, delim, FromString);
+    return Split<C>(value, delim, FromString<typename C::value_type>);
 }
 
 std::string IconvString(const std::string & source, const std::string & from, const std::string & to);
@@ -155,7 +165,8 @@ time_t readTime(const std::string & value);
 //-----------------------------------------------------------------------------
 int str2x(const std::string & str, int32_t & x);
 int str2x(const std::string & str, uint32_t & x);
-int str2x(const std::string & str, double & x);
+inline
+int str2x(const std::string & str, double & x) { return strtodouble2(str.c_str(), x); }
 #ifndef WIN32
 int str2x(const std::string & str, int64_t & x);
 int str2x(const std::string & str, uint64_t & x);
@@ -212,7 +223,7 @@ int str2x(const std::string & str, varT & x)
         x += str[i] - '0';
     }
 
-    x*= minus;
+    x *= minus;
 
     return 0;
 }
index 783a9c309a60340a475842ef2e38ea1af99bb556..80e39cd3458ec53c1fea6587d38d6b33d56e2ed4 100644 (file)
 #define MAXKEYBYTES 56          /* 448 bits */
 
 #ifdef __cplusplus
+#include <cstddef> // size_t
 extern "C" {
+#else
+#include <stddef.h> // size_t
 #endif
 
 typedef struct {
index c8c09b3e7ec258005800aefbb153cb94a255a5d9..803f7ac4edffd2464652fe8547937b35b0f42bad 100644 (file)
@@ -10,8 +10,7 @@ INCS = pinger.h
 
 LIBS = $(LIB_THREAD)
 
-LIB_INCS = -I ../locker.lib/include \
-          -I ../common.lib/include
+LIB_INCS = -I ../common.lib/include
 
 include ../Makefile.in
 
index e3bfa76219fdab686afac6203e6a76186be74e83..d7bc80c01390fdb372f611ff9a11880b4a9b07a4 100644 (file)
@@ -8,14 +8,28 @@ STGLIBS = -lstgcommon \
           -lstgcrypto
 LIBS = -lexpat
 
-SRCS =         netunit.cpp \
-        parser.cpp \
+SRCS =  parsers/property.cpp \
+        parsers/simple.cpp \
+        parsers/server_info.cpp \
+        parsers/get_admin.cpp \
+        parsers/chg_admin.cpp \
+        parsers/get_tariff.cpp \
+        parsers/chg_tariff.cpp \
+        parsers/auth_by.cpp \
+        parsers/get_user.cpp \
+        parsers/chg_user.cpp \
+        parsers/get_service.cpp \
+        parsers/chg_service.cpp \
+        parsers/get_corp.cpp \
+        parsers/chg_corp.cpp \
+        netunit.cpp \
         servconf.cpp
 
+
 INCS = servconf.h \
        netunit.h
 
 LIB_INCS = -I ../common.lib/include \
-          -I ../crypto.lib/include
+           -I ../crypto.lib/include
 
 include ../Makefile.in
diff --git a/stglibs/srvconf.lib/include/stg/netunit.h b/stglibs/srvconf.lib/include/stg/netunit.h
deleted file mode 100644 (file)
index 664eee6..0000000
+++ /dev/null
@@ -1,120 +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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Revision: 1.6 $
- $Date: 2010/02/11 12:32:53 $
- $Author: faust $
- */
-
-#ifndef NetUnitH
-#define NetUnitH
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <list>
-#include <string>
-
-#include "stg/blowfish.h"
-
-#define  STG_HEADER     "SG04"
-#define  OK_HEADER      "OKHD"
-#define  ERR_HEADER     "ERHD"
-#define  OK_LOGIN       "OKLG"
-#define  ERR_LOGIN      "ERLG"
-#define  OK_LOGINS      "OKLS"
-#define  ERR_LOGINS     "ERLS"
-
-// äÌÉÎÎÁ ÛÉÆÒÕÅÍÏÇÏ É ÐÅÒÅÄÁ×ÁÅÍÏÇ ÚÁ ÏÄÉΠÒÁÚ ÂÌÏËÁ ÉÎÆÏÒÍÁÃÉÉ
-#define  ENC_MSG_LEN    (8)
-
-#define MAX_ERR_STR_LEN (64)
-
-typedef int(*RxCallback_t)(void *, std::list<std::string> *);
-
-enum status
-{
-st_ok = 0,
-st_conn_fail,
-st_send_fail,
-st_recv_fail,
-st_header_err,
-st_login_err,
-st_logins_err,
-st_data_err,
-st_unknown_err,
-st_dns_err,
-st_xml_parse_error,
-st_data_error
-};
-
-enum CONF_STATE
-{
-confHdr = 0,
-confLogin,
-confLoginCipher,
-confData
-};
-//---------------------------------------------------------------------------
-class NETTRANSACT
-{
-public:
-    NETTRANSACT();
-    int     Transact(const char * data);
-    const std::string & GetError() const;
-
-    void    SetRxCallback(void * data, RxCallback_t);
-
-    void    SetServer(const char * serverName);
-    void    SetServerPort(short unsigned p);
-
-    void    SetLogin(const char * l);
-    void    SetPassword(const char * p);
-    ////////////////////////////////////////////
-    int     Connect();
-    int     Disconnect();
-    void    Reset();
-private:
-    int     TxHeader();
-    int     RxHeaderAnswer();
-
-    int     TxLogin();
-    int     RxLoginAnswer();
-
-    int     TxLoginS();
-    int     RxLoginSAnswer();
-
-    int     TxData(const char * text);
-    int     RxDataAnswer();
-
-    std::string server;
-    short unsigned  port;
-    std::string login;
-    std::string password;
-    int     outerSocket;
-    std::list<std::string>   answerList;
-    RxCallback_t RxCallBack;
-    void *  dataRxCallBack;
-    std::string errorMsg;
-};
-//---------------------------------------------------------------------------
-#endif
index 6bf33ddb189288e5daaedfb95c458ace5fe4b510..cd37e49e44b984ae84317c17ac3eeb8bc99baf88 100644 (file)
 
 /*
  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
- /*
- $Revision: 1.10 $
- $Date: 2009/03/17 09:52:35 $
- $Author: faust $
- */
-
-#ifndef SERVCONF_H
-#define SERVCONF_H
+#ifndef __STG_STGLIBS_SERVCONF_H__
+#define __STG_STGLIBS_SERVCONF_H__
 
-#include <expat.h>
-
-#include <list>
-#include <vector>
-#include <string>
+#include "stg/servconf_types.h"
 
+#include "stg/admin_conf.h"
 #include "stg/os_int.h"
-#include "stg/const.h"
-#include "netunit.h"
 
-void Start(void *data, const char *el, const char **attr);
-void End(void *data, const char *el);
+#include <string>
 
-#define MAX_ERR_STR_LEN (64)
-#define IP_STRING_LEN   (255)
-#define UNAME_LEN       (256)
-#define SERV_VER_LEN    (64)
-#define DIRNAME_LEN     (16)
+struct USER_CONF_RES;
+struct USER_STAT_RES;
+struct TARIFF_DATA_RES;
+struct SERVICE_CONF_RES;
+struct CORP_CONF_RES;
 
-//-----------------------------------------------------------------------------
-struct STAT
-{
-    long long   su[DIR_NUM];
-    long long   sd[DIR_NUM];
-    long long   mu[DIR_NUM];
-    long long   md[DIR_NUM];
-    double      freeMb;
-};
-//-----------------------------------------------------------------------------
-struct SERVERINFO
+namespace STG
 {
-    std::string version;
-    int         tariffNum;
-    int         tariffType;
-    int         usersNum;
-    std::string uname;
-    int         dirNum;
-    std::string dirName[DIR_NUM];
-};
-//-----------------------------------------------------------------------------
-struct USERDATA
-{
-    std::string     login;
-    std::string     password;
-    double          cash;
-    double          credit;
-    time_t          creditExpire;
-    double          lastCash;
-    double          prepaidTraff;
-    int             down;
-    int             passive;
-    int             disableDetailStat;
-    int             connected;
-    int             alwaysOnline;
-    uint32_t        ip;
-    std::string     ips;
-    std::string     tariff;
-    std::string     iface;
-    std::string     group;
-    std::string     note;
-    std::string     email;
-    std::string     name;
-    std::string     address;
-    std::string     phone;
-    STAT            stat;
-    std::string     userData[USERDATA_NUM];
 
-    struct USERDATA * next;
-};
-//-----------------------------------------------------------------------------
-typedef void(*RecvUserDataCb_t)(USERDATA * ud, void * data);
-typedef void(*RecvServerInfoDataCb_t)(SERVERINFO * si, void * data);
-typedef int(*RecvChgUserCb_t)(const char * asnwer, void * data);
-typedef int(*RecvCheckUserCb_t)(const char * answer, void * data);
-typedef int(*RecvSendMessageCb_t)(const char * answer, void * data);
-typedef void(*RecvAuthByDataCb_t)(const std::vector<std::string> & list, void * data);
-//-----------------------------------------------------------------------------
-struct ADMINDATA
-{
-    char login[ADM_LOGIN_LEN];
-};
-//-----------------------------------------------------------------------------
-class PARSER
-{
-public:
-    PARSER() {}
-    virtual ~PARSER() {}
-    virtual int ParseStart(const char *el, const char **attr) = 0;
-    virtual void ParseEnd(const char *el) = 0;
-};
-//-----------------------------------------------------------------------------
-class PARSER_CHG_USER: public PARSER
-{
-public:
-    PARSER_CHG_USER();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseAnswer(const char *el, const char **attr);
-    void SetChgUserRecvCb(RecvChgUserCb_t, void * data);
-private:
-    RecvChgUserCb_t RecvChgUserCb;
-    void * chgUserCbData;
-    int depth;
-};
-//-----------------------------------------------------------------------------
-class PARSER_CHECK_USER: public PARSER
-{
-public:
-    PARSER_CHECK_USER();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseAnswer(const char *el, const char **attr);
-    void SetCheckUserRecvCb(RecvCheckUserCb_t, void * data);
-private:
-    RecvCheckUserCb_t RecvCheckUserCb;
-    void * checkUserCbData;
-    int depth;
-};
-//-----------------------------------------------------------------------------
-class PARSER_GET_USERS: public PARSER
-{
-public:
-    PARSER_GET_USERS();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseUsers(const char *el, const char **attr);
-    void ParseUser(const char *el, const char **attr);
-    void ParseUserParams(const char *el, const char **attr);
-    void ParseUserLoadStat(const char * el, const char ** attr);
-    void SetUserDataRecvCb(RecvUserDataCb_t, void * data);
-private:
-    RecvUserDataCb_t RecvUserDataCb;
-    void * userDataCb;
-    USERDATA user;
-    int depth;
-};
-//-----------------------------------------------------------------------------
-class PARSER_GET_USER: public PARSER
-{
-public:
-    PARSER_GET_USER();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseUsers(const char *el, const char **attr);
-    void ParseUser(const char *el, const char **attr);
-    void ParseUserParams(const char *el, const char **attr);
-    void ParseUserLoadStat(const char * el, const char ** attr);
-    void SetUserDataRecvCb(RecvUserDataCb_t, void * data);
-private:
-    RecvUserDataCb_t RecvUserDataCb;
-    void * userDataCb;
-    USERDATA user;
-    int depth;
-    bool error;
-};
-//-----------------------------------------------------------------------------
-class PARSER_GET_SERVER_INFO: public PARSER
-{
-public:
-    PARSER_GET_SERVER_INFO();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseServerInfo(const char *el, const char **attr);
-    bool GetError();
-    void SetServerInfoRecvCb(RecvServerInfoDataCb_t, void * data);
-private:
-    void ParseUname(const char ** attr);
-    void ParseServerVersion(const char ** attr);
-    void ParseUsersNum(const char ** attr);
-    void ParseTariffsNum(const char ** attr);
-    void ParseTariffType(const char ** attr);
-    void ParseDirNum(const char **attr);
-    void ParseDirName(const char **attr, int d);
-
-    RecvServerInfoDataCb_t RecvServerInfoDataCb;
-    void * serverInfoDataCb;
-    int depth;
-    bool error;
-    SERVERINFO serverInfo;
-};
-//-----------------------------------------------------------------------------
-class PARSER_SEND_MESSAGE: public PARSER
-{
-public:
-    PARSER_SEND_MESSAGE();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseAnswer(const char *el, const char **attr);
-    void SetSendMessageRecvCb(RecvSendMessageCb_t, void * data);
-private:
-    RecvSendMessageCb_t RecvSendMessageCb;
-    void * sendMessageCbData;
-    int depth;
-};
-//-----------------------------------------------------------------------------
-class PARSER_AUTH_BY: public PARSER
-{
-public:
-    PARSER_AUTH_BY();
-    int  ParseStart(const char *el, const char **attr);
-    void ParseEnd(const char *el);
-    void ParseServerInfo(const char *el, const char **attr);
-    bool GetError();
-    void SetRecvCb(RecvAuthByDataCb_t, void * data);
-private:
-    RecvAuthByDataCb_t RecvAuthByDataCb;
-    void * authByDataCb;
-    int depth;
-    bool error;
-    std::vector<std::string> list;
-};
-//-----------------------------------------------------------------------------
 class SERVCONF
 {
 public:
-    SERVCONF();
+    SERVCONF(const std::string & server, uint16_t port,
+             const std::string & login, const std::string & password);
+    SERVCONF(const std::string & server, uint16_t port,
+             const std::string & localAddress, uint16_t localPort,
+             const std::string & login, const std::string & password);
     ~SERVCONF();
-    void SetServer(const char * server);
-    void SetPort(uint16_t port);
 
-    void SetAdmLogin(const char * login);
-    void SetAdmPassword(const char * password);
-
-    void SetUserDataRecvCb(RecvUserDataCb_t, void * data);
-    void SetGetUserAuthByRecvCb(RecvAuthByDataCb_t, void * data);
-    void SetServerInfoRecvCb(RecvServerInfoDataCb_t, void * data);
-    void SetChgUserCb(RecvChgUserCb_t, void * data);
-    void SetCheckUserCb(RecvCheckUserCb_t, void * data);
-    void SetGetUserDataRecvCb(RecvUserDataCb_t, void * data);
-    void SetSendMessageCb(RecvSendMessageCb_t, void * data);
-
-    int GetUsers();
-    int GetUser(const char * login);
-    int ChgUser(const char * request);
-    int GetUserAuthBy(const char * login);
-    // TODO: Remove this shit!
-    int MsgUser(const char * request);
-    int SendMessage(const char * login, const char * message, int prio);
-    int GetServerInfo();
-    int CheckUser(const char * login, const char * password);
+    int ServerInfo(SERVER_INFO::CALLBACK f, void * data);
+
+    int RawXML(const std::string & request, RAW_XML::CALLBACK f, void * data);
+
+    int GetAdmins(GET_CONTAINER::CALLBACK<GET_ADMIN::INFO>::TYPE f, void * data);
+    int GetAdmin(const std::string & login, GET_ADMIN::CALLBACK f, void * data);
+    int ChgAdmin(const ADMIN_CONF_RES & conf, SIMPLE::CALLBACK f, void * data);
+    int AddAdmin(const std::string & login,
+                 const ADMIN_CONF_RES & conf,
+                 SIMPLE::CALLBACK f, void * data);
+    int DelAdmin(const std::string & login, SIMPLE::CALLBACK f, void * data);
+
+    int GetTariffs(GET_CONTAINER::CALLBACK<GET_TARIFF::INFO>::TYPE f, void * data);
+    int GetTariff(const std::string & name, GET_TARIFF::CALLBACK f, void * data);
+    int ChgTariff(const TARIFF_DATA_RES & conf, SIMPLE::CALLBACK f, void * data);
+    int AddTariff(const std::string & name,
+                  const TARIFF_DATA_RES & conf,
+                  SIMPLE::CALLBACK f, void * data);
+    int DelTariff(const std::string & name, SIMPLE::CALLBACK f, void * data);
+
+    int GetUsers(GET_CONTAINER::CALLBACK<GET_USER::INFO>::TYPE f, void * data);
+    int GetUser(const std::string & login, GET_USER::CALLBACK f, void * data);
+    int ChgUser(const std::string & login,
+                const USER_CONF_RES & conf,
+                const USER_STAT_RES & stat,
+                SIMPLE::CALLBACK f, void * data);
+    int DelUser(const std::string & login, SIMPLE::CALLBACK f, void * data);
+    int AddUser(const std::string & login,
+                const USER_CONF_RES & conf,
+                const USER_STAT_RES & stat,
+                SIMPLE::CALLBACK f, void * data);
+    int AuthBy(const std::string & login, AUTH_BY::CALLBACK f, void * data);
+    int SendMessage(const std::string & login, const std::string & text, SIMPLE::CALLBACK f, void * data);
+    int CheckUser(const std::string & login, const std::string & password, SIMPLE::CALLBACK f, void * data);
+
+    int GetServices(GET_CONTAINER::CALLBACK<GET_SERVICE::INFO>::TYPE f, void * data);
+    int GetService(const std::string & name, GET_SERVICE::CALLBACK f, void * data);
+    int ChgService(const SERVICE_CONF_RES & conf, SIMPLE::CALLBACK f, void * data);
+    int AddService(const std::string & name,
+                   const SERVICE_CONF_RES & conf,
+                   SIMPLE::CALLBACK f, void * data);
+    int DelService(const std::string & name, SIMPLE::CALLBACK f, void * data);
+
+    int GetCorporations(GET_CONTAINER::CALLBACK<GET_CORP::INFO>::TYPE f, void * data);
+    int GetCorp(const std::string & name, GET_CORP::CALLBACK f, void * data);
+    int ChgCorp(const CORP_CONF_RES & conf, SIMPLE::CALLBACK f, void * data);
+    int AddCorp(const std::string & name,
+                const CORP_CONF_RES & conf,
+                SIMPLE::CALLBACK f, void * data);
+    int DelCorp(const std::string & name, SIMPLE::CALLBACK f, void * data);
 
     const std::string & GetStrError() const;
-    int GetError();
-    int Start(const char *el, const char **attr);
-    void End(const char *el);
 
 private:
-    PARSER * currParser;
-
-    PARSER_GET_USERS parserGetUsers;
-    PARSER_GET_USER parserGetUser;
-    PARSER_AUTH_BY parserAuthBy;
-    PARSER_GET_SERVER_INFO  parserServerInfo;
-    PARSER_CHG_USER parserChgUser;
-    PARSER_CHECK_USER parserCheckUser;
-    PARSER_SEND_MESSAGE parserSendMessage;
-
-    NETTRANSACT nt;
-
-    std::string errorMsg;
-    int error;
-    XML_Parser parser;
-
-    RecvUserDataCb_t RecvUserDataCb;
-    RecvUserDataCb_t RecvGetUserDataCb;
-    RecvAuthByDataCb_t RecvAuthByCb;
-    RecvServerInfoDataCb_t RecvServerInfoDataCb;
-    RecvChgUserCb_t RecvChgUserCb;
-    RecvCheckUserCb_t RecvCheckUserCb;
-    RecvSendMessageCb_t RecvSendMessageCb;
-
-    void * getUserDataDataCb;
-    void * getUserAuthByDataCb;
-    void * getUsersDataDataCb;
-    void * getServerInfoDataCb;
-    void * chgUserDataCb;
-    void * checkUserDataCb;
-    void * sendMessageDataCb;
-
-    friend int AnsRecv(void * data, std::list<std::string> * list);
+    class IMPL;
+    IMPL * pImpl;
 };
-//-----------------------------------------------------------------------------
 
-#endif  /* _SERVCONF_H_ */
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/include/stg/servconf_types.h b/stglibs/srvconf.lib/include/stg/servconf_types.h
new file mode 100644 (file)
index 0000000..167b809
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_TYPES_H__
+#define __STG_STGLIBS_SRVCONF_TYPES_H__
+
+#include "stg/array.h"
+#include "stg/const.h" // DIR_NUM
+#include "stg/os_int.h" // uint32_t, etc...
+
+#include <string>
+#include <vector>
+#include <ctime>
+
+struct ADMIN_CONF;
+struct TARIFF_DATA;
+struct SERVICE_CONF;
+struct CORP_CONF;
+
+namespace STG
+{
+
+enum status
+{
+st_ok = 0,
+st_conn_fail,
+st_send_fail,
+st_recv_fail,
+st_header_err,
+st_login_err,
+st_logins_err,
+st_data_err,
+st_unknown_err,
+st_dns_err,
+st_xml_parse_error,
+st_data_error
+};
+
+namespace SIMPLE
+{
+
+typedef void (* CALLBACK)(bool result, const std::string & reason, void * data);
+
+} // namespace SIMPLE
+
+namespace GET_CONTAINER
+{
+
+template <typename INFO>
+struct CALLBACK
+{
+typedef void (* TYPE)(bool result, const std::string & reason, const std::vector<INFO> & info, void * data);
+};
+
+} // namespace GET_CONTAINER
+
+namespace AUTH_BY
+{
+
+typedef std::vector<std::string> INFO;
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace AUTH_BY
+
+namespace SERVER_INFO
+{
+
+struct INFO
+{
+    std::string version;
+    int         tariffNum;
+    int         tariffType;
+    int         usersNum;
+    std::string uname;
+    int         dirNum;
+    ARRAY<std::string, DIR_NUM> dirName;
+};
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace SERVER_INFO
+
+namespace RAW_XML
+{
+
+typedef void (* CALLBACK)(bool result, const std::string & reason, const std::string & response, void * data);
+
+} // namespace RAW_XML
+
+namespace GET_USER
+{
+
+struct STAT
+{
+    ARRAY<long long, DIR_NUM> su;
+    ARRAY<long long, DIR_NUM> sd;
+    ARRAY<long long, DIR_NUM> mu;
+    ARRAY<long long, DIR_NUM> md;
+};
+
+struct INFO
+{
+    std::string login;
+    std::string password;
+    double      cash;
+    double      credit;
+    time_t      creditExpire;
+    double      lastCashAdd;
+    double      lastCashAddTime;
+    time_t      lastTimeCash;
+    double      prepaidTraff;
+    int         disabled;
+    int         passive;
+    int         disableDetailStat;
+    int         connected;
+    int         alwaysOnline;
+    uint32_t    ip;
+    std::string ips;
+    std::string tariff;
+    std::string group;
+    std::string note;
+    std::string email;
+    std::string name;
+    std::string address;
+    std::string phone;
+    std::string corp;
+    STAT        stat;
+    time_t      pingTime;
+    time_t      lastActivityTime;
+    ARRAY<std::string, USERDATA_NUM> userData;
+    std::vector<std::string> services;
+    std::vector<std::string> authBy;
+};
+
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace GET_USER
+
+namespace GET_ADMIN
+{
+
+typedef ADMIN_CONF INFO;
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace GET_ADMIN
+
+namespace GET_TARIFF
+{
+
+typedef TARIFF_DATA INFO;
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace GET_TARIFF
+
+namespace GET_SERVICE
+{
+
+typedef SERVICE_CONF INFO;
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace GET_SERVICE
+
+namespace GET_CORP
+{
+
+typedef CORP_CONF INFO;
+typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+
+} // namespace GET_CORP
+
+} // namespace STG
+
+#endif
index 61dc5c69a16cca574c04e0de59009564632dd59d..6515158727ae6ce4f141ddc44ebb0d5d4ea31e36 100644 (file)
  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
  */
 
- /*
- $Revision: 1.6 $
- $Date: 2009/02/06 10:25:54 $
- $Author: faust $
- */
+#include "netunit.h"
+
+#include "stg/servconf_types.h"
+#include "stg/common.h"
+#include "stg/blowfish.h"
+#include "stg/bfstream.h"
+
+#include <algorithm> // std::min
+
+#include <cerrno>
+#include <cstring>
+#include <cassert>
 
-//---------------------------------------------------------------------------
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 
-#include <cstdio>
-#include <cstring>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
 
-#include "stg/netunit.h"
-#include "stg/common.h"
+const char STG_HEADER[] = "SG04";
+const char OK_HEADER[]  = "OKHD";
+const char ERR_HEADER[] = "ERHD";
+const char OK_LOGIN[]   = "OKLG";
+const char ERR_LOGIN[]  = "ERLG";
+const char OK_LOGINS[]  = "OKLS";
+const char ERR_LOGINS[] = "ERLS";
+
+using namespace STG;
+
+namespace
+{
+
+struct ReadState
+{
+    bool final;
+    NETTRANSACT::CALLBACK callback;
+    void * callbackData;
+    NETTRANSACT * nt;
+};
+
+}
 
 //---------------------------------------------------------------------------
 
-#define SEND_DATA_ERROR             "Send data error!"
-#define RECV_DATA_ANSWER_ERROR      "Recv data answer error!"
-#define UNKNOWN_ERROR               "Unknown error!"
-#define CONNECT_FAILED              "Connect failed!"
-#define INCORRECT_LOGIN             "Incorrect login!"
-#define INCORRECT_HEADER            "Incorrect header!"
-#define SEND_LOGIN_ERROR            "Send login error!"
-#define RECV_LOGIN_ANSWER_ERROR     "Recv login answer error!"
-#define CREATE_SOCKET_ERROR         "Create socket failed!"
-#define WSASTARTUP_FAILED           "WSAStartup failed!"
-#define SEND_HEADER_ERROR           "Send header error!"
-#define RECV_HEADER_ANSWER_ERROR    "Recv header answer error!"
+const char SEND_DATA_ERROR[]          = "Error sending data.";
+const char RECV_DATA_ANSWER_ERROR[]   = "Error receiving data answer.";
+const char UNKNOWN_ERROR[]            = "Unknown error";
+const char CONNECT_FAILED[]           = "Failed to connect.";
+const char BIND_FAILED[]              = "Failed to bind.";
+const char INCORRECT_LOGIN[]          = "Incorrect login.";
+const char INCORRECT_HEADER[]         = "Incorrect header.";
+const char SEND_LOGIN_ERROR[]         = "Error sending login.";
+const char RECV_LOGIN_ANSWER_ERROR[]  = "Error receiving login answer.";
+const char CREATE_SOCKET_ERROR[]      = "Failed to create socket.";
+const char SEND_HEADER_ERROR[]        = "Error sending header.";
+const char RECV_HEADER_ANSWER_ERROR[] = "Error receiving header answer.";
 
 //---------------------------------------------------------------------------
-NETTRANSACT::NETTRANSACT()
-    : port(0),
-      outerSocket(-1),
-      RxCallBack(NULL),
-      dataRxCallBack(NULL)
+NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
+                         const std::string & l, const std::string & pwd)
+    : server(s),
+      port(p),
+      localPort(0),
+      login(l),
+      password(pwd),
+      sock(-1)
 {
 }
 //---------------------------------------------------------------------------
+NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
+                         const std::string & la, uint16_t lp,
+                         const std::string & l, const std::string & pwd)
+    : server(s),
+      port(p),
+      localAddress(la),
+      localPort(lp),
+      login(l),
+      password(pwd),
+      sock(-1)
+{
+}
+//---------------------------------------------------------------------------
+NETTRANSACT::~NETTRANSACT()
+{
+Disconnect();
+}
+//---------------------------------------------------------------------------
 int NETTRANSACT::Connect()
 {
-int ret;
-
-outerSocket = socket(PF_INET, SOCK_STREAM, 0);
-if (outerSocket < 0)
+sock = socket(PF_INET, SOCK_STREAM, 0);
+if (sock < 0)
     {
     errorMsg = CREATE_SOCKET_ERROR;
     return st_conn_fail;
     }
 
+if (!localAddress.empty())
+    {
+    if (localPort == 0)
+        localPort = port;
+
+    unsigned long ip = inet_addr(localAddress.c_str());
+
+    if (ip == INADDR_NONE)
+        {
+        struct hostent * phe = gethostbyname(localAddress.c_str());
+        if (phe == NULL)
+            {
+            errorMsg = "Can not reslove '" + localAddress + "'";
+            return st_dns_err;
+            }
+
+        struct hostent he;
+        memcpy(&he, phe, sizeof(he));
+        ip = *((long *)he.h_addr_list[0]);
+        }
+
+    struct sockaddr_in localAddr;
+    memset(&localAddr, 0, sizeof(localAddr));
+    localAddr.sin_family = AF_INET;
+    localAddr.sin_port = htons(localPort);
+    localAddr.sin_addr.s_addr = ip;
+
+    if (bind(sock, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0)
+        {
+        errorMsg = BIND_FAILED;
+        return st_conn_fail;
+        }
+    }
+
 struct sockaddr_in outerAddr;
 memset(&outerAddr, 0, sizeof(outerAddr));
 
-struct hostent he;
-struct hostent * phe;
-
-unsigned long ip;
-ip = inet_addr(server.c_str());
+unsigned long ip = inet_addr(server.c_str());
 
 if (ip == INADDR_NONE)
     {
-    phe = gethostbyname(server.c_str());
+    struct hostent * phe = gethostbyname(server.c_str());
     if (phe == NULL)
         {
-        errorMsg = "DNS error.\nCan not reslove " + server;
+        errorMsg = "Can not reslove '" + server + "'";
         return st_dns_err;
         }
 
+    struct hostent he;
     memcpy(&he, phe, sizeof(he));
-    ip = *((long*)he.h_addr_list[0]);
+    ip = *((long *)he.h_addr_list[0]);
     }
+
 outerAddr.sin_family = AF_INET;
 outerAddr.sin_port = htons(port);
 outerAddr.sin_addr.s_addr = ip;
 
-ret = connect(outerSocket, (struct sockaddr*)&outerAddr, sizeof(outerAddr));
-
-if (ret < 0)
+if (connect(sock, (struct sockaddr *)&outerAddr, sizeof(outerAddr)) < 0)
     {
     errorMsg = CONNECT_FAILED;
-    close(outerSocket);
     return st_conn_fail;
     }
+
 return st_ok;
 }
 //---------------------------------------------------------------------------
-int NETTRANSACT::Disconnect()
+void NETTRANSACT::Disconnect()
 {
-close(outerSocket);
-return 0;
+if (sock != -1)
+    {
+    shutdown(sock, SHUT_RDWR);
+    close(sock);
+    sock = -1;
+    }
 }
 //---------------------------------------------------------------------------
-int NETTRANSACT::Transact(const char * data)
+int NETTRANSACT::Transact(const std::string & request, CALLBACK callback, void * data)
 {
 int ret;
 if ((ret = TxHeader()) != st_ok)
-    {
-    Disconnect();
     return ret;
-    }
 
 if ((ret = RxHeaderAnswer()) != st_ok)
-    {
-    Disconnect();
     return ret;
-    }
 
 if ((ret = TxLogin()) != st_ok)
-    {
-    Disconnect();
     return ret;
-    }
 
 if ((ret = RxLoginAnswer()) != st_ok)
-    {
-    Disconnect();
     return ret;
-    }
 
 if ((ret = TxLoginS()) != st_ok)
-    {
-    Disconnect();
     return ret;
-    }
 
 if ((ret = RxLoginSAnswer()) != st_ok)
-    {
-    Disconnect();
     return ret;
-    }
 
-if ((ret = TxData(data)) != st_ok)
-    {
-    Disconnect();
+if ((ret = TxData(request)) != st_ok)
     return ret;
-    }
 
-if ((ret = RxDataAnswer()) != st_ok)
-    {
-    Disconnect();
+if ((ret = RxDataAnswer(callback, data)) != st_ok)
     return ret;
-    }
 
 return st_ok;
 }
 //---------------------------------------------------------------------------
 int NETTRANSACT::TxHeader()
 {
-int ret;
-ret = send(outerSocket, STG_HEADER, strlen(STG_HEADER), 0);
-if (ret <= 0)
+if (!WriteAll(sock, STG_HEADER, strlen(STG_HEADER)))
     {
     errorMsg = SEND_HEADER_ERROR;
     return st_send_fail;
@@ -181,45 +235,36 @@ return st_ok;
 //---------------------------------------------------------------------------
 int NETTRANSACT::RxHeaderAnswer()
 {
-char buffer[sizeof(STG_HEADER)+1];
-int ret;
+char buffer[sizeof(STG_HEADER) + 1];
 
-ret = recv(outerSocket, buffer, strlen(OK_HEADER), 0);
-if (ret <= 0)
+if (!ReadAll(sock, buffer, strlen(OK_HEADER)))
     {
     errorMsg = RECV_HEADER_ANSWER_ERROR;
     return st_recv_fail;
     }
 
 if (strncmp(OK_HEADER, buffer, strlen(OK_HEADER)) == 0)
-    {
     return st_ok;
+
+if (strncmp(ERR_HEADER, buffer, strlen(ERR_HEADER)) == 0)
+    {
+    errorMsg = INCORRECT_HEADER;
+    return st_header_err;
     }
 else
     {
-    if (strncmp(ERR_HEADER, buffer, strlen(ERR_HEADER)) == 0)
-        {
-        errorMsg = INCORRECT_HEADER;
-        return st_header_err;
-        }
-    else
-        {
-        errorMsg = UNKNOWN_ERROR;
-        return st_unknown_err;
-        }
+    errorMsg = UNKNOWN_ERROR;
+    return st_unknown_err;
     }
 }
 //---------------------------------------------------------------------------
 int NETTRANSACT::TxLogin()
 {
-char loginZ[ADM_LOGIN_LEN];
-int ret;
-
-memset(loginZ, 0, ADM_LOGIN_LEN);
+char loginZ[ADM_LOGIN_LEN + 1];
+memset(loginZ, 0, ADM_LOGIN_LEN + 1);
 strncpy(loginZ, login.c_str(), ADM_LOGIN_LEN);
-ret = send(outerSocket, loginZ, ADM_LOGIN_LEN, 0);
 
-if (ret <= 0)
+if (!WriteAll(sock, loginZ, ADM_LOGIN_LEN))
     {
     errorMsg = SEND_LOGIN_ERROR;
     return st_send_fail;
@@ -230,175 +275,130 @@ return st_ok;
 //---------------------------------------------------------------------------
 int NETTRANSACT::RxLoginAnswer()
 {
-char buffer[sizeof(OK_LOGIN)+1];
-int ret;
+char buffer[sizeof(OK_LOGIN) + 1];
 
-ret = recv(outerSocket, buffer, strlen(OK_LOGIN), 0);
-if (ret <= 0)
+if (!ReadAll(sock, buffer, strlen(OK_LOGIN)))
     {
     errorMsg = RECV_LOGIN_ANSWER_ERROR;
     return st_recv_fail;
     }
 
 if (strncmp(OK_LOGIN, buffer, strlen(OK_LOGIN)) == 0)
-    {
     return st_ok;
+
+if (strncmp(ERR_LOGIN, buffer, strlen(ERR_LOGIN)) == 0)
+    {
+    errorMsg = INCORRECT_LOGIN;
+    return st_login_err;
     }
 else
     {
-    if (strncmp(ERR_LOGIN, buffer, strlen(ERR_LOGIN)) == 0)
-        {
-        errorMsg = INCORRECT_LOGIN;
-        return st_login_err;
-        }
-    else
-        {
-        errorMsg = UNKNOWN_ERROR;
-        return st_unknown_err;
-        }
+    errorMsg = UNKNOWN_ERROR;
+    return st_unknown_err;
     }
 }
 //---------------------------------------------------------------------------
 int NETTRANSACT::TxLoginS()
 {
-char loginZ[ADM_LOGIN_LEN];
+char loginZ[ADM_LOGIN_LEN + 1];
+memset(loginZ, 0, ADM_LOGIN_LEN + 1);
 
-memset(loginZ, 0, ADM_LOGIN_LEN);
 BLOWFISH_CTX ctx;
 InitContext(password.c_str(), PASSWD_LEN, &ctx);
-EncryptString(loginZ, login.c_str(), std::min<int>(login.length() + 1, ADM_LOGIN_LEN), &ctx);
-if (send(outerSocket, loginZ, ADM_LOGIN_LEN, 0) <= 0)
+EncryptString(loginZ, login.c_str(), std::min<size_t>(login.length() + 1, ADM_LOGIN_LEN), &ctx);
+if (!WriteAll(sock, loginZ, ADM_LOGIN_LEN))
     {
     errorMsg = SEND_LOGIN_ERROR;
     return st_send_fail;
     }
+
 return st_ok;
 }
 //---------------------------------------------------------------------------
 int NETTRANSACT::RxLoginSAnswer()
 {
-char buffer[sizeof(OK_LOGINS)+1];
-int ret;
+char buffer[sizeof(OK_LOGINS) + 1];
 
-ret = recv(outerSocket, buffer, strlen(OK_LOGINS), 0);
-if (ret <= 0)
+if (!ReadAll(sock, buffer, strlen(OK_LOGINS)))
     {
     errorMsg = RECV_LOGIN_ANSWER_ERROR;
     return st_recv_fail;
     }
 
 if (strncmp(OK_LOGINS, buffer, strlen(OK_LOGINS)) == 0)
-    {
     return st_ok;
+
+if (strncmp(ERR_LOGINS, buffer, strlen(ERR_LOGINS)) == 0)
+    {
+    errorMsg = INCORRECT_LOGIN;
+    return st_logins_err;
     }
 else
     {
-    if (strncmp(ERR_LOGINS, buffer, strlen(ERR_LOGINS)) == 0)
-        {
-        errorMsg = INCORRECT_LOGIN;
-        return st_logins_err;
-        }
-    else
-        {
-        errorMsg = UNKNOWN_ERROR;
-        return st_unknown_err;
-        }
+    errorMsg = UNKNOWN_ERROR;
+    return st_unknown_err;
     }
 }
 //---------------------------------------------------------------------------
-int NETTRANSACT::TxData(const char * text)
+int NETTRANSACT::TxData(const std::string & text)
 {
-BLOWFISH_CTX ctx;
-InitContext(password.c_str(), PASSWD_LEN, &ctx);
-size_t length = strlen(text);
-char buffer[length + 9];
-memset(buffer, 0, sizeof(buffer));
-EncryptString(buffer, text, length + 1, &ctx);
-if (send(outerSocket, buffer, sizeof(buffer), 0) <= 0)
+STG::ENCRYPT_STREAM stream(password, TxCrypto, this);
+stream.Put(text.c_str(), text.length() + 1, true);
+if (!stream.IsOk())
     {
     errorMsg = SEND_DATA_ERROR;
     return st_send_fail;
     }
+
 return st_ok;
 }
 //---------------------------------------------------------------------------
-int NETTRANSACT::RxDataAnswer()
+int NETTRANSACT::RxDataAnswer(CALLBACK callback, void * data)
 {
-int n = 0;
-int ret;
-char bufferS[ENC_MSG_LEN];
-char buffer[ENC_MSG_LEN + 1];
-
-BLOWFISH_CTX ctx;
-InitContext(password.c_str(), PASSWD_LEN, &ctx);
-
-while (1)
+ReadState state = {false, callback, data, this};
+STG::DECRYPT_STREAM stream(password, RxCrypto, &state);
+while (!state.final)
     {
-    ret = recv(outerSocket, &bufferS[n++], 1, 0);
-    if (ret <= 0)
+    char buffer[1024];
+    ssize_t res = read(sock, buffer, sizeof(buffer));
+    if (res < 0)
         {
-        close(outerSocket);
         errorMsg = RECV_DATA_ANSWER_ERROR;
         return st_recv_fail;
         }
-
-    if (n == ENC_MSG_LEN)
-        {
-        n = 0;
-        DecryptBlock(buffer, bufferS, &ctx);
-        buffer[ENC_MSG_LEN] = 0;
-
-        answerList.push_back(buffer);
-
-        for (int j = 0; j < ENC_MSG_LEN; j++)
-            {
-            if (buffer[j] == 0)
-                {
-                if (RxCallBack)
-                    if (st_ok != RxCallBack(dataRxCallBack, &answerList))
-                        {
-                        return st_xml_parse_error;
-                        }
-                return st_ok;
-                }
-            }
-        }
+    stream.Put(buffer, res, res == 0);
+    if (!stream.IsOk())
+        return st_xml_parse_error;
     }
+
+return st_ok;
 }
 //---------------------------------------------------------------------------
-void NETTRANSACT::SetLogin(const char * l)
-{
-login = l;
-}
-//---------------------------------------------------------------------------
-void NETTRANSACT::SetPassword(const char * p)
-{
-password = p;
-}
-//---------------------------------------------------------------------------
-void NETTRANSACT::SetServer(const char * serverName)
-{
-server = serverName;
-}
-//---------------------------------------------------------------------------
-void NETTRANSACT::SetServerPort(short unsigned p)
-{
-port = p;
-}
-//---------------------------------------------------------------------------
-void NETTRANSACT::SetRxCallback(void * data, RxCallback_t cb)
-{
-RxCallBack = cb;
-dataRxCallBack = data;
-}
-//---------------------------------------------------------------------------
-const std::string & NETTRANSACT::GetError() const
+bool NETTRANSACT::TxCrypto(const void * block, size_t size, void * data)
 {
-return errorMsg;
+assert(data != NULL);
+NETTRANSACT & nt = *static_cast<NETTRANSACT *>(data);
+if (!WriteAll(nt.sock, block, size))
+    return false;
+return true;
 }
 //---------------------------------------------------------------------------
-void NETTRANSACT::Reset()
+bool NETTRANSACT::RxCrypto(const void * block, size_t size, void * data)
 {
-answerList.clear();
+assert(data != NULL);
+ReadState & state = *static_cast<ReadState *>(data);
+
+const char * buffer = static_cast<const char *>(block);
+for (size_t pos = 0; pos < size; ++pos)
+    if (buffer[pos] == 0)
+        {
+        state.final = true;
+        size = pos; // Adjust string size
+        }
+
+if (state.callback)
+    if (!state.callback(std::string(buffer, size), state.final, state.callbackData))
+        return false;
+
+return true;
 }
-//---------------------------------------------------------------------------
diff --git a/stglibs/srvconf.lib/netunit.h b/stglibs/srvconf.lib/netunit.h
new file mode 100644 (file)
index 0000000..ca13bbc
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ */
+
+#ifndef NetUnitH
+#define NetUnitH
+
+#include "stg/os_int.h"
+
+#include <string>
+
+namespace STG
+{
+
+class NETTRANSACT
+{
+public:
+    typedef bool (* CALLBACK)(const std::string &, bool, void *);
+
+    NETTRANSACT(const std::string & server, uint16_t port,
+                const std::string & login, const std::string & password);
+    NETTRANSACT(const std::string & server, uint16_t port,
+                const std::string & localAddress, uint16_t localPort,
+                const std::string & login, const std::string & password);
+    ~NETTRANSACT();
+    int Transact(const std::string & request, CALLBACK f, void * data);
+    const std::string & GetError() const { return errorMsg; }
+
+    int  Connect();
+    void Disconnect();
+private:
+    int  TxHeader();
+    int  RxHeaderAnswer();
+
+    int  TxLogin();
+    int  RxLoginAnswer();
+
+    int  TxLoginS();
+    int  RxLoginSAnswer();
+
+    int  TxData(const std::string & text);
+    int  RxDataAnswer(CALLBACK f, void * data);
+
+    std::string server;
+    uint16_t  port;
+    std::string localAddress;
+    uint16_t localPort;
+    std::string login;
+    std::string password;
+    int sock;
+    std::string errorMsg;
+
+    static bool TxCrypto(const void * block, size_t size, void * data);
+    static bool RxCrypto(const void * block, size_t size, void * data);
+};
+
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parser.cpp b/stglibs/srvconf.lib/parser.cpp
deleted file mode 100644 (file)
index 40557e3..0000000
+++ /dev/null
@@ -1,996 +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 <stg34@stargazer.dp.ua>
- */
-
- /*
- $Revision: 1.18 $
- $Date: 2010/08/04 00:40:00 $
- $Author: faust $
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string>
-
-#include "stg/common.h"
-#include "stg/const.h"
-#include "stg/servconf.h"
-
-using namespace std;
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_GET_USERS::PARSER_GET_USERS()
-    : RecvUserDataCb(NULL),
-      userDataCb(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int PARSER_GET_USERS::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    ParseUsers(el, attr);
-    }
-
-if (depth == 2)
-    {
-    ParseUser(el, attr);
-    }
-
-if (depth == 3)
-    {
-    ParseUserParams(el, attr);
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USERS::ParseEnd(const char *)
-{
-depth--;
-if (depth == 1)
-    {
-    if (RecvUserDataCb)
-        {
-        RecvUserDataCb(&user, userDataCb);
-        }
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USERS::ParseUsers(const char * el, const char ** attr)
-{
-if (strcasecmp(el, "users") == 0)
-    {
-    if (*attr != NULL)
-        return;
-    return;
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USERS::ParseUser(const char * el, const char ** attr)
-{
-if (el && attr[0])
-    {
-    if (strcasecmp(el, "user") != 0)
-        {
-        return;
-        }
-
-    if (strcasecmp(attr[0], "login") != 0)
-        {
-        return;
-        }
-    user.login = attr[1];
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USERS::ParseUserParams(const char * el, const char ** attr)
-{
-if (strcasecmp(el, "cash") == 0)
-    {
-    if (strtodouble2(attr[1], user.cash) < 0)
-        {
-        return;
-        }
-    }
-
-/*if (strcasecmp(el, "LastCash") == 0)
-    {
-    if (strtodouble2(attr[1], user.lastCash) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }*/
-
-/*if (strcasecmp(el, "LastActivityTime") == 0)
-    {
-    if (strtol(attr[1], user.lastActivityTime) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }*/
-
-
-/*if (strcasecmp(el, "LastTimeCash") == 0)
-    {
-    if (strtol(attr[1], user.lastTimeCash) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }*/
-
-/*if (strcasecmp(el, "CashExpire") == 0)
-    {
-    if (strtol(attr[1], user.cashExpire) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }*/
-
-if (strcasecmp(el, "credit") == 0)
-    {
-    if (strtodouble2(attr[1], user.credit) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "creditExpire") == 0)
-    {
-    if (str2x(attr[1], user.creditExpire) < 0)
-        {
-        return;
-        }
-    }
-
-/*if (strcasecmp(el, "freemb") == 0)
-    {
-    if (strtodouble2(attr[1], user.freeMb) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }*/
-
-if (strcasecmp(el, "down") == 0)
-    {
-    if (str2x(attr[1], user.down) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "passive") == 0)
-    {
-    if (str2x(attr[1], user.passive) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "disableDetailStat") == 0)
-    {
-    if (str2x(attr[1], user.disableDetailStat) < 0)
-        {
-        return;
-        }
-    }
-
-
-if (strcasecmp(el, "status") == 0)
-    {
-    if (str2x(attr[1], user.connected) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "aonline") == 0)
-    {
-    if (str2x(attr[1], user.alwaysOnline) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "currip") == 0)
-    {
-    user.ip = inet_addr(attr[1]);
-    }
-
-if (strcasecmp(el, "ip") == 0)
-    {
-    user.ips = attr[1];
-    }
-
-
-if (strcasecmp(el, "tariff") == 0)
-    {
-    //KOIToWin(user.tariff, *(attr+1), TARIFF_LEN);
-    user.tariff = attr[1];
-    return;
-    }
-
-if (strcasecmp(el, "password") == 0)
-    {
-    user.password = *(attr+1);
-    return;
-    }
-
-if (strcasecmp(el, "iface") == 0)
-    {
-    user.iface = attr[1];
-    return;
-    }
-
-/*if (strcasecmp(el, "name") == 0)
-    {
-    / *char nameEnc[REALNM_LEN * 2 + 1];
-    char name[REALNM_LEN];
-    strncpy(nameEnc, attr[1], REALNM_LEN * 2 + 1);
-    Decode21(name, nameEnc);
-    KOIToWin(user.realName, name, REALNM_LEN);* /
-    Decode21str(user.realName, attr[1]);
-    return;
-    }*/
-
-if (strcasecmp(el, "address") == 0)
-    {
-    /*char addressEnc[ADDR_LEN * 2 + 1];
-    char address[ADDR_LEN];
-    strncpy(addressEnc, attr[1], ADDR_LEN * 2 + 1);
-    Decode21(address, addressEnc);
-    KOIToWin(user.address, address, ADDR_LEN);*/
-    Decode21str(user.address, attr[1]);
-    return;
-    }
-
-if (strcasecmp(el, "phone") == 0)
-    {
-    /*char phoneEnc[PHONE_LEN * 2 + 1];
-    char phone[PHONE_LEN];
-    strncpy(phoneEnc, attr[1], PHONE_LEN * 2 + 1);
-    Decode21(phone, phoneEnc);
-    KOIToWin(user.phone, phone, PHONE_LEN);*/
-    Decode21str(user.phone, attr[1]);
-    return;
-    }
-
-if (strcasecmp(el, "note") == 0)
-    {
-    /*char noteEnc[NOTE_LEN * 2 + 1];
-    char note[NOTE_LEN];
-    strncpy(noteEnc, attr[1], NOTE_LEN * 2 + 1);*/
-    //KOIToWin(user.note, note, NOTE_LEN);
-    //user.note = note;
-    Decode21str(user.note, attr[1]);
-    return;
-    }
-
-if (strcasecmp(el, "email") == 0)
-    {
-    /*char emailEnc[EMAIL_LEN * 2 + 1];
-    char email[EMAIL_LEN];
-    strncpy(emailEnc, attr[1], EMAIL_LEN * 2 + 1);
-    Decode21(email, emailEnc);
-    //KOIToWin(user.email, email, EMAIL_LEN);
-    user.email = email;*/
-    Decode21str(user.email, attr[1]);
-    return;
-    }
-
-if (strcasecmp(el, "group") == 0)
-    {
-    /*char groupEnc[GROUP_LEN * 2 + 1];
-    char group[GROUP_LEN];
-    strncpy(groupEnc, attr[1], GROUP_LEN * 2 + 1);
-    Decode21(group, groupEnc);
-    //KOIToWin(user.group, group, GROUP_LEN);
-    user.group = group;*/
-    Decode21str(user.group, attr[1]);
-    return;
-    }
-
-if (strcasecmp(el, "traff") == 0)
-    {
-    ParseUserLoadStat(el, attr);
-    return;
-    }
-
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USERS::ParseUserLoadStat(const char *, const char ** attr)
-{
-int i = 0;
-char dir[6];
-while (attr[i])
-    {
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "MU%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.mu[j]);
-            break;
-            }
-        }
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "MD%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.md[j]);
-            break;
-            }
-        }
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "SU%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.su[j]);
-            break;
-            }
-        }
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "SD%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.sd[j]);
-            break;
-            }
-        }
-    i+=2;
-    }
-return;
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USERS::SetUserDataRecvCb(RecvUserDataCb_t f, void * data)
-{
-RecvUserDataCb = f;
-userDataCb = data;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_GET_USER::PARSER_GET_USER()
-    : RecvUserDataCb(NULL),
-      userDataCb(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int PARSER_GET_USER::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    ParseUser(el, attr);
-    }
-
-if (depth == 2)
-    {
-    ParseUserParams(el, attr);
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USER::ParseEnd(const char *)
-{
-depth--;
-if (depth == 0)
-    {
-    if (RecvUserDataCb)
-        {
-        RecvUserDataCb(&user, userDataCb);
-        }
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USER::ParseUser(const char * el, const char ** attr)
-{
-if (strcasecmp(el, "user") == 0)
-    {
-    if (strcasecmp(attr[1], "error") == 0)
-        user.login = "";
-    return;
-    }
-}
-//-----------------------------------------------------------------------------
-struct ParsedStringParams
-{
-string    * param;
-string      paramName;
-};
-//-----------------------------------------------------------------------------
-struct ParsedDoubleParams
-{
-double    * param;
-string      paramName;
-};
-//-----------------------------------------------------------------------------
-void PARSER_GET_USER::ParseUserParams(const char * el, const char ** attr)
-{
-//printf("PARSER_GET_USER::ParseUserParams el=%s attr[1]=%s\n", el, attr[1]);
-
-if (strcasecmp(el, "login") == 0)
-    {
-    user.login = attr[1];
-    }
-
-
-/*if (strcasecmp(el, "LastActivityTime") == 0)
-    {
-    if (strtol(attr[1], user.lastActivityTime) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }
-
-
-if (strcasecmp(el, "LastTimeCash") == 0)
-    {
-    if (strtol(attr[1], user.lastTimeCash) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }
-
-if (strcasecmp(el, "CashExpire") == 0)
-    {
-    if (strtol(attr[1], user.cashExpire) < 0)
-        {
-        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
-        return 0;
-        }
-    }
-*/
-
-if (strcasecmp(el, "down") == 0)
-    {
-    if (str2x(attr[1], user.down) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "passive") == 0)
-    {
-    if (str2x(attr[1], user.passive) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "disableDetailStat") == 0)
-    {
-    if (str2x(attr[1], user.disableDetailStat) < 0)
-        {
-        return;
-        }
-    }
-
-
-if (strcasecmp(el, "status") == 0)
-    {
-    if (str2x(attr[1], user.connected) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "aonline") == 0)
-    {
-    if (str2x(attr[1], user.alwaysOnline) < 0)
-        {
-        return;
-        }
-    }
-
-if (strcasecmp(el, "currip") == 0)
-    {
-    user.ip = inet_addr(attr[1]);
-    }
-
-if (strcasecmp(el, "creditExpire") == 0)
-    {
-    if (str2x(attr[1], user.creditExpire) < 0)
-        {
-        return;
-        }
-    }
-
-for (int i = 0; i < USERDATA_NUM; i++)
-    {
-    string num;
-    x2str(i, num);
-    string udName = "UserData" + num;
-    if (strcasecmp(el, udName.c_str()) == 0)
-        {
-        Decode21str(user.userData[i], attr[1]);
-        return;
-        }
-    }
-
-ParsedStringParams psp[] =
-{
-    {&user.ips,         "ip"},
-    {&user.tariff,      "tariff"},
-    {&user.password,    "password"},
-    {&user.iface,       "iface"},
-};
-
-for (unsigned i = 0; i < sizeof(psp)/sizeof(ParsedStringParams); i++)
-    {
-    if (strcasecmp(el, psp[i].paramName.c_str()) == 0)
-        {
-        *psp[i].param = attr[1];
-        return;
-        }
-    }
-
-ParsedStringParams pspEnc[] =
-{
-    {&user.note,    "note"},
-    {&user.email,   "email"},
-    {&user.group,   "group"},
-    {&user.name,    "name"},
-    {&user.address, "address"},
-    {&user.phone,   "phone"}
-};
-
-for (unsigned i = 0; i < sizeof(pspEnc)/sizeof(ParsedStringParams); i++)
-    {
-    if (strcasecmp(el, pspEnc[i].paramName.c_str()) == 0)
-        {
-        Decode21str(*pspEnc[i].param, attr[1]);
-        return;
-        }
-    }
-
-ParsedDoubleParams pdp[] =
-{
-    {&user.cash,            "cash"},
-    {&user.credit,          "credit"},
-    {&user.lastCash,        "lastCash"},
-    {&user.prepaidTraff,    "freemb"},
-};
-
-for (unsigned i = 0; i < sizeof(pdp)/sizeof(ParsedDoubleParams); i++)
-    {
-    if (strcasecmp(el, pdp[i].paramName.c_str()) == 0)
-        {
-        strtodouble2(attr[1], *pdp[i].param);
-        return;
-        }
-    }
-
-if (strcasecmp(el, "traff") == 0)
-    {
-    ParseUserLoadStat(el, attr);
-    return;
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USER::ParseUserLoadStat(const char *, const char ** attr)
-{
-int i = 0;
-char dir[6];
-while (attr[i])
-    {
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "MU%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.mu[j]);
-            break;
-            }
-        }
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "MD%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.md[j]);
-            break;
-            }
-        }
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "SU%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.su[j]);
-            break;
-            }
-        }
-    for (int j = 0; j < DIR_NUM; j++)
-        {
-        sprintf(dir, "SD%d", j);
-        if (strcasecmp(dir, attr[i]) == 0)
-            {
-            str2x(attr[i+1], user.stat.sd[j]);
-            break;
-            }
-        }
-    i+=2;
-    }
-return;
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_USER::SetUserDataRecvCb(RecvUserDataCb_t f, void * data)
-{
-RecvUserDataCb = f;
-userDataCb = data;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_GET_SERVER_INFO::PARSER_GET_SERVER_INFO()
-    : RecvServerInfoDataCb(NULL),
-      serverInfoDataCb(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int PARSER_GET_SERVER_INFO::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    if (strcasecmp(el, "ServerInfo") != 0)
-        {
-        //printf("%s\n", el);
-        }
-    }
-else
-    {
-    if (depth == 2)
-        {
-        if (strcasecmp(el, "uname") == 0)
-            {
-            ParseUname(attr);
-            return 0;
-            }
-        if (strcasecmp(el, "version") == 0)
-            {
-            ParseServerVersion(attr);
-            return 0;
-            }
-        if (strcasecmp(el, "tariff") == 0)
-            {
-            ParseTariffType(attr);
-            return 0;
-            }
-        if (strcasecmp(el, "dir_num") == 0)
-            {
-            ParseDirNum(attr);
-            return 0;
-            }
-        if (strcasecmp(el, "users_num") == 0)
-            {
-            ParseUsersNum(attr);
-            return 0;
-            }
-        if (strcasecmp(el, "tariff_num") == 0)
-            {
-            ParseTariffsNum(attr);
-            return 0;
-            }
-
-        for (int j = 0; j < DIR_NUM; j++)
-            {
-            char str[16];
-            sprintf(str, "dir_name_%d", j);
-            if (strcasecmp(el, str) == 0)
-                {
-                ParseDirName(attr, j);
-                }
-            }
-
-        }
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseEnd(const char *)
-{
-depth--;
-if (depth == 0)
-    {
-    RecvServerInfoDataCb(&serverInfo, serverInfoDataCb);
-    }
-}
-//-----------------------------------------------------------------------------
-/*void PARSER_GET_SERVER_INFO::ParseServerInfo(const char * el, const char ** attr)
-    {
-    }*/
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::SetServerInfoRecvCb(RecvServerInfoDataCb_t f, void * data)
-{
-RecvServerInfoDataCb = f;
-serverInfoDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseUname(const char ** attr)
-{
-if (strcmp(*attr, "value") == 0)
-    serverInfo.uname = attr[1];
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseServerVersion(const char ** attr)
-{
-if (strcmp(*attr, "value") == 0)
-    serverInfo.version = attr[1];
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseUsersNum(const char ** attr)
-{
-if (strcmp(*attr, "value") == 0)
-    {
-    if (str2x(attr[1], serverInfo.usersNum) < 0)
-        {
-        serverInfo.usersNum = -1;
-        return;
-        }
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseTariffsNum(const char ** attr)
-{
-if (strcmp(*attr, "value") == 0)
-    {
-    if (str2x(attr[1], serverInfo.tariffNum) < 0)
-        {
-        serverInfo.tariffNum = -1;
-        return;
-        }
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseTariffType(const char ** attr)
-{
-if (strcmp(*attr, "value") == 0)
-    {
-    if (str2x(attr[1], serverInfo.tariffType) < 0)
-        {
-        serverInfo.tariffType = -1;
-        return;
-        }
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseDirNum(const char **attr)
-{
-if (strcasecmp(*attr, "value") == 0)
-    {
-    if (str2x(attr[1], serverInfo.dirNum) < 0)
-        {
-        serverInfo.dirNum = -1;
-        return;
-        }
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_GET_SERVER_INFO::ParseDirName(const char **attr, int d)
-{
-if (strcmp(attr[0], "value") == 0)
-    {
-    char str[2*DIRNAME_LEN + 1];
-    Decode21(str, attr[1]);
-    serverInfo.dirName[d] = str;
-    }
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_AUTH_BY::PARSER_AUTH_BY()
-    : RecvAuthByDataCb(NULL),
-      authByDataCb(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int PARSER_AUTH_BY::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    if (strcasecmp(el, "AuthorizedBy") != 0)
-        {
-        list.erase(list.begin(), list.end());
-        //printf("%s\n", el);
-        }
-    }
-else
-    {
-    if (depth == 2)
-        {
-        if (strcasecmp(el, "Auth") == 0)
-            {
-            if (attr && attr[0] && attr[1])
-                list.push_back(attr[1]);
-            return 0;
-            }
-        }
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_AUTH_BY::ParseEnd(const char *)
-{
-depth--;
-if (depth == 0)
-    {
-    RecvAuthByDataCb(list, authByDataCb);
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_AUTH_BY::SetRecvCb(RecvAuthByDataCb_t f, void * data)
-{
-RecvAuthByDataCb = f;
-authByDataCb = data;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_CHG_USER::PARSER_CHG_USER()
-    : RecvChgUserCb(NULL),
-      chgUserCbData(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int PARSER_CHG_USER::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    if (strcasecmp(el, "SetUser") == 0)
-        {
-        ParseAnswer(el, attr);
-        }
-    else if (strcasecmp(el, "DelUser") == 0)
-        {
-        ParseAnswer(el, attr);
-        }
-    else if (strcasecmp(el, "AddUser") == 0)
-        {
-        ParseAnswer(el, attr);
-        }
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_CHG_USER::ParseEnd(const char *)
-{
-depth--;
-}
-//-----------------------------------------------------------------------------
-void PARSER_CHG_USER::ParseAnswer(const char *, const char **attr)
-{
-if (RecvChgUserCb)
-    {
-    RecvChgUserCb(attr[1], chgUserCbData);
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_CHG_USER::SetChgUserRecvCb(RecvChgUserCb_t f, void * data)
-{
-RecvChgUserCb = f;
-chgUserCbData = data;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_CHECK_USER::PARSER_CHECK_USER()
-    : RecvCheckUserCb(NULL),
-      checkUserCbData(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int PARSER_CHECK_USER::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    if (strcasecmp(el, "CheckUser") == 0)
-        {
-        //printf("el=%s attr[0]=%s attr[1]=%s\n", el, attr[0], attr[1]);
-        ParseAnswer(el, attr);
-        }
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_CHECK_USER::ParseEnd(const char *)
-{
-depth--;
-}
-//-----------------------------------------------------------------------------
-void PARSER_CHECK_USER::ParseAnswer(const char *, const char **attr)
-{
-if (RecvCheckUserCb)
-    {
-    RecvCheckUserCb(attr[1], checkUserCbData);
-    }
-}
-//-----------------------------------------------------------------------------
-void PARSER_CHECK_USER::SetCheckUserRecvCb(RecvCheckUserCb_t f, void * data)
-{
-RecvCheckUserCb = f;
-checkUserCbData = data;
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-PARSER_SEND_MESSAGE::PARSER_SEND_MESSAGE()
-    : RecvSendMessageCb(NULL),
-      sendMessageCbData(NULL),
-      depth(0)
-{
-}
-//-----------------------------------------------------------------------------
-int  PARSER_SEND_MESSAGE::ParseStart(const char *el, const char **attr)
-{
-depth++;
-if (depth == 1)
-    {
-    if (strcasecmp(el, "SendMessageResult") == 0)
-        {
-        ParseAnswer(el, attr);
-        }
-    }
-return 0;
-}
-//-----------------------------------------------------------------------------
-void PARSER_SEND_MESSAGE::ParseEnd(const char *)
-{
-depth--;
-}
-//-----------------------------------------------------------------------------
-void PARSER_SEND_MESSAGE::ParseAnswer(const char *, const char **attr)
-{
-if (RecvSendMessageCb)
-    RecvSendMessageCb(attr[1], sendMessageCbData);
-}
-//-----------------------------------------------------------------------------
-void PARSER_SEND_MESSAGE::SetSendMessageRecvCb(RecvSendMessageCb_t f, void * data)
-{
-RecvSendMessageCb = f;
-sendMessageCbData = data;
-}
-//-----------------------------------------------------------------------------
diff --git a/stglibs/srvconf.lib/parsers/auth_by.cpp b/stglibs/srvconf.lib/parsers/auth_by.cpp
new file mode 100644 (file)
index 0000000..143eee2
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "auth_by.h"
+
+#include <strings.h> // strcasecmp
+
+using namespace STG;
+
+AUTH_BY::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+}
+//-----------------------------------------------------------------------------
+int AUTH_BY::PARSER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "AuthorizedBy") == 0)
+        if (attr && attr[0] && attr[1])
+            {
+            if (strcasecmp(attr[1], "error") == 0)
+                {
+                if (attr[2] && attr[3])
+                    error = attr[3];
+                else
+                    error = "User not found.";
+                }
+            else
+                parsingAnswer = true;
+            }
+    }
+else
+    {
+    if (depth == 2)
+        {
+        if (parsingAnswer && strcasecmp(el, "Auth") == 0)
+            {
+            if (attr && attr[0] && attr[1] && strcasecmp(attr[0], "name") == 0)
+                info.push_back(attr[1]);
+            return 0;
+            }
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void AUTH_BY::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    info.clear();
+    error.clear();
+    }
+}
diff --git a/stglibs/srvconf.lib/parsers/auth_by.h b/stglibs/srvconf.lib/parsers/auth_by.h
new file mode 100644 (file)
index 0000000..5b2dfe5
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_AUTH_BY_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_AUTH_BY_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace AUTH_BY
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    int depth;
+    bool parsingAnswer;
+    INFO info;
+    std::string error;
+};
+
+} // namespace AUTH_BY
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/base.h b/stglibs/srvconf.lib/parsers/base.h
new file mode 100644 (file)
index 0000000..4f84d87
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_H__
+
+#include <string>
+
+namespace STG
+{
+
+class PARSER
+{
+public:
+    virtual ~PARSER() {}
+    virtual int ParseStart(const char * el, const char ** attr) = 0;
+    virtual void ParseEnd(const char * el) = 0;
+    virtual void Failure(const std::string & reason) = 0;
+};
+
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/chg_admin.cpp b/stglibs/srvconf.lib/parsers/chg_admin.cpp
new file mode 100644 (file)
index 0000000..14679df
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "chg_admin.h"
+
+#include "stg/admin_conf.h"
+#include "stg/common.h"
+
+#include <strings.h>
+
+using namespace STG;
+
+std::string CHG_ADMIN::Serialize(const ADMIN_CONF_RES & conf, const std::string & /*encoding*/)
+{
+std::string params;
+if (!conf.login.empty())
+    params += " login=\"" + conf.login.data() + "\"";
+if (!conf.password.empty())
+    params += " password=\"" + conf.password.data() + "\"";
+if (!conf.priv.empty())
+    params += " priv=\"" + unsigned2str(conf.priv.data().ToInt()) + "\"";
+return params;
+}
diff --git a/stglibs/srvconf.lib/parsers/chg_admin.h b/stglibs/srvconf.lib/parsers/chg_admin.h
new file mode 100644 (file)
index 0000000..7041aa8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_CHG_ADMIN_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_CHG_ADMIN_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+struct ADMIN_CONF_RES;
+
+namespace STG
+{
+namespace CHG_ADMIN
+{
+
+std::string Serialize(const ADMIN_CONF_RES & conf, const std::string & encoding);
+
+} // namespace CHG_ADMIN
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/chg_corp.cpp b/stglibs/srvconf.lib/parsers/chg_corp.cpp
new file mode 100644 (file)
index 0000000..852fe8e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "chg_corp.h"
+
+#include "resetable_utils.h"
+
+#include "stg/corp_conf.h"
+#include "stg/common.h"
+
+#include <sstream>
+
+using namespace STG;
+
+std::string CHG_CORP::Serialize(const CORP_CONF_RES & conf, const std::string & /*encoding*/)
+{
+std::ostringstream stream;
+
+appendResetableTag(stream, "name", conf.name);
+appendResetableTag(stream, "cash", conf.cash);
+
+return stream.str();
+}
diff --git a/stglibs/srvconf.lib/parsers/chg_corp.h b/stglibs/srvconf.lib/parsers/chg_corp.h
new file mode 100644 (file)
index 0000000..b30482f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_CHG_CORP_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_CHG_CORP_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+struct CORP_CONF_RES;
+
+namespace STG
+{
+namespace CHG_CORP
+{
+
+std::string Serialize(const CORP_CONF_RES & conf, const std::string & encoding);
+
+} // namespace CHG_CORP
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/chg_service.cpp b/stglibs/srvconf.lib/parsers/chg_service.cpp
new file mode 100644 (file)
index 0000000..6bea756
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "chg_service.h"
+
+#include "resetable_utils.h"
+
+#include "stg/service_conf.h"
+#include "stg/common.h"
+
+#include <sstream>
+
+using namespace STG;
+
+std::string CHG_SERVICE::Serialize(const SERVICE_CONF_RES & conf, const std::string & /*encoding*/)
+{
+std::ostringstream stream;
+
+appendResetableAttr(stream, "name", conf.name);
+appendResetableAttr(stream, "comment", MaybeEncode(conf.comment));
+appendResetableAttr(stream, "cost", conf.cost);
+appendResetableAttr(stream, "payDay", conf.payDay);
+
+return stream.str();
+}
diff --git a/stglibs/srvconf.lib/parsers/chg_service.h b/stglibs/srvconf.lib/parsers/chg_service.h
new file mode 100644 (file)
index 0000000..09464a6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_CHG_SERVICE_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_CHG_SERVICE_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+struct SERVICE_CONF_RES;
+
+namespace STG
+{
+namespace CHG_SERVICE
+{
+
+std::string Serialize(const SERVICE_CONF_RES & conf, const std::string & encoding);
+
+} // namespace CHG_SERVICE
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/chg_tariff.cpp b/stglibs/srvconf.lib/parsers/chg_tariff.cpp
new file mode 100644 (file)
index 0000000..16c4b19
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "chg_tariff.h"
+
+#include "resetable_utils.h"
+
+#include "stg/tariff_conf.h"
+#include "stg/common.h"
+
+#include <sstream>
+
+#include <strings.h>
+
+using namespace STG;
+
+namespace
+{
+
+template <typename A, typename T>
+void appendSlashedResetable(std::ostream & stream, const std::string & name, const A & array, T A::value_type:: * field)
+{
+std::string res;
+for (typename A::size_type i = 0; i < array.size(); ++i)
+    {
+    if ((array[i].*field).empty()) // All values must be set
+        return;
+    if (!res.empty())
+        res += "/";
+    res += x2str((array[i].*field).data());
+    }
+stream << "<" << name << " value=\"" << res << "\"/>";
+}
+
+} // namespace anonymous
+
+std::string CHG_TARIFF::Serialize(const TARIFF_DATA_RES & data, const std::string & /*encoding*/)
+{
+std::ostringstream stream;
+
+appendResetableTag(stream, "fee", data.tariffConf.fee);
+appendResetableTag(stream, "passiveCost", data.tariffConf.passiveCost);
+appendResetableTag(stream, "free", data.tariffConf.free);
+
+if (!data.tariffConf.traffType.empty())
+    stream << "<traffType value=\"" + TARIFF::TraffTypeToString(data.tariffConf.traffType.data()) + "\"/>";
+
+if (!data.tariffConf.period.empty())
+    switch (data.tariffConf.period.data())
+        {
+        case TARIFF::DAY: stream << "<period value=\"day\"/>"; break;
+        case TARIFF::MONTH: stream << "<period value=\"month\"/>"; break;
+        }
+
+if (!data.tariffConf.changePolicy.empty())
+    switch (data.tariffConf.changePolicy.data())
+        {
+        case TARIFF::ALLOW: stream << "<changePolicy value=\"allow\"/>"; break;
+        case TARIFF::TO_CHEAP: stream << "<changePolicy value=\"to_cheap\"/>"; break;
+        case TARIFF::TO_EXPENSIVE: stream << "<changePolicy value=\"to_expensive\"/>"; break;
+        case TARIFF::DENY: stream << "<changePolicy value=\"deny\"/>"; break;
+        }
+
+appendResetableTag(stream, "changePolicyTimeout", data.tariffConf.changePolicyTimeout);
+for (size_t i = 0; i < DIR_NUM; ++i)
+    if (!data.dirPrice[i].hDay.empty() &&
+        !data.dirPrice[i].mDay.empty() &&
+        !data.dirPrice[i].hNight.empty() &&
+        !data.dirPrice[i].mNight.empty())
+        stream << "<time" << i << " value=\"" << data.dirPrice[i].hDay.data() << ":"
+                                              << data.dirPrice[i].mDay.data() << "-"
+                                              << data.dirPrice[i].hNight.data() << ":"
+                                              << data.dirPrice[i].mNight.data() << "\"/>";
+
+appendSlashedResetable(stream, "priceDayA", data.dirPrice, &DIRPRICE_DATA_RES::priceDayA);
+appendSlashedResetable(stream, "priceDayB", data.dirPrice, &DIRPRICE_DATA_RES::priceDayB);
+appendSlashedResetable(stream, "priceNightA", data.dirPrice, &DIRPRICE_DATA_RES::priceNightA);
+appendSlashedResetable(stream, "priceNightB", data.dirPrice, &DIRPRICE_DATA_RES::priceNightB);
+appendSlashedResetable(stream, "singlePrice", data.dirPrice, &DIRPRICE_DATA_RES::singlePrice);
+appendSlashedResetable(stream, "noDiscount", data.dirPrice, &DIRPRICE_DATA_RES::noDiscount);
+appendSlashedResetable(stream, "threshold", data.dirPrice, &DIRPRICE_DATA_RES::threshold);
+
+return stream.str();
+}
diff --git a/stglibs/srvconf.lib/parsers/chg_tariff.h b/stglibs/srvconf.lib/parsers/chg_tariff.h
new file mode 100644 (file)
index 0000000..142b015
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_CHG_TARIFF_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_CHG_TARIFF_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+struct TARIFF_DATA_RES;
+
+namespace STG
+{
+namespace CHG_TARIFF
+{
+
+std::string Serialize(const TARIFF_DATA_RES & data, const std::string & encoding);
+
+} // namespace CHG_TARIFF
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/chg_user.cpp b/stglibs/srvconf.lib/parsers/chg_user.cpp
new file mode 100644 (file)
index 0000000..e30392f
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "chg_user.h"
+
+#include "resetable_utils.h"
+
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/common.h"
+
+#include <sstream>
+#include <iostream>
+
+#include <strings.h>
+
+using namespace STG;
+
+CHG_USER::PARSER::PARSER(SIMPLE::CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0)
+{
+}
+//-----------------------------------------------------------------------------
+int CHG_USER::PARSER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetUser") == 0)
+        ParseAnswer(el, attr);
+    else if (strcasecmp(el, "DelUser") == 0)
+        ParseAnswer(el, attr);
+    else if (strcasecmp(el, "AddUser") == 0)
+        ParseAnswer(el, attr);
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void CHG_USER::PARSER::ParseEnd(const char *)
+{
+depth--;
+}
+//-----------------------------------------------------------------------------
+void CHG_USER::PARSER::ParseAnswer(const char * /*el*/, const char ** attr)
+{
+if (!callback)
+    return;
+if (attr && attr[0] && attr[1])
+    callback(strcasecmp(attr[1], "ok") == 0, attr[2] && attr[3] ? attr[3] : "", data);
+else
+    callback(false, "Invalid response.", data);
+}
+
+std::string CHG_USER::Serialize(const USER_CONF_RES & conf, const USER_STAT_RES & stat, const std::string & encoding)
+{
+std::ostringstream stream;
+
+// Conf
+
+appendResetableTag(stream, "credit", conf.credit);
+appendResetableTag(stream, "creditExpire", conf.creditExpire);
+appendResetableTag(stream, "password", conf.password);
+appendResetableTag(stream, "down", conf.disabled); // TODO: down -> disabled
+appendResetableTag(stream, "passive", conf.passive);
+appendResetableTag(stream, "disableDetailStat", conf.disabledDetailStat); // TODO: disable -> disabled
+appendResetableTag(stream, "aonline", conf.alwaysOnline); // TODO: aonline -> alwaysOnline
+appendResetableTag(stream, "ip", conf.ips); // TODO: ip -> ips
+
+if (!conf.nextTariff.empty())
+    stream << "<tariff delayed=\"" << conf.nextTariff.data() << "\"/>";
+else if (!conf.tariffName.empty())
+    stream << "<tariff now=\"" << conf.tariffName.data() << "\"/>";
+
+appendResetableTag(stream, "note", MaybeEncode(MaybeIconv(conf.note, encoding, "koi8-ru")));
+appendResetableTag(stream, "name", MaybeEncode(MaybeIconv(conf.realName, encoding, "koi8-ru"))); // TODO: name -> realName
+appendResetableTag(stream, "address", MaybeEncode(MaybeIconv(conf.address, encoding, "koi8-ru")));
+appendResetableTag(stream, "email", MaybeEncode(MaybeIconv(conf.email, encoding, "koi8-ru")));
+appendResetableTag(stream, "phone", MaybeEncode(MaybeIconv(conf.phone, encoding, "cp1251")));
+appendResetableTag(stream, "group", MaybeEncode(MaybeIconv(conf.group, encoding, "koi8-ru")));
+appendResetableTag(stream, "corp", conf.corp);
+
+for (size_t i = 0; i < conf.userdata.size(); ++i)
+    appendResetableTag(stream, "userdata", i, MaybeEncode(MaybeIconv(conf.userdata[i], encoding, "koi8-ru")));
+
+if (!conf.services.empty())
+    {
+    stream << "<services>";
+    for (size_t i = 0; i < conf.services.data().size(); ++i)
+        stream << "<service name=\"" << conf.services.data()[i] << "\"/>";
+    stream << "</services>";
+    }
+
+// Stat
+
+if (!stat.cashAdd.empty())
+    stream << "<cash add=\"" << stat.cashAdd.data().first << "\" msg=\"" << IconvString(Encode12str(stat.cashAdd.data().second), encoding, "koi8-ru") << "\"/>";
+else if (!stat.cashSet.empty())
+    stream << "<cash set=\"" << stat.cashSet.data().first << "\" msg=\"" << IconvString(Encode12str(stat.cashSet.data().second), encoding, "koi8-ru") << "\"/>";
+
+appendResetableTag(stream, "freeMb", stat.freeMb);
+
+std::ostringstream traff;
+for (size_t i = 0; i < stat.sessionUp.size(); ++i)
+    if (!stat.sessionUp[i].empty())
+        traff << " SU" << i << "=\"" << stat.sessionUp[i].data() << "\"";
+for (size_t i = 0; i < stat.sessionDown.size(); ++i)
+    if (!stat.sessionDown[i].empty())
+        traff << " SD" << i << "=\"" << stat.sessionDown[i].data() << "\"";
+for (size_t i = 0; i < stat.monthUp.size(); ++i)
+    if (!stat.monthUp[i].empty())
+        traff << " MU" << i << "=\"" << stat.monthUp[i].data() << "\"";
+for (size_t i = 0; i < stat.monthDown.size(); ++i)
+    if (!stat.monthDown[i].empty())
+        traff << " MD" << i << "=\"" << stat.monthDown[i].data() << "\"";
+
+std::string traffData = traff.str();
+if (!traffData.empty())
+    stream << "<traff" << traffData << "/>";
+
+std::cerr << stream.str() << "\n";
+return stream.str();
+}
diff --git a/stglibs/srvconf.lib/parsers/chg_user.h b/stglibs/srvconf.lib/parsers/chg_user.h
new file mode 100644 (file)
index 0000000..9ac559e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_CHG_USER_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_CHG_USER_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+struct USER_CONF_RES;
+struct USER_STAT_RES;
+
+namespace STG
+{
+namespace CHG_USER
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    PARSER(SIMPLE::CALLBACK f, void * data, const std::string & encoding);
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, data); }
+
+private:
+    SIMPLE::CALLBACK callback;
+    void * data;
+    std::string encoding;
+    int depth;
+
+    void ParseAnswer(const char * el, const char ** attr);
+};
+
+std::string Serialize(const USER_CONF_RES & conf, const USER_STAT_RES & stat, const std::string & encoding);
+
+} // namespace CHG_USER
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/get_admin.cpp b/stglibs/srvconf.lib/parsers/get_admin.cpp
new file mode 100644 (file)
index 0000000..29e35ba
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "get_admin.h"
+
+#include "stg/common.h"
+
+#include <map>
+#include <utility>
+
+#include <strings.h>
+
+using namespace STG;
+
+namespace STG
+{
+
+template <>
+inline
+bool GetValue<PRIV>(const char ** attr, PRIV & value, const std::string & attrName)
+{
+uint32_t priv;
+if (!GetValue(attr, priv, attrName))
+    return false;
+value = priv;
+return true;
+}
+
+} // namespace STG
+
+GET_ADMIN::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+    AddParser(propertyParsers, "login", info.login);
+    AddParser(propertyParsers, "password", info.password);
+    AddParser(propertyParsers, "priv", info.priv);
+}
+//-----------------------------------------------------------------------------
+GET_ADMIN::PARSER::~PARSER()
+{
+    PROPERTY_PARSERS::iterator it(propertyParsers.begin());
+    while (it != propertyParsers.end())
+        delete (it++)->second;
+}
+//-----------------------------------------------------------------------------
+int GET_ADMIN::PARSER::ParseStart(const char * el, const char ** attr)
+{
+depth++;
+if (depth == 1)
+    ParseAdmin(el, attr);
+
+/*if (depth == 2 && parsingAnswer)
+    ParseAdminParams(el, attr);*/
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void GET_ADMIN::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0 && parsingAnswer)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    error.clear();
+    parsingAnswer = false;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_ADMIN::PARSER::ParseAdmin(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "admin") == 0)
+    {
+    if (attr && attr[0] && attr[1])
+        {
+        if (strcasecmp(attr[1], "error") == 0)
+            {
+            if (attr[2] && attr[3])
+                error = attr[3];
+            else
+                error = "Admin not found.";
+            }
+        else
+            {
+            parsingAnswer = true;
+            for (const char ** pos = attr; *pos != NULL; pos = pos + 2)
+                if (!TryParse(propertyParsers, ToLower(*pos), pos, encoding, *pos))
+                    {
+                    error = std::string("Invalid parameter '") + *pos + "'.";
+                    break;
+                    }
+            }
+        }
+    else
+        parsingAnswer = true;
+    }
+}
+//-----------------------------------------------------------------------------
+/*void GET_ADMIN::PARSER::ParseAdminParams(const char * el, const char ** attr)
+{
+if (!TryParse(propertyParsers, ToLower(el), attr))
+    error = "Invalid parameter.";
+}*/
diff --git a/stglibs/srvconf.lib/parsers/get_admin.h b/stglibs/srvconf.lib/parsers/get_admin.h
new file mode 100644 (file)
index 0000000..f7cb308
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_GET_ADMIN_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_GET_ADMIN_H__
+
+#include "base.h"
+#include "property.h"
+
+#include "stg/admin_conf.h"
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace GET_ADMIN
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    typedef GET_ADMIN::INFO INFO;
+
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    virtual ~PARSER();
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    PROPERTY_PARSERS propertyParsers;
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    INFO info;
+    int depth;
+    bool parsingAnswer;
+    std::string error;
+
+    void ParseAdmin(const char * el, const char ** attr);
+    //void ParseAdminParams(const char * el, const char ** attr);
+};
+
+} // namespace GET_ADMIN
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/get_container.h b/stglibs/srvconf.lib/parsers/get_container.h
new file mode 100644 (file)
index 0000000..cbfd1ea
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_GET_CONTAINER_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_GET_CONTAINER_H__
+
+#include "base.h"
+
+#include <string>
+
+#include <strings.h>
+
+namespace STG
+{
+namespace GET_CONTAINER
+{
+
+template <typename ELEMENT_PARSER>
+class PARSER: public STG::PARSER
+{
+public:
+    typedef std::vector<typename ELEMENT_PARSER::INFO> INFO;
+    typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
+    PARSER(const std::string & t, CALLBACK f, void * d, const std::string & e)
+        : tag(t), callback(f), data(d), encoding(e),
+          elementParser(&PARSER<ELEMENT_PARSER>::ElementCallback, this, e),
+          depth(0), parsingAnswer(false)
+    {}
+    int  ParseStart(const char * el, const char ** attr)
+    {
+    depth++;
+    if (depth == 1 && strcasecmp(el, tag.c_str()) == 0)
+        parsingAnswer = true;
+
+    if (depth > 1 && parsingAnswer)
+        elementParser.ParseStart(el, attr);
+
+    return 0;
+    }
+    void ParseEnd(const char * el)
+    {
+    depth--;
+    if (depth > 0 && parsingAnswer)
+        elementParser.ParseEnd(el);
+
+    if (depth == 0 && parsingAnswer)
+        {
+        if (callback)
+            callback(error.empty(), error, info, data);
+        error.clear();
+        info.clear();
+        parsingAnswer = false;
+        }
+    }
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    std::string tag;
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    ELEMENT_PARSER elementParser;
+    INFO info;
+    int depth;
+    bool parsingAnswer;
+    std::string error;
+
+    void AddElement(const typename ELEMENT_PARSER::INFO & elementInfo)
+    {
+    info.push_back(elementInfo);
+    }
+    void SetError(const std::string & e) { error = e; }
+
+    static void ElementCallback(bool result, const std::string& reason, const typename ELEMENT_PARSER::INFO & info, void * data)
+    {
+    PARSER<ELEMENT_PARSER> * parser = static_cast<PARSER<ELEMENT_PARSER> *>(data);
+    if (!result)
+        parser->SetError(reason);
+    else
+        parser->AddElement(info);
+    }
+};
+
+} // namespace GET_CONTAINER
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/get_corp.cpp b/stglibs/srvconf.lib/parsers/get_corp.cpp
new file mode 100644 (file)
index 0000000..732a4d6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "get_corp.h"
+
+#include "parsers/property.h"
+
+#include "stg/common.h"
+
+#include <strings.h>
+
+using namespace STG;
+
+GET_CORP::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+    AddParser(propertyParsers, "name", info.name);
+    AddParser(propertyParsers, "cash", info.cash);
+}
+//-----------------------------------------------------------------------------
+GET_CORP::PARSER::~PARSER()
+{
+    PROPERTY_PARSERS::iterator it(propertyParsers.begin());
+    while (it != propertyParsers.end())
+        delete (it++)->second;
+}
+//-----------------------------------------------------------------------------
+int GET_CORP::PARSER::ParseStart(const char * el, const char ** attr)
+{
+depth++;
+if (depth == 1)
+    ParseCorp(el, attr);
+
+if (depth == 2 && parsingAnswer)
+    ParseCorpParams(el, attr);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void GET_CORP::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0 && parsingAnswer)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    error.clear();
+    parsingAnswer = false;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_CORP::PARSER::ParseCorp(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "corp") == 0)
+    {
+    if (attr && attr[0] && attr[1])
+        {
+        if (strcasecmp(attr[1], "error") == 0)
+            {
+            if (attr[2] && attr[3])
+                error = attr[3];
+            else
+                error = "Corp not found.";
+            }
+        else
+            parsingAnswer = true;
+        }
+    else
+        parsingAnswer = true;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_CORP::PARSER::ParseCorpParams(const char * el, const char ** attr)
+{
+if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
+    error = "Invalid parameter.";
+}
diff --git a/stglibs/srvconf.lib/parsers/get_corp.h b/stglibs/srvconf.lib/parsers/get_corp.h
new file mode 100644 (file)
index 0000000..b9d8798
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_GET_CORP_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_GET_CORP_H__
+
+#include "base.h"
+#include "property.h"
+
+#include "stg/corp_conf.h"
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace GET_CORP
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    typedef GET_CORP::INFO INFO;
+
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    virtual ~PARSER();
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    PROPERTY_PARSERS propertyParsers;
+    CALLBACK callback;
+    void * data;
+    INFO info;
+    std::string encoding;
+    int depth;
+    bool parsingAnswer;
+    std::string error;
+
+    void ParseCorp(const char * el, const char ** attr);
+    void ParseCorpParams(const char * el, const char ** attr);
+};
+
+} // namespace GET_CORP
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/get_service.cpp b/stglibs/srvconf.lib/parsers/get_service.cpp
new file mode 100644 (file)
index 0000000..e9949cb
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "get_service.h"
+
+#include "parsers/property.h"
+
+#include "stg/common.h"
+
+#include <strings.h>
+
+using namespace STG;
+
+GET_SERVICE::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+    AddParser(propertyParsers, "name", info.name);
+    AddParser(propertyParsers, "comment", info.comment, GetEncodedValue);
+    AddParser(propertyParsers, "cost", info.cost);
+    AddParser(propertyParsers, "payDay", info.payDay);
+}
+//-----------------------------------------------------------------------------
+GET_SERVICE::PARSER::~PARSER()
+{
+    PROPERTY_PARSERS::iterator it(propertyParsers.begin());
+    while (it != propertyParsers.end())
+        delete (it++)->second;
+}
+//-----------------------------------------------------------------------------
+int GET_SERVICE::PARSER::ParseStart(const char * el, const char ** attr)
+{
+depth++;
+if (depth == 1)
+    ParseService(el, attr);
+
+/*if (depth == 2 && parsingAnswer)
+    ParseServiceParams(el, attr);*/
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void GET_SERVICE::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0 && parsingAnswer)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    error.clear();
+    parsingAnswer = false;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_SERVICE::PARSER::ParseService(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "service") == 0)
+    {
+    if (attr && attr[0] && attr[1])
+        {
+        if (strcasecmp(attr[1], "error") == 0)
+            {
+            if (attr[2] && attr[3])
+                error = attr[3];
+            else
+                error = "Service not found.";
+            }
+        else
+            {
+            parsingAnswer = true;
+            for (const char ** pos = attr; *pos != NULL; pos = pos + 2)
+                if (!TryParse(propertyParsers, ToLower(*pos), pos, encoding, *pos))
+                    {
+                    error = std::string("Invalid parameter '") + *pos + "' or value '" + *(pos + 1) + "'.";
+                    break;
+                    }
+            }
+        }
+    else
+        parsingAnswer = true;
+    }
+}
+//-----------------------------------------------------------------------------
+/*void GET_SERVICE::PARSER::ParseServiceParams(const char * el, const char ** attr)
+{
+if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
+    error = "Invalid parameter.";
+}*/
diff --git a/stglibs/srvconf.lib/parsers/get_service.h b/stglibs/srvconf.lib/parsers/get_service.h
new file mode 100644 (file)
index 0000000..d821362
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_GET_SERVICE_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_GET_SERVICE_H__
+
+#include "base.h"
+#include "property.h"
+
+#include "stg/service_conf.h"
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace GET_SERVICE
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    typedef GET_SERVICE::INFO INFO;
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    virtual ~PARSER();
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    PROPERTY_PARSERS propertyParsers;
+    CALLBACK callback;
+    void * data;
+    INFO info;
+    std::string encoding;
+    int depth;
+    bool parsingAnswer;
+    std::string error;
+
+    void ParseService(const char * el, const char ** attr);
+    //void ParseServiceParams(const char * el, const char ** attr);
+};
+
+} // namespace GET_SERVICE
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/get_tariff.cpp b/stglibs/srvconf.lib/parsers/get_tariff.cpp
new file mode 100644 (file)
index 0000000..e206636
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "get_tariff.h"
+
+#include "parsers/property.h"
+
+#include "stg/common.h"
+
+#include <utility>
+
+#include <strings.h>
+
+using namespace STG;
+
+namespace
+{
+
+template <typename A, typename T>
+class AOS_PARSER : public BASE_PROPERTY_PARSER
+{
+    public:
+        typedef bool (* FUNC)(const char **, A &, T A::value_type:: *);
+        AOS_PARSER(A & a, T A::value_type:: * fld, FUNC f) : array(a), field(fld), func(f) {}
+        virtual bool Parse(const char ** attr, const std::string & /*attrName*/, const std::string & /*fromEncoding*/) { return func(attr, array, field); }
+    private:
+        A & array;
+        T A::value_type:: * field;
+        FUNC func;
+};
+
+template <typename A, typename T>
+inline
+void AddAOSParser(PROPERTY_PARSERS & parsers, const std::string & name, A & array, T A::value_type:: * field, const typename AOS_PARSER<A, T>::FUNC & func)
+{
+    parsers.insert(std::make_pair(ToLower(name), new AOS_PARSER<A, T>(array, field, func)));
+}
+
+bool GetTimeSpan(const char ** attr, DIRPRICE_DATA & value, const std::string & attrName)
+{
+if (CheckValue(attr, attrName))
+    {
+    int hb = 0;
+    int mb = 0;
+    int he = 0;
+    int me = 0;
+    if (ParseTariffTimeStr(attr[1], hb, mb, he, me) == 0)
+        {
+        value.hDay = hb;
+        value.mDay = mb;
+        value.hNight = he;
+        value.mNight = me;
+        return true;
+        }
+    }
+return false;
+}
+
+template <typename T>
+bool GetTraffType(const char ** attr, T & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+value = TARIFF::StringToTraffType(attr[1]);
+return true;
+}
+
+template <typename T>
+bool GetPeriod(const char ** attr, T & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+std::string type(attr[1]);
+if (type == "day")
+    value = TARIFF::DAY;
+else if (type == "month")
+    value = TARIFF::MONTH;
+else
+    return false;
+return true;
+}
+
+template <typename T>
+bool GetChangePolicy(const char ** attr, T & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+std::string type(attr[1]);
+if (type == "allow")
+        value = TARIFF::ALLOW;
+else if (type == "to_cheap")
+        value = TARIFF::TO_CHEAP;
+else if (type == "to_expensive")
+        value = TARIFF::TO_EXPENSIVE;
+else if (type == "deny")
+        value = TARIFF::DENY;
+else
+    return false;
+return true;
+}
+
+template <typename T>
+bool GetChangePolicyTimeout(const char ** attr, T & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+value = readTime(attr[1]);
+return true;
+}
+
+template <typename A, typename T>
+bool GetSlashedValue(const char ** attr, A & array, T A::value_type:: * field)
+{
+if (!CheckValue(attr, "value"))
+    return false;
+const char * start = attr[1];
+size_t item = 0;
+const char * pos = NULL;
+while ((pos = strchr(start, '/')) && item < array.size())
+    {
+    if (str2x(std::string(start, pos), array[item++].*field))
+            return false;
+    start = pos + 1;
+    }
+if (item < array.size())
+    if (str2x(start, array[item].*field))
+        return false;
+return true;
+}
+
+} // namespace anonymous
+
+GET_TARIFF::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+    AddParser(propertyParsers, "fee", info.tariffConf.fee);
+    AddParser(propertyParsers, "passiveCost", info.tariffConf.passiveCost);
+    AddParser(propertyParsers, "free", info.tariffConf.free);
+    AddParser(propertyParsers, "traffType", info.tariffConf.traffType, GetTraffType);
+    AddParser(propertyParsers, "period", info.tariffConf.period, GetPeriod);
+    AddParser(propertyParsers, "changePolicy", info.tariffConf.changePolicy, GetChangePolicy);
+    AddParser(propertyParsers, "changePolicyTimeout", info.tariffConf.changePolicyTimeout, GetChangePolicyTimeout);
+    for (size_t i = 0; i < DIR_NUM; ++i)
+        AddParser(propertyParsers, "time" + unsigned2str(i), info.dirPrice[i], GetTimeSpan);
+    AddAOSParser(propertyParsers, "priceDayA", info.dirPrice, &DIRPRICE_DATA::priceDayA, GetSlashedValue);
+    AddAOSParser(propertyParsers, "priceDayB", info.dirPrice, &DIRPRICE_DATA::priceDayB, GetSlashedValue);
+    AddAOSParser(propertyParsers, "priceNightA", info.dirPrice, &DIRPRICE_DATA::priceNightA, GetSlashedValue);
+    AddAOSParser(propertyParsers, "priceNightB", info.dirPrice, &DIRPRICE_DATA::priceNightB, GetSlashedValue);
+    AddAOSParser(propertyParsers, "singlePrice", info.dirPrice, &DIRPRICE_DATA::singlePrice, GetSlashedValue);
+    AddAOSParser(propertyParsers, "noDiscount", info.dirPrice, &DIRPRICE_DATA::noDiscount, GetSlashedValue);
+    AddAOSParser(propertyParsers, "threshold", info.dirPrice, &DIRPRICE_DATA::threshold, GetSlashedValue);
+}
+//-----------------------------------------------------------------------------
+GET_TARIFF::PARSER::~PARSER()
+{
+    PROPERTY_PARSERS::iterator it(propertyParsers.begin());
+    while (it != propertyParsers.end())
+        delete (it++)->second;
+}
+//-----------------------------------------------------------------------------
+int GET_TARIFF::PARSER::ParseStart(const char * el, const char ** attr)
+{
+depth++;
+if (depth == 1)
+    ParseTariff(el, attr);
+
+if (depth == 2 && parsingAnswer)
+    ParseTariffParams(el, attr);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void GET_TARIFF::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0 && parsingAnswer)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    error.clear();
+    parsingAnswer = false;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_TARIFF::PARSER::ParseTariff(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "tariff") == 0)
+    {
+    if (attr && attr[0] && attr[1])
+        {
+        if (strcasecmp(attr[1], "error") == 0)
+            {
+            if (attr[2] && attr[3])
+                error = attr[3];
+            else
+                error = "Tariff not found.";
+            }
+        else
+            {
+            parsingAnswer = true;
+            if (strcasecmp(attr[0], "name") == 0)
+                info.tariffConf.name = attr[1];
+            }
+        }
+    else
+        parsingAnswer = true;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_TARIFF::PARSER::ParseTariffParams(const char * el, const char ** attr)
+{
+if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
+    error = std::string("Invalid parameter '") + el + "'.";
+}
diff --git a/stglibs/srvconf.lib/parsers/get_tariff.h b/stglibs/srvconf.lib/parsers/get_tariff.h
new file mode 100644 (file)
index 0000000..be78fdb
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_GET_TARIFF_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_GET_TARIFF_H__
+
+#include "base.h"
+#include "property.h"
+
+#include "stg/tariff_conf.h"
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace GET_TARIFF
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    typedef GET_TARIFF::INFO INFO;
+
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    virtual ~PARSER();
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    PROPERTY_PARSERS propertyParsers;
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    INFO info;
+    int depth;
+    bool parsingAnswer;
+    std::string error;
+
+    void ParseTariff(const char * el, const char ** attr);
+    void ParseTariffParams(const char * el, const char ** attr);
+};
+
+} // namespace GET_TARIFF
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/get_user.cpp b/stglibs/srvconf.lib/parsers/get_user.cpp
new file mode 100644 (file)
index 0000000..03327c4
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "get_user.h"
+
+#include "stg/common.h"
+
+#include <map>
+#include <utility>
+
+#include <strings.h>
+
+using namespace STG;
+
+namespace STG
+{
+
+template <>
+bool GetValue<GET_USER::STAT>(const char ** attr, GET_USER::STAT & value, const std::string & /*attrName*/)
+{
+if (!attr)
+    return false;
+std::map<std::string, long long *> props;
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    props.insert(std::pair<std::string, long long *>("su" + unsigned2str(i), &value.su[i]));
+    props.insert(std::pair<std::string, long long *>("sd" + unsigned2str(i), &value.sd[i]));
+    props.insert(std::pair<std::string, long long *>("mu" + unsigned2str(i), &value.mu[i]));
+    props.insert(std::pair<std::string, long long *>("md" + unsigned2str(i), &value.md[i]));
+    }
+size_t pos = 0;
+while (attr[pos])
+    {
+        std::string name(ToLower(attr[pos++]));
+        std::map<std::string, long long *>::iterator it(props.find(name));
+        if (it != props.end())
+            if (str2x(attr[pos++], *it->second) < 0)
+                return false;
+    }
+return true;
+}
+
+}
+
+GET_USER::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+    AddParser(propertyParsers, "login", info.login);
+    AddParser(propertyParsers, "password", info.password);
+    AddParser(propertyParsers, "cash", info.cash);
+    AddParser(propertyParsers, "credit", info.credit);
+    AddParser(propertyParsers, "creditExpire", info.creditExpire);
+    AddParser(propertyParsers, "lastCash", info.lastCashAdd);
+    AddParser(propertyParsers, "lastTimeCash", info.lastCashAddTime);
+    AddParser(propertyParsers, "freeMb", info.prepaidTraff);
+    AddParser(propertyParsers, "down", info.disabled);
+    AddParser(propertyParsers, "passive", info.passive);
+    AddParser(propertyParsers, "disableDetailStat", info.disableDetailStat);
+    AddParser(propertyParsers, "status", info.connected);
+    AddParser(propertyParsers, "aonline", info.alwaysOnline);
+    AddParser(propertyParsers, "currIP", info.ip, GetIPValue);
+    AddParser(propertyParsers, "ip", info.ips);
+    AddParser(propertyParsers, "tariff", info.tariff);
+    AddParser(propertyParsers, "group", info.group, "koi8-ru", GetEncodedValue);
+    AddParser(propertyParsers, "note", info.note, "koi8-ru", GetEncodedValue);
+    AddParser(propertyParsers, "email", info.email, "koi8-ru", GetEncodedValue);
+    AddParser(propertyParsers, "name", info.name, "koi8-ru", GetEncodedValue);
+    AddParser(propertyParsers, "address", info.address, "koi8-ru", GetEncodedValue);
+    AddParser(propertyParsers, "phone", info.phone, "cp1251", GetEncodedValue);
+    AddParser(propertyParsers, "corp", info.corp);
+    AddParser(propertyParsers, "traff", info.stat);
+    AddParser(propertyParsers, "pingTime", info.pingTime);
+    AddParser(propertyParsers, "lastActivityTime", info.lastActivityTime);
+
+    for (size_t i = 0; i < USERDATA_NUM; ++i)
+        AddParser(propertyParsers, "userData" + unsigned2str(i), info.userData[i], "koi8-ru", GetEncodedValue);
+}
+//-----------------------------------------------------------------------------
+GET_USER::PARSER::~PARSER()
+{
+    PROPERTY_PARSERS::iterator it(propertyParsers.begin());
+    while (it != propertyParsers.end())
+        delete (it++)->second;
+}
+//-----------------------------------------------------------------------------
+int GET_USER::PARSER::ParseStart(const char * el, const char ** attr)
+{
+depth++;
+if (depth == 1)
+    ParseUser(el, attr);
+
+if (depth == 2 && parsingAnswer)
+    ParseUserParams(el, attr);
+
+if (depth == 3 && parsingAnswer)
+    {
+    ParseAuthBy(el, attr);
+    ParseServices(el, attr);
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void GET_USER::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0 && parsingAnswer)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    error.clear();
+    parsingAnswer = false;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_USER::PARSER::ParseUser(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "user") == 0)
+    {
+    if (attr && attr[0] && attr[1])
+        {
+        if (strcasecmp(attr[1], "error") == 0)
+            {
+            if (attr[2] && attr[3])
+                error = attr[3];
+            else
+                error = "User not found.";
+            }
+        else if (strcasecmp(attr[0], "login") == 0 && attr[1])
+            info.login = attr[1];
+        }
+    parsingAnswer = true;
+    }
+}
+//-----------------------------------------------------------------------------
+void GET_USER::PARSER::ParseUserParams(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "AuthorizedBy") != 0 &&
+    !TryParse(propertyParsers, ToLower(el), attr, encoding))
+    error = "Invalid parameter.";
+else if (strcasecmp(el, "Services") != 0 &&
+    !TryParse(propertyParsers, ToLower(el), attr, encoding))
+    error = "Invalid parameter.";
+}
+//-----------------------------------------------------------------------------
+void GET_USER::PARSER::ParseAuthBy(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "Auth") == 0 &&
+    attr && attr[0] && attr[1] &&
+    strcasecmp(attr[0], "name") == 0)
+    info.authBy.push_back(attr[1]);
+}
+//-----------------------------------------------------------------------------
+void GET_USER::PARSER::ParseServices(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "Service") == 0 &&
+    attr && attr[0] && attr[1] &&
+    strcasecmp(attr[0], "name") == 0)
+    info.services.push_back(attr[1]);
+}
diff --git a/stglibs/srvconf.lib/parsers/get_user.h b/stglibs/srvconf.lib/parsers/get_user.h
new file mode 100644 (file)
index 0000000..a0e3e3a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_GET_USER_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_GET_USER_H__
+
+#include "base.h"
+#include "property.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace GET_USER
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    typedef GET_USER::INFO INFO;
+
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    virtual ~PARSER();
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    PROPERTY_PARSERS propertyParsers;
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    INFO info;
+    int depth;
+    bool parsingAnswer;
+    std::string error;
+
+    void ParseUser(const char * el, const char ** attr);
+    void ParseUserParams(const char * el, const char ** attr);
+    void ParseAuthBy(const char * el, const char ** attr);
+    void ParseServices(const char * el, const char ** attr);
+};
+
+} // namespace GET_USER
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/property.cpp b/stglibs/srvconf.lib/parsers/property.cpp
new file mode 100644 (file)
index 0000000..eb9c2df
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "property.h"
+
+#include <strings.h>
+
+bool STG::CheckValue(const char ** attr, const std::string & attrName)
+{
+return attr && attr[0] && attr[1] && strcasecmp(attr[0], attrName.c_str()) == 0;
+}
+
+bool STG::GetEncodedValue(const char ** attr, std::string & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+Decode21str(value, attr[1]);
+return true;
+}
+
+bool STG::GetIPValue(const char ** attr, uint32_t & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+std::string ip(attr[1]);
+value = inet_strington(attr[1]);
+if (value == 0 && ip != "0.0.0.0")
+    return false;
+return true;
+}
+
+bool STG::TryParse(PROPERTY_PARSERS & parsers, const std::string & name, const char ** attr, const std::string & toEncoding, const std::string & attrName)
+{
+    PROPERTY_PARSERS::iterator it(parsers.find(name));
+    if (it != parsers.end())
+        return it->second->Parse(attr, attrName, toEncoding);
+    return true; // Assume that non-existing params are ok.
+}
diff --git a/stglibs/srvconf.lib/parsers/property.h b/stglibs/srvconf.lib/parsers/property.h
new file mode 100644 (file)
index 0000000..7aa98ae
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PROPERTY_PARSERS_H__
+#define __STG_STGLIBS_SRVCONF_PROPERTY_PARSERS_H__
+
+#include "stg/common.h"
+
+#include <map>
+#include <string>
+
+namespace STG
+{
+
+class BASE_PROPERTY_PARSER
+{
+    public:
+        virtual ~BASE_PROPERTY_PARSER() {}
+        virtual bool Parse(const char ** attr, const std::string & attrName, const std::string & fromEncoding) = 0;
+};
+
+template <typename T>
+class PROPERTY_PARSER : public BASE_PROPERTY_PARSER
+{
+    public:
+        typedef bool (* FUNC)(const char **, T &, const std::string &);
+        PROPERTY_PARSER(T & v, FUNC f) : value(v), func(f) {}
+        PROPERTY_PARSER(T & v, FUNC f, const std::string & e) : value(v), func(f), encoding(e) {}
+        virtual bool Parse(const char ** attr, const std::string & attrName, const std::string & /*fromEncoding*/) { return func(attr, value, attrName); }
+    private:
+        T & value;
+        FUNC func;
+        std::string encoding;
+};
+
+template <>
+inline
+bool PROPERTY_PARSER<std::string>::Parse(const char ** attr, const std::string & attrName, const std::string & toEncoding)
+{
+if (!encoding.empty() && !toEncoding.empty())
+    {
+    std::string tmp;
+    if (!func(attr, tmp, attrName))
+        return false;
+    value = IconvString(tmp, encoding, toEncoding);
+    return true;
+    }
+else
+    return func(attr, value, attrName);
+}
+
+typedef std::map<std::string, BASE_PROPERTY_PARSER *> PROPERTY_PARSERS;
+
+bool CheckValue(const char ** attr, const std::string & attrName);
+
+template <typename T>
+inline
+bool GetValue(const char ** attr, T & value, const std::string & attrName)
+{
+if (CheckValue(attr, attrName))
+    if (str2x(attr[1], value) < 0)
+        return false;
+return true;
+}
+
+template <>
+inline
+bool GetValue<std::string>(const char ** attr, std::string & value, const std::string & attrName)
+{
+if (!CheckValue(attr, attrName))
+    return false;
+value = attr[1];
+return true;
+}
+
+template <>
+inline
+bool GetValue<double>(const char ** attr, double & value, const std::string & attrName)
+{
+if (CheckValue(attr, attrName))
+    if (strtodouble2(attr[1], value))
+        return false;
+return true;
+}
+
+bool GetEncodedValue(const char ** attr, std::string & value, const std::string & attrName);
+
+bool GetIPValue(const char ** attr, uint32_t& value, const std::string & attrName);
+
+template <typename T>
+inline
+void AddParser(PROPERTY_PARSERS & parsers, const std::string & name, T & value, const typename PROPERTY_PARSER<T>::FUNC & func = GetValue<T>)
+{
+    parsers.insert(std::make_pair(ToLower(name), new PROPERTY_PARSER<T>(value, func)));
+}
+
+template <typename T>
+inline
+void AddParser(PROPERTY_PARSERS & parsers, const std::string & name, T & value, const std::string & toEncoding, const typename PROPERTY_PARSER<T>::FUNC & func = GetValue<T>)
+{
+    parsers.insert(std::make_pair(ToLower(name), new PROPERTY_PARSER<T>(value, func, toEncoding)));
+}
+
+bool TryParse(PROPERTY_PARSERS & parsers, const std::string & name, const char ** attr, const std::string & fromEncoding, const std::string & attrName = "value");
+
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/resetable_utils.h b/stglibs/srvconf.lib/parsers/resetable_utils.h
new file mode 100644 (file)
index 0000000..6f026ad
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_RESETABLE_UTILS_H__
+#define __STG_STGLIBS_SRVCONF_RESETABLE_UTILS_H__
+
+#include "stg/resetable.h"
+#include "stg/common.h"
+
+#include <string>
+#include <ostream>
+
+namespace STG
+{
+
+template <typename T>
+inline
+void appendTag(std::ostream & stream, const std::string & name, const T & value)
+{
+    stream << "<" << name << " value=\"" << value << "\"/>";
+}
+
+template <typename T>
+inline
+void appendTag(std::ostream & stream, const std::string & name, size_t suffix, const T & value)
+{
+    stream << "<" << name << suffix << " value=\"" << value << "\"/>";
+}
+
+template <>
+inline
+void appendTag<uint8_t>(std::ostream & stream, const std::string & name, const uint8_t & value)
+{
+    stream << "<" << name << " value=\"" << static_cast<unsigned>(value) << "\"/>";
+}
+
+template <>
+inline
+void appendTag<int8_t>(std::ostream & stream, const std::string & name, const int8_t & value)
+{
+    stream << "<" << name << " value=\"" << static_cast<int>(value) << "\"/>";
+}
+
+template <typename T>
+inline
+void appendAttr(std::ostream & stream, const std::string & name, const T & value)
+{
+    stream << " " << name << "=\"" << value << "\"";
+}
+
+template <typename T>
+inline
+void appendAttr(std::ostream & stream, const std::string & name, size_t suffix, const T & value)
+{
+    stream << " " << name << suffix << "=\"" << value << "\"";
+}
+
+template <>
+inline
+void appendAttr<uint8_t>(std::ostream & stream, const std::string & name, const uint8_t & value)
+{
+    stream << " " << name << "=\"" << static_cast<unsigned>(value) << "\"";
+}
+
+template <>
+inline
+void appendAttr<int8_t>(std::ostream & stream, const std::string & name, const int8_t & value)
+{
+    stream << " " << name << "=\"" << static_cast<int>(value) << "\"";
+}
+
+template <typename T>
+inline
+void appendResetableTag(std::ostream & stream, const std::string & name, const T & value)
+{
+if (!value.empty())
+    appendTag(stream, name, value.const_data());
+}
+
+template <typename T>
+inline
+void appendResetableTag(std::ostream & stream, const std::string & name, size_t suffix, const T & value)
+{
+if (!value.empty())
+    appendTag(stream, name, suffix, value.const_data());
+}
+
+template <typename T>
+inline
+void appendResetableAttr(std::ostream & stream, const std::string & name, const T & value)
+{
+if (!value.empty())
+    appendAttr(stream, name, value.const_data());
+}
+
+template <typename T>
+inline
+void appendResetableAttr(std::ostream & stream, const std::string & name, size_t suffix, const T & value)
+{
+if (!value.empty())
+    appendAttr(stream, name, suffix, value.const_data());
+}
+
+inline
+RESETABLE<std::string> MaybeEncode(const RESETABLE<std::string> & value)
+{
+RESETABLE<std::string> res;
+if (!value.empty())
+    res = Encode12str(value.data());
+return res;
+}
+
+inline
+RESETABLE<std::string> MaybeIconv(const RESETABLE<std::string> & value, const std::string & fromEncoding, const std::string & toEncoding)
+{
+RESETABLE<std::string> res;
+if (!value.empty())
+    res = IconvString(value.data(), fromEncoding, toEncoding);
+return res;
+}
+
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/server_info.cpp b/stglibs/srvconf.lib/parsers/server_info.cpp
new file mode 100644 (file)
index 0000000..f003361
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include "server_info.h"
+
+#include "stg/common.h"
+
+#include <cstdio> // sprintf
+
+#include <strings.h>
+
+using namespace STG;
+
+SERVER_INFO::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
+    : callback(f),
+      data(d),
+      encoding(e),
+      depth(0),
+      parsingAnswer(false)
+{
+    AddParser(propertyParsers, "uname", info.uname);
+    AddParser(propertyParsers, "version", info.version);
+    AddParser(propertyParsers, "tariff", info.tariffType);
+    AddParser(propertyParsers, "dir_num", info.dirNum);
+    AddParser(propertyParsers, "user_num", info.usersNum);
+    AddParser(propertyParsers, "tariff_num", info.tariffNum);
+
+    for (size_t i = 0; i < DIR_NUM; i++)
+        AddParser(propertyParsers, "dir_name_" + unsigned2str(i), info.dirName[i], GetEncodedValue);
+}
+//-----------------------------------------------------------------------------
+int SERVER_INFO::PARSER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "GetServerInfo") == 0)
+        parsingAnswer = true;
+    }
+else
+    {
+    if (depth == 2 && parsingAnswer)
+        if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
+            error = "Invalid parameter.";
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void SERVER_INFO::PARSER::ParseEnd(const char * /*el*/)
+{
+depth--;
+if (depth == 0 && parsingAnswer)
+    {
+    if (callback)
+        callback(error.empty(), error, info, data);
+    error.clear();
+    parsingAnswer = false;
+    }
+}
diff --git a/stglibs/srvconf.lib/parsers/server_info.h b/stglibs/srvconf.lib/parsers/server_info.h
new file mode 100644 (file)
index 0000000..0390638
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *    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 <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_SERVER_INFO_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_SERVER_INFO_H__
+
+#include "base.h"
+#include "property.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace SERVER_INFO
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    PARSER(CALLBACK f, void * data, const std::string & encoding);
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, info, data); }
+
+private:
+    PROPERTY_PARSERS propertyParsers;
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    int depth;
+    bool parsingAnswer;
+    INFO info;
+    std::string error;
+};
+
+} // namespace SERVER_INFO
+} // namespace STG
+
+#endif
diff --git a/stglibs/srvconf.lib/parsers/simple.cpp b/stglibs/srvconf.lib/parsers/simple.cpp
new file mode 100644 (file)
index 0000000..4749c70
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#include "simple.h"
+
+#include <strings.h>
+
+using namespace STG;
+
+SIMPLE::PARSER::PARSER(const std::string & t, CALLBACK f, void * d, const std::string & e)
+    : tag(t),
+      callback(f),
+      data(d),
+      encoding(e),
+      depth(0)
+{
+}
+//-----------------------------------------------------------------------------
+int SIMPLE::PARSER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    if (strcasecmp(el, tag.c_str()) == 0)
+        ParseAnswer(el, attr);
+return 0;
+}
+//-----------------------------------------------------------------------------
+void SIMPLE::PARSER::ParseEnd(const char *)
+{
+depth--;
+}
+//-----------------------------------------------------------------------------
+void SIMPLE::PARSER::ParseAnswer(const char * /*el*/, const char ** attr)
+{
+if (!callback)
+    return;
+if (attr && attr[0] && attr[1])
+    callback(strcasecmp(attr[1], "ok") == 0, attr[2] && attr[3] ? attr[3] : attr[1], data);
+else
+    callback(false, "Invalid response.", data);
+}
diff --git a/stglibs/srvconf.lib/parsers/simple.h b/stglibs/srvconf.lib/parsers/simple.h
new file mode 100644 (file)
index 0000000..244e8ef
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *    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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_STGLIBS_SRVCONF_PARSER_SIMPLE_H__
+#define __STG_STGLIBS_SRVCONF_PARSER_SIMPLE_H__
+
+#include "base.h"
+
+#include "stg/servconf_types.h"
+
+#include <string>
+
+namespace STG
+{
+namespace SIMPLE
+{
+
+class PARSER: public STG::PARSER
+{
+public:
+    PARSER(const std::string & tag, CALLBACK f, void * data, const std::string & encoding);
+    int  ParseStart(const char * el, const char ** attr);
+    void ParseEnd(const char * el);
+    void Failure(const std::string & reason) { callback(false, reason, data); }
+
+private:
+    std::string tag;
+    CALLBACK callback;
+    void * data;
+    std::string encoding;
+    int depth;
+
+    void ParseAnswer(const char * el, const char ** attr);
+};
+
+} // namespace SIMPLE
+} // namespace STG
+
+#endif
index 2f4afaba147bc7132d33bddfba5331197b9cb877..046190ee25bcf9381d69cb5876a4cd8de95decb4 100644 (file)
 
 /*
  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
- /*
- $Revision: 1.8 $
- $Date: 2010/08/04 00:40:38 $
- $Author: faust $
- */
+#include "stg/servconf.h"
 
-#include <cstdio>
-#include <cstring>
+#include "netunit.h"
 
-#include "stg/common.h"
-#include "stg/servconf.h"
+#include "parsers/simple.h"
+#include "parsers/get_container.h"
 
-using namespace std;
+#include "parsers/server_info.h"
 
-//-----------------------------------------------------------------------------
-int AnsRecv(void * data, list<string> * list1)
-{
-//NODE * node;
-SERVCONF * sc;
-char ans[ENC_MSG_LEN + 1];
-int len, done = 0;
+#include "parsers/get_admin.h"
+#include "parsers/chg_admin.h"
+
+#include "parsers/get_tariff.h"
+#include "parsers/chg_tariff.h"
 
-sc = (SERVCONF*)data;
+#include "parsers/auth_by.h"
+#include "parsers/get_user.h"
+#include "parsers/chg_user.h"
+
+#include "parsers/get_service.h"
+#include "parsers/chg_service.h"
+
+#include "parsers/get_corp.h"
+#include "parsers/chg_corp.h"
+
+#include "parsers/base.h"
+
+#include "stg/common.h"
+
+#include <cstdio>
+#include <cstring>
+#include <clocale>
 
-XML_ParserReset(sc->parser, NULL);
-XML_SetElementHandler(sc->parser, Start, End);
-XML_SetUserData(sc->parser, data);
+#include <expat.h>
+#include <langinfo.h>
 
-//loop parsing
-list<string>::iterator node;
-node = list1->begin();
+using namespace STG;
 
-if (node == list1->end())
+class SERVCONF::IMPL
+{
+public:
+    IMPL(const std::string & server, uint16_t port,
+         const std::string & login, const std::string & password);
+    IMPL(const std::string & server, uint16_t port,
+         const std::string & localAddress, uint16_t localPort,
+         const std::string & login, const std::string & password);
+    ~IMPL() { XML_ParserFree(parser); }
+
+    const std::string & GetStrError() const;
+    static void Start(void * data, const char * el, const char ** attr);
+    static void End(void * data, const char * el);
+
+    int RawXML(const std::string & request, RAW_XML::CALLBACK f, void * data);
+
+    template <class P, typename C>
+    int Exec(const std::string & request, C callback, void * data)
     {
-    return st_ok;
+        P cp(callback, data, encoding);
+        return ExecImpl(request, cp);
     }
 
-while (node != list1->end())
+    template <class P, typename C>
+    int Exec(const std::string & tag, const std::string & request, C callback, void * data)
     {
-    strncpy(ans, node->c_str(), ENC_MSG_LEN);
-    ans[ENC_MSG_LEN] = 0;
-       //printf("---> %s\n", ans);
-    len = strlen(ans);
-
-    if (XML_Parse(sc->parser, ans, len, done) == XML_STATUS_ERROR)
-        {
-        strprintf(&sc->errorMsg, "XML parse error at line %d: %s",
-                  static_cast<int>(XML_GetCurrentLineNumber(sc->parser)),
-                  XML_ErrorString(XML_GetErrorCode(sc->parser)));
-        return st_xml_parse_error;
-        }
-    ++node;
+        P cp(tag, callback, data, encoding);
+        return ExecImpl(request, cp);
+    }
+
+    const std::string & Encoding() const { return encoding; }
+
+private:
+    NETTRANSACT nt;
+
+    std::string encoding;
+    std::string errorMsg;
+    XML_Parser parser;
+
+    static bool ParserRecv(const std::string & chunk, bool final, void * data);
+    static bool SimpleRecv(const std::string & chunk, bool final, void * data);
+    int ExecImpl(const std::string & request, PARSER & cp);
+};
+
+bool SERVCONF::IMPL::ParserRecv(const std::string & chunk, bool final, void * data)
+{
+SERVCONF::IMPL * sc = static_cast<SERVCONF::IMPL *>(data);
 
+if (XML_Parse(sc->parser, chunk.c_str(), chunk.length(), final) == XML_STATUS_ERROR)
+    {
+    strprintf(&sc->errorMsg, "XML parse error at line %d, %d: %s. Is final: %d",
+              static_cast<int>(XML_GetCurrentLineNumber(sc->parser)),
+              static_cast<int>(XML_GetCurrentColumnNumber(sc->parser)),
+              XML_ErrorString(XML_GetErrorCode(sc->parser)), (int)final);
+    return false;
     }
 
-return 0;
+return true;
 }
-//-----------------------------------------------------------------------------
-void Start(void *data, const char *el, const char **attr)
+
+bool SERVCONF::IMPL::SimpleRecv(const std::string & chunk, bool /*final*/, void * data)
 {
-SERVCONF * sc;
-sc = (SERVCONF*)data;
-sc->Start(el, attr);
+*static_cast<std::string *>(data) += chunk;
+return true;
 }
-//-----------------------------------------------------------------------------
-void End(void *data, const char *el)
+
+SERVCONF::SERVCONF(const std::string & server, uint16_t port,
+                   const std::string & login, const std::string & password)
+    : pImpl(new IMPL(server, port, login, password))
 {
-SERVCONF * sc;
-sc = (SERVCONF*)data;
-sc->End(el);
 }
-//-----------------------------------------------------------------------------
-SERVCONF::SERVCONF()
-    : currParser(NULL),
-      error(0),
-      RecvUserDataCb(NULL),
-      RecvGetUserDataCb(NULL),
-      RecvServerInfoDataCb(NULL),
-      RecvChgUserCb(NULL),
-      RecvCheckUserCb(NULL),
-      RecvSendMessageCb(NULL),
-      getUserDataDataCb(NULL),
-      getUserAuthByDataCb(NULL),
-      getUsersDataDataCb(NULL),
-      getServerInfoDataCb(NULL),
-      chgUserDataCb(NULL),
-      checkUserDataCb(NULL),
-      sendMessageDataCb(NULL)
+
+SERVCONF::SERVCONF(const std::string & server, uint16_t port,
+                   const std::string & localAddress, uint16_t localPort,
+                   const std::string & login, const std::string & password)
+    : pImpl(new IMPL(server, port, localAddress, localPort, login, password))
 {
-parser = XML_ParserCreate(NULL);
 }
-//-----------------------------------------------------------------------------
+
 SERVCONF::~SERVCONF()
 {
-XML_ParserFree(parser);
+delete pImpl;
 }
-//-----------------------------------------------------------------------------
-void SERVCONF::SetServer(const char * server)
+
+int SERVCONF::ServerInfo(SERVER_INFO::CALLBACK f, void * data)
 {
-nt.SetServer(server);
+return pImpl->Exec<SERVER_INFO::PARSER>("<GetServerInfo/>", f, data);
 }
-//-----------------------------------------------------------------------------
-void SERVCONF::SetPort(uint16_t port)
+
+int SERVCONF::RawXML(const std::string & request, RAW_XML::CALLBACK f, void * data)
 {
-nt.SetServerPort(port);
+return pImpl->RawXML(request, f, data);
 }
-//-----------------------------------------------------------------------------
-void SERVCONF::SetAdmLogin(const char * login)
+
+// -- Admins --
+
+int SERVCONF::GetAdmins(GET_CONTAINER::CALLBACK<GET_ADMIN::INFO>::TYPE f, void * data)
 {
-nt.SetLogin(login);
+return pImpl->Exec<GET_CONTAINER::PARSER<GET_ADMIN::PARSER> >("admins", "<GetAdmins/>", f, data);
 }
-//-----------------------------------------------------------------------------
-void SERVCONF::SetAdmPassword(const char * password)
+
+int SERVCONF::GetAdmin(const std::string & login, GET_ADMIN::CALLBACK f, void * data)
 {
-nt.SetPassword(password);
+return pImpl->Exec<GET_ADMIN::PARSER>("<GetAdmin login=\"" + login + "\"/>", f, data);
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::GetUser(const char * l)
+
+int SERVCONF::ChgAdmin(const ADMIN_CONF_RES & conf, SIMPLE::CALLBACK f, void * data)
 {
-char request[255];
-snprintf(request, 255, "<GetUser login=\"%s\"/>", l);
-int ret;
+return pImpl->Exec<SIMPLE::PARSER>("ChgAdmin", "<ChgAdmin" + CHG_ADMIN::Serialize(conf, pImpl->Encoding()) + "/>", f, data);
+}
 
-currParser = &parserGetUser;
-((PARSER_GET_USER*)currParser)->SetUserDataRecvCb(RecvGetUserDataCb, getUserDataDataCb);
+int SERVCONF::AddAdmin(const std::string & login,
+                       const ADMIN_CONF_RES & conf,
+                       SIMPLE::CALLBACK f, void * data)
+{
+int res = pImpl->Exec<SIMPLE::PARSER>("AddAdmin", "<AddAdmin login=\"" + login + "\"/>", f, data);
+if (res != st_ok)
+    return res;
+return pImpl->Exec<SIMPLE::PARSER>("ChgAdmin", "<ChgAdmin" + CHG_ADMIN::Serialize(conf, pImpl->Encoding()) + "/>", f, data);
+}
 
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+int SERVCONF::DelAdmin(const std::string & login, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("DelAdmin", "<DelAdmin login=\"" + login + "\"/>", f, data);
+}
 
-if ((ret = nt.Connect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
+// -- Tariffs --
 
-return st_ok;
+int SERVCONF::GetTariffs(GET_CONTAINER::CALLBACK<GET_TARIFF::INFO>::TYPE f, void * data)
+{
+return pImpl->Exec<GET_CONTAINER::PARSER<GET_TARIFF::PARSER> >("tariffs", "<GetTariffs/>", f, data);
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::GetUserAuthBy(const char * l)
+
+int SERVCONF::GetTariff(const std::string & name, GET_TARIFF::CALLBACK f, void * data)
 {
-char request[255];
-snprintf(request, 255, "<GetUserAuthBy login=\"%s\"/>", l);
-int ret;
+return pImpl->Exec<GET_TARIFF::PARSER>("<GetTariff name=\"" + name + "\"/>", f, data);
+}
 
-currParser = &parserAuthBy;
-((PARSER_AUTH_BY*)currParser)->SetRecvCb(RecvAuthByCb, getUserAuthByDataCb);
+int SERVCONF::ChgTariff(const TARIFF_DATA_RES & tariffData, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("SetTariff", "<SetTariff name=\"" + tariffData.tariffConf.name.data() + "\">" + CHG_TARIFF::Serialize(tariffData, pImpl->Encoding()) + "</SetTariff>", f, data);
+}
 
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+int SERVCONF::AddTariff(const std::string & name,
+                       const TARIFF_DATA_RES & tariffData,
+                       SIMPLE::CALLBACK f, void * data)
+{
+int res = pImpl->Exec<SIMPLE::PARSER>("AddTariff", "<AddTariff name=\"" + name + "\"/>", f, data);
+if (res != st_ok)
+    return res;
+return pImpl->Exec<SIMPLE::PARSER>("SetTariff", "<SetTariff name=\"" + name + "\">" + CHG_TARIFF::Serialize(tariffData, pImpl->Encoding()) + "</SetTariff>", f, data);
+}
 
-if ((ret = nt.Connect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
+int SERVCONF::DelTariff(const std::string & name, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("DelTariff", "<DelTariff name=\"" + name + "\"/>", f, data);
+}
 
-return st_ok;
+// -- Users --
+
+int SERVCONF::GetUsers(GET_CONTAINER::CALLBACK<GET_USER::INFO>::TYPE f, void * data)
+{
+return pImpl->Exec<GET_CONTAINER::PARSER<GET_USER::PARSER> >("users", "<GetUsers/>", f, data);
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::GetUsers()
+
+int SERVCONF::GetUser(const std::string & login, GET_USER::CALLBACK f, void * data)
 {
-char request[] = "<GetUsers/>";
-int ret;
+return pImpl->Exec<GET_USER::PARSER>("<GetUser login=\"" + login + "\"/>", f, data);
+}
 
-currParser = &parserGetUsers;
-((PARSER_GET_USERS*)currParser)->SetUserDataRecvCb(RecvUserDataCb, getUsersDataDataCb);
+int SERVCONF::ChgUser(const std::string & login,
+                      const USER_CONF_RES & conf,
+                      const USER_STAT_RES & stat,
+                      SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<CHG_USER::PARSER>("<SetUser><Login value=\"" + login + "\"/>" + CHG_USER::Serialize(conf, stat, pImpl->Encoding()) + "</SetUser>", f, data);
+}
 
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+int SERVCONF::DelUser(const std::string & login, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("DelUser", "<DelUser login=\"" + login + "\"/>", f, data);
+}
 
-if ((ret = nt.Connect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
+int SERVCONF::AddUser(const std::string & login,
+                      const USER_CONF_RES & conf,
+                      const USER_STAT_RES & stat,
+                      SIMPLE::CALLBACK f, void * data)
+{
+int res = pImpl->Exec<SIMPLE::PARSER>("AddUser", "<AddUser><Login value=\"" + login + "\"/></AddUser>", f, data);
+if (res != st_ok)
+    return res;
+return pImpl->Exec<CHG_USER::PARSER>("<SetUser><Login value=\"" + login + "\"/>" + CHG_USER::Serialize(conf, stat, pImpl->Encoding()) + "</SetUser>", f, data);
+}
 
-return st_ok;
+int SERVCONF::AuthBy(const std::string & login, AUTH_BY::CALLBACK f, void * data)
+{
+return pImpl->Exec<AUTH_BY::PARSER>("<GetUserAuthBy login=\"" + login + "\"/>", f, data);
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::SendMessage(const char * login, const char * message, int prio)
+
+int SERVCONF::SendMessage(const std::string & login, const std::string & text, SIMPLE::CALLBACK f, void * data)
 {
-char request[1000];
-char msg[500];
-Encode12(msg, message, strlen(message));
-snprintf(request, 1000, "<Message login=\"%s\" priority=\"%d\" text=\"%s\"/>", login, prio, msg);
-int ret;
+return pImpl->Exec<SIMPLE::PARSER>("SendMessageResult", "<Message login=\"" + login + "\" msgver=\"1\" msgtype=\"1\" repeat=\"0\" repeatperiod=\"0\" showtime=\"0\" text=\"" + Encode12str(text) + "\"/>", f, data);
+}
 
-currParser = &parserSendMessage;
-parserSendMessage.SetSendMessageRecvCb(RecvSendMessageCb, sendMessageDataCb);
+int SERVCONF::CheckUser(const std::string & login, const std::string & password, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("CheckUser", "<CheckUser login=\"" + login + "\" password=\"" + password + "\"/>", f, data);
+}
 
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+// -- Services --
 
-if ((ret = nt.Connect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
+int SERVCONF::GetServices(GET_CONTAINER::CALLBACK<GET_SERVICE::INFO>::TYPE f, void * data)
+{
+return pImpl->Exec<GET_CONTAINER::PARSER<GET_SERVICE::PARSER> >("services", "<GetServices/>", f, data);
+}
 
-return st_ok;
+int SERVCONF::GetService(const std::string & name, GET_SERVICE::CALLBACK f, void * data)
+{
+return pImpl->Exec<GET_SERVICE::PARSER>("<GetService name=\"" + name + "\"/>", f, data);
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::GetServerInfo()
+
+int SERVCONF::ChgService(const SERVICE_CONF_RES & conf, SIMPLE::CALLBACK f, void * data)
 {
-char request[] = "<GetServerInfo/>";
-int ret;
+return pImpl->Exec<SIMPLE::PARSER>("SetService", "<SetService " + CHG_SERVICE::Serialize(conf, pImpl->Encoding()) + "/>", f, data);
+}
 
-currParser = &parserServerInfo;
-((PARSER_GET_SERVER_INFO*)currParser)->SetServerInfoRecvCb(RecvServerInfoDataCb, getServerInfoDataCb);
+int SERVCONF::AddService(const std::string & name,
+                         const SERVICE_CONF_RES & conf,
+                         SIMPLE::CALLBACK f, void * data)
+{
+int res = pImpl->Exec<SIMPLE::PARSER>("AddService", "<AddService name=\"" + name + "\"/>", f, data);
+if (res != st_ok)
+    return res;
+return pImpl->Exec<SIMPLE::PARSER>("SetService", "<SetService " + CHG_SERVICE::Serialize(conf, pImpl->Encoding()) + "/>", f, data);
+}
 
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+int SERVCONF::DelService(const std::string & name, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("DelService", "<DelService name=\"" + name + "\"/>", f, data);
+}
 
-if ((ret = nt.Connect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
+// -- Corporations --
 
-return st_ok;
+int SERVCONF::GetCorporations(GET_CONTAINER::CALLBACK<GET_CORP::INFO>::TYPE f, void * data)
+{
+return pImpl->Exec<GET_CONTAINER::PARSER<GET_CORP::PARSER> >("corporations", "<GetCorporations/>", f, data);
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::ChgUser(const char * request)
+
+int SERVCONF::GetCorp(const std::string & name, GET_CORP::CALLBACK f, void * data)
 {
-int ret;
+return pImpl->Exec<GET_CORP::PARSER>("<GetCorp name=\"" + name + "\"/>", f, data);
+}
 
-currParser = &parserChgUser;
-((PARSER_CHG_USER*)currParser)->SetChgUserRecvCb(RecvChgUserCb, chgUserDataCb);
+int SERVCONF::ChgCorp(const CORP_CONF_RES & conf, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("SetCorp", "<SetCorp name=\"" + conf.name.data() + "\">" + CHG_CORP::Serialize(conf, pImpl->Encoding()) + "</SetCorp>", f, data);
+}
 
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+int SERVCONF::AddCorp(const std::string & name,
+                      const CORP_CONF_RES & conf,
+                      SIMPLE::CALLBACK f, void * data)
+{
+int res = pImpl->Exec<SIMPLE::PARSER>("AddCorp", "<AddCorp name=\"" + name + "\"/>", f, data);
+if (res != st_ok)
+    return res;
+return pImpl->Exec<SIMPLE::PARSER>("SetCorp", "<SetCorp name=\"" + name + "\">" + CHG_CORP::Serialize(conf, pImpl->Encoding()) + "</SetCorp>", f, data);
+}
 
-if ((ret = nt.Connect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
+int SERVCONF::DelCorp(const std::string & name, SIMPLE::CALLBACK f, void * data)
+{
+return pImpl->Exec<SIMPLE::PARSER>("DelCorp", "<DelCorp name=\"" + name + "\"/>", f, data);
+}
 
-return st_ok;
+const std::string & SERVCONF::GetStrError() const
+{
+return pImpl->GetStrError();
 }
+
 //-----------------------------------------------------------------------------
-//  TODO: remove this shit!
+SERVCONF::IMPL::IMPL(const std::string & server, uint16_t port,
+                     const std::string & login, const std::string & password)
+    : nt(server, port, login, password)
+{
+setlocale(LC_ALL, "");
+setlocale(LC_NUMERIC, "C");
+encoding = nl_langinfo(CODESET);
+parser = XML_ParserCreate(NULL);
+}
 //-----------------------------------------------------------------------------
-int SERVCONF::MsgUser(const char * request)
+SERVCONF::IMPL::IMPL(const std::string & server, uint16_t port,
+                     const std::string & localAddress, uint16_t localPort,
+                     const std::string & login, const std::string & password)
+    : nt(server, port, localAddress, localPort, login, password)
 {
-int ret;
-
-currParser = &parserSendMessage;
-parserSendMessage.SetSendMessageRecvCb(RecvSendMessageCb, sendMessageDataCb);
-
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
+setlocale(LC_ALL, "");
+setlocale(LC_NUMERIC, "C");
+encoding = nl_langinfo(CODESET);
+parser = XML_ParserCreate(NULL);
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::IMPL::Start(void * data, const char * el, const char ** attr)
+{
+PARSER * currParser = static_cast<PARSER *>(data);
+currParser->ParseStart(el, attr);
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::IMPL::End(void * data, const char * el)
+{
+PARSER * currParser = static_cast<PARSER *>(data);
+currParser->ParseEnd(el);
+}
+//-----------------------------------------------------------------------------
+const std::string & SERVCONF::IMPL::GetStrError() const
+{
+return errorMsg;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::IMPL::ExecImpl(const std::string & request, PARSER & cp)
+{
+XML_ParserReset(parser, NULL);
+XML_SetElementHandler(parser, Start, End);
+XML_SetUserData(parser, &cp);
 
+int ret = 0;
 if ((ret = nt.Connect()) != st_ok)
     {
     errorMsg = nt.GetError();
+    cp.Failure(errorMsg);
     return ret;
     }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
+if ((ret = nt.Transact(request, ParserRecv, this)) != st_ok)
     {
     errorMsg = nt.GetError();
+    cp.Failure(errorMsg);
     return ret;
     }
 
+nt.Disconnect();
 return st_ok;
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::CheckUser(const char * login, const char * password)
-{
-char request[255];
-snprintf(request, 255, "<CheckUser login=\"%s\" password=\"%s\"/>", login, password);
-int ret;
-
-currParser = &parserCheckUser;
-((PARSER_CHECK_USER*)currParser)->SetCheckUserRecvCb(RecvCheckUserCb, checkUserDataCb);
-
-nt.Reset();
-nt.SetRxCallback(this, AnsRecv);
 
+int SERVCONF::IMPL::RawXML(const std::string & request, RAW_XML::CALLBACK callback, void * data)
+{
+int ret = 0;
 if ((ret = nt.Connect()) != st_ok)
     {
     errorMsg = nt.GetError();
+    callback(false, errorMsg, "", data);
     return ret;
     }
-if ((ret = nt.Transact(request)) != st_ok)
-    {
-    errorMsg = nt.GetError();
-    return ret;
-    }
-if ((ret = nt.Disconnect()) != st_ok)
+std::string response;
+if ((ret = nt.Transact(request, SimpleRecv, &response)) != st_ok)
     {
     errorMsg = nt.GetError();
+    callback(false, errorMsg, "", data);
     return ret;
     }
 
+nt.Disconnect();
+callback(true, "", response, data);
 return st_ok;
 }
-//-----------------------------------------------------------------------------
-int SERVCONF::Start(const char *el, const char **attr)
-{
-currParser->ParseStart(el, attr);
-return 0;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::End(const char *el)
-{
-currParser->ParseEnd(el);
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetUserDataRecvCb(RecvUserDataCb_t f, void * data)
-{
-RecvUserDataCb = f;
-getUsersDataDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetGetUserDataRecvCb(RecvUserDataCb_t f, void * data)
-{
-RecvGetUserDataCb = f;            //GET_USER
-getUserDataDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetGetUserAuthByRecvCb(RecvAuthByDataCb_t f, void * data)
-{
-RecvAuthByCb = f;
-getUserAuthByDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetServerInfoRecvCb(RecvServerInfoDataCb_t f, void * data)
-{
-RecvServerInfoDataCb = f;
-getServerInfoDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetChgUserCb(RecvChgUserCb_t f, void * data)
-{
-RecvChgUserCb = f;
-chgUserDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetCheckUserCb(RecvCheckUserCb_t f, void * data)
-{
-RecvCheckUserCb = f;
-checkUserDataCb = data;
-}
-//-----------------------------------------------------------------------------
-void SERVCONF::SetSendMessageCb(RecvSendMessageCb_t f, void * data)
-{
-RecvSendMessageCb = f;
-sendMessageDataCb = data;
-}
-//-----------------------------------------------------------------------------
-const std::string & SERVCONF::GetStrError() const
-{
-return errorMsg;
-}
-//-----------------------------------------------------------------------------
-int SERVCONF::GetError()
-{
-int e = error;
-error = 0;
-return e;
-}
-//-----------------------------------------------------------------------------
diff --git a/stglibs/srvconf.lib/servconf.vpj b/stglibs/srvconf.lib/servconf.vpj
deleted file mode 100644 (file)
index c5f9b3c..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
-<Project
-       Version="10.0"
-       VendorName="SlickEdit"
-       WorkingDir="."
-       BuildSystem="automakefile"
-       BuildMakeFile="makefile">
-       <Config
-               Name="Debug"
-               Type="gnuc"
-               DebugCallbackName="gdb"
-               OutputFile="%bdservconf.a">
-               <Menu>
-                       <Target
-                               Name="Compile"
-                               MenuCaption="&amp;Compile"
-                               OutputExts="*.o"
-                               Dialog="_gnuc_options_form Compile"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               SaveOption="SaveCurrent"
-                               Deletable="0">
-                               <Exec CmdLine='g++ -c %xup -pipe -g -Wall -ggdb -o "%bd%n%oe" %i "%f"'/>
-                       </Target>
-                       <Target
-                               Name="Link"
-                               MenuCaption="&amp;Link"
-                               ShowOnMenu="Never"
-                               Dialog="_gnuc_options_form Link"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               SaveOption="SaveCurrent"
-                               Deletable="0">
-                               <Exec CmdLine='g++ %xup -pipe -g -Wall -o "%o" %f %libs'/>
-                       </Target>
-                       <Target
-                               Name="Build"
-                               MenuCaption="&amp;Build"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               SaveOption="SaveWorkspaceFiles"
-                               Deletable="0">
-                               <Exec CmdLine="gmake -fMakefile"/>
-                       </Target>
-                       <Target
-                               Name="Rebuild"
-                               MenuCaption="&amp;Rebuild"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               Deletable="0">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="Debug"
-                               MenuCaption="&amp;Debug"
-                               RunFromDir="%rw"
-                               Deletable="0">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="Execute"
-                               MenuCaption="E&amp;xecute"
-                               RunFromDir="%rw"
-                               Deletable="0">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="dash"
-                               MenuCaption="-"
-                               RunFromDir="%rw">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="GNU C Options"
-                               MenuCaption="GNU C &amp;Options..."
-                               ShowOnMenu="HideIfNoCmdLine"
-                               Deletable="0">
-                               <Exec
-                                       CmdLine="gnucoptions"
-                                       Type="Slick-C"/>
-                       </Target>
-               </Menu>
-               <Libs>
-                       <Lib File="/usr/lib/libexpat.a"/>
-               </Libs>
-       </Config>
-       <Config
-               Name="Release"
-               Type="gnuc"
-               DebugCallbackName="gdb"
-               OutputFile="%bdservconf.a">
-               <Menu>
-                       <Target
-                               Name="Compile"
-                               MenuCaption="&amp;Compile"
-                               OutputExts="*.o"
-                               Dialog="_gnuc_options_form Compile"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               SaveOption="SaveCurrent"
-                               Deletable="0">
-                               <Exec CmdLine='g++ -c %xup -pipe -Wall -o "%bd%n%oe" %i "%f"'/>
-                       </Target>
-                       <Target
-                               Name="Link"
-                               MenuCaption="&amp;Link"
-                               ShowOnMenu="Never"
-                               Dialog="_gnuc_options_form Link"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               SaveOption="SaveCurrent"
-                               Deletable="0">
-                               <Exec CmdLine='g++ %xup -pipe -Wall -o "%o" %f %libs'/>
-                       </Target>
-                       <Target
-                               Name="Build"
-                               MenuCaption="&amp;Build"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               SaveOption="SaveWorkspaceFiles"
-                               Deletable="0">
-                               <Exec CmdLine="gmake -fMakefile"/>
-                       </Target>
-                       <Target
-                               Name="Rebuild"
-                               MenuCaption="&amp;Rebuild"
-                               RunFromDir="%rw"
-                               CaptureOutputWith="ProcessBuffer"
-                               Deletable="0">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="Debug"
-                               MenuCaption="&amp;Debug"
-                               RunFromDir="%rw"
-                               Deletable="0">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="Execute"
-                               MenuCaption="E&amp;xecute"
-                               RunFromDir="%rw"
-                               Deletable="0">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="dash"
-                               MenuCaption="-"
-                               RunFromDir="%rw">
-                               <Exec/>
-                       </Target>
-                       <Target
-                               Name="GNU C Options"
-                               MenuCaption="GNU C &amp;Options..."
-                               ShowOnMenu="HideIfNoCmdLine"
-                               Deletable="0">
-                               <Exec
-                                       CmdLine="gnucoptions"
-                                       Type="Slick-C"/>
-                       </Target>
-               </Menu>
-               <Libs>
-                       <Lib File="/usr/lib/libexpat.a"/>
-               </Libs>
-       </Config>
-       <Files>
-               <Folder
-                       Name="Source Files"
-                       Filters="*.c;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl">
-                       <F N="netunit.cpp"/>
-                       <F N="parser.cpp"/>
-                       <F N="servconf.cpp"/>
-                       <F N="test.cpp"/>
-               </Folder>
-               <Folder
-                       Name="Header Files"
-                       Filters="*.h;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
-                       <F N="netunit.h"/>
-                       <F N="servconf.h"/>
-               </Folder>
-               <Folder
-                       Name="Resource Files"
-                       Filters="*.ico;*.cur;*.dlg"/>
-               <Folder
-                       Name="Bitmaps"
-                       Filters="*.bmp;*.xpm;*.xbm"/>
-               <Folder
-                       Name="Other Files"
-                       Filters=""/>
-       </Files>
-</Project>
diff --git a/stglibs/srvconf.lib/servconf.vpw b/stglibs/srvconf.lib/servconf.vpw
deleted file mode 100644 (file)
index 96ebe79..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-[Global]
-Version=8
-[ProjectFiles]
-servconf.vpj