]> git.stg.codes - stg.git/commitdiff
Merge branch 'naffanya-dev'
authorMaxim Mamontov <faust.madf@gmail.com>
Sun, 8 Jun 2014 19:06:32 +0000 (22:06 +0300)
committerMaxim Mamontov <faust.madf@gmail.com>
Sun, 8 Jun 2014 19:06:32 +0000 (22:06 +0300)
98 files changed:
include/stg/admin_conf.h
include/stg/array.h [new file with mode: 0644]
include/stg/resetable.h
include/stg/tariff_conf.h
include/stg/user_conf.h
projects/rlm_stg/build
projects/rscriptd/build
projects/sgauth/build
projects/sgconf/Makefile
projects/sgconf/README.txt
projects/sgconf/action.h
projects/sgconf/actions.h
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/build
projects/sgconf/common_sg.cpp [deleted file]
projects/sgconf/common_sg.h [deleted file]
projects/sgconf/config.h
projects/sgconf/corps.cpp [new file with mode: 0644]
projects/sgconf/corps.h [new file with mode: 0644]
projects/sgconf/main.cpp
projects/sgconf/options.cpp
projects/sgconf/options.h
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
projects/sgconf/xml.h
projects/sgconf_xml/build
projects/sgconv/build
projects/stargazer/build
projects/stargazer/plugins/capture/cap_debug/debug_cap.cpp
projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp
projects/stargazer/plugins/capture/cap_nf/cap_nf.h
projects/stargazer/plugins/capture/divert_freebsd/divert_cap.cpp
projects/stargazer/plugins/capture/ether_freebsd/ether_cap.cpp
projects/stargazer/plugins/capture/ether_linux/ether_cap.cpp
projects/stargazer/plugins/capture/ipq_linux/ipq_cap.cpp
projects/stargazer/plugins/capture/nfqueue/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/nfqueue/nfqueue.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/nfqueue/nfqueue.h [new file with mode: 0644]
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/parser.h
projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
stglibs/common.lib/common.cpp
stglibs/common.lib/include/stg/common.h
stglibs/logger.lib/include/stg/logger.h
stglibs/logger.lib/logger.cpp
stglibs/srvconf.lib/include/stg/servconf.h
stglibs/srvconf.lib/include/stg/servconf_types.h
stglibs/srvconf.lib/netunit.cpp
stglibs/srvconf.lib/netunit.h
stglibs/srvconf.lib/parsers/auth_by.cpp
stglibs/srvconf.lib/parsers/auth_by.h
stglibs/srvconf.lib/parsers/base.h
stglibs/srvconf.lib/parsers/chg_admin.cpp
stglibs/srvconf.lib/parsers/chg_admin.h
stglibs/srvconf.lib/parsers/chg_corp.cpp
stglibs/srvconf.lib/parsers/chg_corp.h
stglibs/srvconf.lib/parsers/chg_service.cpp
stglibs/srvconf.lib/parsers/chg_service.h
stglibs/srvconf.lib/parsers/chg_tariff.cpp
stglibs/srvconf.lib/parsers/chg_tariff.h
stglibs/srvconf.lib/parsers/chg_user.cpp
stglibs/srvconf.lib/parsers/chg_user.h
stglibs/srvconf.lib/parsers/get_admin.cpp
stglibs/srvconf.lib/parsers/get_admin.h
stglibs/srvconf.lib/parsers/get_container.h
stglibs/srvconf.lib/parsers/get_corp.cpp
stglibs/srvconf.lib/parsers/get_corp.h
stglibs/srvconf.lib/parsers/get_service.cpp
stglibs/srvconf.lib/parsers/get_service.h
stglibs/srvconf.lib/parsers/get_tariff.cpp
stglibs/srvconf.lib/parsers/get_tariff.h
stglibs/srvconf.lib/parsers/get_user.cpp
stglibs/srvconf.lib/parsers/get_user.h
stglibs/srvconf.lib/parsers/property.cpp
stglibs/srvconf.lib/parsers/property.h
stglibs/srvconf.lib/parsers/resetable_utils.h
stglibs/srvconf.lib/parsers/server_info.cpp
stglibs/srvconf.lib/parsers/server_info.h
stglibs/srvconf.lib/parsers/simple.cpp
stglibs/srvconf.lib/parsers/simple.h
stglibs/srvconf.lib/servconf.cpp

index 8b1a988e1877ff79c77e73bfd404b67e22710583..7fbf44408c72ea45807a8b8f5ae5c1d942df6f6e 100644 (file)
@@ -78,6 +78,7 @@ struct ADMIN_CONF
 //-----------------------------------------------------------------------------
 struct ADMIN_CONF_RES
 {
+    ADMIN_CONF_RES() {}
     ADMIN_CONF_RES(const ADMIN_CONF & conf)
         : priv(conf.priv),
           login(conf.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 c78d02476e5cbea97d9b80acd764a80aad8d1c61..8a6ad27c13584e04ca05c98caae867e97d18699a 100644 (file)
@@ -42,6 +42,14 @@ public:
     const T & data() const throw() { return value; }
     bool empty() const throw() { return !is_set; }
     void reset() throw() { is_set = false; }
+    void splice(const RESETABLE<T> & rhs)
+    {
+        if (rhs.is_set)
+        {
+            value = rhs.value;
+            is_set = true;
+        }
+    }
 
 private:
     value_type value;
index 6a296230d8413e3b148d3969ffc69992fb115ae2..fc9807beb88fc13763b1f597a2b7f5e8446f247c 100644 (file)
@@ -121,6 +121,21 @@ struct DIRPRICE_DATA_RES
         return dd;
         }
 
+    void Splice(const DIRPRICE_DATA_RES & rhs)
+        {
+        hDay.splice(rhs.hDay);
+        mDay.splice(rhs.mDay);
+        hNight.splice(rhs.hNight);
+        mNight.splice(rhs.mNight);
+        priceDayA.splice(rhs.priceDayA);
+        priceNightA.splice(rhs.priceNightA);
+        priceDayB.splice(rhs.priceDayB);
+        priceNightB.splice(rhs.priceNightB);
+        threshold.splice(rhs.threshold);
+        singlePrice.splice(rhs.singlePrice);
+        noDiscount.splice(rhs.noDiscount);
+        }
+
     RESETABLE<int>    hDay;
     RESETABLE<int>    mDay;
     RESETABLE<int>    hNight;
index 5d65fcee9f606dc053b66a3f66b53bd173b14a43..fe458211b2ef69c8f8e8ca50f63756b95d205e1c 100644 (file)
@@ -30,7 +30,7 @@ struct USER_CONF
           note(),
           realName(),
           corp(),
-          service(),
+          services(),
           group(),
           credit(0),
           nextTariff(),
@@ -51,7 +51,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;
@@ -74,10 +74,12 @@ struct USER_CONF_RES
           email(),
           note(),
           realName(),
+          corp(),
           group(),
           credit(),
           nextTariff(),
           userdata(USERDATA_NUM),
+          services(),
           creditExpire(),
           ips()
     {
@@ -97,10 +99,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 (size_t i = 0; i < USERDATA_NUM; i++) userdata[i]  = uc.userdata[i];
+        services     = uc.services;
         creditExpire = uc.creditExpire;
         ips          = uc.ips;
         return *this;
@@ -119,13 +123,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;
@@ -143,10 +149,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 6459cdb9e4f5e3fc049fada62d5bfba6e8f13b0a..b93f30bd4d6b929d104dddcefcd003b34807b9bf 100755 (executable)
@@ -44,15 +44,13 @@ then
         5) OS=bsd5;;
         6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     MAKE="gmake"
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but rlm_stg currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #\n"
     printf "#############################################################################\n"
index 626819323b7b41ac21a1c075f08d050a4d7b9b86..5746d8226b86b89be2c8379e3bfbbbcfce218756 100755 (executable)
@@ -46,15 +46,13 @@ then
         5) OS=bsd5;;
         6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     MAKE="gmake"
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but rscriptd currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #\n"
     printf "#############################################################################\n"
@@ -65,12 +63,12 @@ printf "########################################################################
 printf "       Building rscriptd for $sys $release\n"
 printf "#############################################################################\n"
 
-STG_LIBS="logger.lib 
+STG_LIBS="logger.lib
           locker.lib
-         crypto.lib 
-         common.lib 
-         scriptexecuter.lib 
-         conffiles.lib"
+          crypto.lib
+          common.lib
+          scriptexecuter.lib
+          conffiles.lib"
 
 if [ "$OS" = "linux" ]
 then
index 203e0c889c261162dabaf41fffd80d8aaec6e4e4..82a3dcf6f014ec8b4d9e5c7863fbd0eaf4ccd913 100755 (executable)
@@ -46,15 +46,13 @@ then
         5) OS=bsd5;;
         6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     MAKE="gmake"
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but sgauth currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #\n"
     printf "#############################################################################\n"
@@ -65,10 +63,10 @@ printf "########################################################################
 printf "       Building sgauth for $sys $release\n"
 printf "#############################################################################\n"
 
-STG_LIBS="crypto.lib 
-         common.lib 
-         conffiles.lib
-         ia.lib"
+STG_LIBS="crypto.lib
+          common.lib
+          conffiles.lib
+          ia.lib"
 
 if [ "$OS" = "linux" ]
 then
index e564b246126d83591a34b6949cdaf87f00aaacba..52a70ae8fdc49d569985f02500cc188c2d36c2e0 100644 (file)
@@ -7,14 +7,18 @@ include ../../Makefile.conf
 PROG = sgconf
 
 SRCS = ./main.cpp \
-       ./common_sg.cpp \
        ./options.cpp \
+       ./api_action.cpp \
        ./actions.cpp \
+       ./admins.cpp \
+       ./tariffs.cpp \
+       ./users.cpp \
+       ./services.cpp \
+       ./corps.cpp \
        ./xml.cpp
 
-STGLIBS = conffiles \
-          srvconf \
-         crypto \
+STGLIBS = srvconf \
+          crypto \
           common
 
 STGLIBS_INCS = $(addprefix -I ../../stglibs/,$(addsuffix .lib/include,$(STGLIBS)))
@@ -25,7 +29,7 @@ LIBS += $(addprefix -lstg,$(STGLIBS)) -lexpat $(LIB_THREAD)
 ifeq ($(OS),linux)
 else
 LIBS += -lc \
-       -liconv
+        -liconv
 endif
 
 SEARCH_DIRS = -I ../../include
@@ -60,11 +64,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
@@ -94,7 +94,7 @@ endif
 endif
 endif
 
-deps:  $(SRCS) ../../Makefile.conf
+deps: $(SRCS) ../../Makefile.conf
        $(MAKE) -C $(DIR_LIBSRC)
        @>deps ;\
        for file in $(SRCS); do\
index cbdf9acae4bb76a4e1fa8d4daf92ce8baa9716b6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-Compiling:
-> ./build
-
index 0c1b4f92a57aed3e70ad0acf663c22463a25c281..940ea7f6272673bad87ab08aa12819e8e86a602f 100644 (file)
@@ -22,6 +22,7 @@
 #define __STG_SGCONF_ACTION_H__
 
 #include <string>
+#include <map>
 #include <stdexcept>
 
 namespace SGCONF
@@ -29,6 +30,7 @@ namespace SGCONF
 
 class OPTION_BLOCK;
 struct PARSER_STATE;
+struct CONFIG;
 
 class ACTION
 {
@@ -39,7 +41,7 @@ class ACTION
         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) = 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
index 33a11347a27fb7a3143380f5dda1a8f3d08435c5..07bcfb8b22b19c58f803d03e8c8d85a53975a31a 100644 (file)
@@ -30,6 +30,8 @@
 
 #include <string>
 
+#include <cassert>
+
 namespace SGCONF
 {
 
@@ -46,7 +48,7 @@ class FUNC0_ACTION : public ACTION
         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)
+        virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/)
         {
         m_func();
         return PARSER_STATE(true, argc, argv);
@@ -88,7 +90,7 @@ class PARAM_ACTION : public ACTION
         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);
+        virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
         virtual void ParseValue(const std::string & value);
 
     private:
@@ -117,7 +119,7 @@ return m_hasDefault ? " (default: '" + m_defaltValue + "')"
 
 template <typename T>
 inline
-PARSER_STATE PARAM_ACTION<T>::Parse(int argc, char ** argv)
+PARSER_STATE PARAM_ACTION<T>::Parse(int argc, char ** argv, void * /*data*/)
 {
 if (argc == 0 ||
     argv == NULL ||
@@ -151,7 +153,7 @@ m_param = stringValue;
 
 template <>
 inline
-PARSER_STATE PARAM_ACTION<std::string>::Parse(int argc, char ** argv)
+PARSER_STATE PARAM_ACTION<std::string>::Parse(int argc, char ** argv, void * /*data*/)
 {
 if (argc == 0 ||
     argv == NULL ||
@@ -178,6 +180,48 @@ PARAM_ACTION<T> * MakeParamAction(RESETABLE<T> & param,
 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
index 62fceb2314f19a2c42aab73acbcb778d45cbc429..8431474d522d9ecfc3e4a64fb63c91c3eca203be 100755 (executable)
@@ -46,9 +46,7 @@ then
         5) OS=bsd5;;
         6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     MAKE="gmake"
 fi
@@ -61,7 +59,7 @@ then
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but sgconf currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #\n"
     printf "#############################################################################\n"
@@ -73,9 +71,9 @@ printf "       Building sgconf for $sys $release\n"
 printf "#############################################################################\n"
 
 STG_LIBS="conffiles.lib
-         crypto.lib 
-         common.lib 
-         srvconf.lib"
+          crypto.lib
+          common.lib
+          srvconf.lib"
 
 if [ "$OS" = "linux" ]
 then
diff --git a/projects/sgconf/common_sg.cpp b/projects/sgconf/common_sg.cpp
deleted file mode 100644 (file)
index e407a71..0000000
+++ /dev/null
@@ -1,536 +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 "sg_error_codes.h"
-#include "common_sg.h"
-#include "version_sg.h"
-
-#include "stg/common.h"
-
-#include <iostream>
-#include <vector>
-
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-#include <cerrno>
-#include <clocale>
-
-#include <langinfo.h>
-#include <iconv.h>
-
-using namespace STG;
-
-const int usageConf = 0;
-const int usageInfo = 1;
-
-const int TO_KOI8 = 0;
-const int FROM_KOI8 = 1;
-//-----------------------------------------------------------------------------
-struct ResultData
-{
-    bool result;
-    std::string reason;
-};
-//-----------------------------------------------------------------------------
-struct GetUserData
-{
-    GetUserData(REQUEST & req, bool res) : request(req), result(res) {}
-    REQUEST & request;
-    bool result;
-    std::string reason;
-};
-//---------------------------------------------------------------------------
-struct HelpParams
-{
-    std::string setActionName;
-    std::string getActionName;
-    std::string valueName;
-    std::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("Incorrect server port %s\n", p);
-    exit(NETWORK_ERR_CODE);
-    }
-return (short)port;
-}
-//-----------------------------------------------------------------------------
-char * ParseAdminLogin(char * adm)
-{
-if (CheckLogin(adm))
-    {
-    printf("Incorrect 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("Incorrect user login %s\n", usr);
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-return usr;
-}
-//-----------------------------------------------------------------------------
-void ConvertKOI8(const std::string & src, std::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(FREE_BSD) || defined(FREE_BSD5)
-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 std::string & src, std::string * dst)
-{
-ConvertKOI8(src, dst, FROM_KOI8);
-}
-//-----------------------------------------------------------------------------
-void ResultCallback(bool result, const std::string & reason, void * d)
-{
-ResultData * data = static_cast<ResultData *>(d);
-data->result = result;
-data->reason = reason;
-}
-//-----------------------------------------------------------------------------
-void RecvAuthByData(bool result, const std::string & reason,
-                    const AUTH_BY::INFO & list, void * d)
-{
-ResultData * data = static_cast<ResultData *>(d);
-data->result = result;
-data->reason = reason;
-
-if (!result)
-    return;
-
-for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
-    std::cout << *it << "\n";
-
-std::cout << std::endl;
-}
-//-----------------------------------------------------------------------------
-struct StringReqParams
-{
-    std::string name;
-    RESETABLE<std::string> reqParam;
-    const std::string * value;
-};
-//-----------------------------------------------------------------------------
-void GetUserCallback(bool result, const std::string& reason, const GET_USER::INFO & info, void * d)
-{
-GetUserData * data = static_cast<GetUserData *>(d);
-data->result = false;
-data->reason = reason;
-
-if (!result)
-    return;
-
-if (info.login == "")
-    {
-    data->result = false;
-    data->reason = "Invalid login.";
-    return;
-    }
-
-if (!data->request.cash.empty())
-    cout << "cash = " << info.cash << endl;
-
-if (!data->request.credit.empty())
-    cout << "credit = " << info.credit << endl;
-
-if (!data->request.creditExpire.empty())
-    {
-    char buf[32];
-    struct tm brokenTime;
-    time_t tt = info.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 (!data->request.down.empty())
-    cout << "down = " << info.down << endl;
-
-if (!data->request.passive.empty())
-    cout << "passive = " << info.passive << endl;
-
-if (!data->request.disableDetailStat.empty())
-    cout << "disableDetailStat = " << info.disableDetailStat << endl;
-
-if (!data->request.alwaysOnline.empty())
-    cout << "alwaysOnline = " << info.alwaysOnline << endl;
-
-if (!data->request.prepaidTraff.empty())
-    cout << "prepaidTraff = " << info.prepaidTraff << endl;
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (!data->request.sessionUpload[i].empty())
-        cout << "session upload for dir " << i << " = " << info.stat.su[i] << endl;
-    if (!data->request.sessionDownload[i].empty())
-        cout << "session download for dir " << i << "=" << info.stat.sd[i] << endl;
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (!data->request.monthUpload[i].empty())
-        cout << "month upload for dir " << i << " = " << info.stat.mu[i] << endl;
-    if (!data->request.monthDownload[i].empty())
-        cout << "month download for dir " << i << " = " << info.stat.md[i] << endl;
-    }
-
-for (int i = 0; i < USERDATA_NUM; i++)
-    {
-    if (!data->request.userData[i].empty())
-        {
-        std::string str;
-        ConvertFromKOI8(info.userData[i], &str);
-        cout << "user data " << i << " = " << str << endl;
-        }
-    }
-
-StringReqParams strReqParams[] =
-{
-    {"note",     data->request.note,        &info.note},
-    {"name",     data->request.name,        &info.name},
-    {"address",  data->request.address,     &info.address},
-    {"email",    data->request.email,       &info.email},
-    {"phone",    data->request.phone,       &info.phone},
-    {"group",    data->request.group,       &info.group},
-    {"tariff",   data->request.tariff,      &info.tariff},
-    {"password", data->request.usrPasswd,   &info.password},
-    {"ip",       data->request.ips,         &info.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;
-        }
-    }
-data->result = true;
-}
-//-----------------------------------------------------------------------------
-bool ProcessSetUser(const std::string & server,
-                    int port,
-                    const std::string & login,
-                    const std::string & password,
-                    const std::string & user,
-                    const USER_CONF_RES & conf,
-                    const USER_STAT_RES & stat)
-{
-SERVCONF sc(server, port, login, password);
-
-ResultData data;
-int res = sc.ChgUser(user, conf, stat, ResultCallback, &data);
-
-if (res == st_ok && data.result)
-    {
-    printf("Ok\n");
-    return false;
-    }
-
-printf("Error\n");
-if (res != st_ok)
-    printf("%s\n", sc.GetStrError().c_str());
-else
-    printf("%s\n", data.reason.c_str());
-return true;
-}
-//-----------------------------------------------------------------------------
-bool ProcessSendMessage(const std::string & server, uint16_t port,
-                        const std::string & login, const std::string & password,
-                        const std::string & user, const std::string & text)
-{
-SERVCONF sc(server, port, login, password);
-
-ResultData data;
-int res = sc.SendMessage(user, text, ResultCallback, &data);
-
-if (res == st_ok && data.result)
-    {
-    printf("Ok\n");
-    return true;
-    }
-
-printf("Error\n");
-if (res != st_ok)
-    printf("%s\n", sc.GetStrError().c_str());
-else
-    printf("%s\n", data.reason.c_str());
-return false;
-}
-//-----------------------------------------------------------------------------
-bool ProcessGetUser(const std::string &server,
-                    int port,
-                    const std::string &admLogin,
-                    const std::string &admPasswd,
-                    const std::string &login,
-                    REQUEST & request)
-{
-SERVCONF sc(server, port, admLogin, admPasswd);
-
-GetUserData data(request, false);
-bool res = (sc.GetUser(login.c_str(), GetUserCallback, &data) == st_ok);
-
-if (res && data.result)
-    {
-    printf("Ok\n");
-    return true;
-    }
-
-printf("Error\n");
-if (!res)
-    printf("%s\n", sc.GetStrError().c_str());
-else
-    printf("%s\n", data.reason.c_str());
-return false;
-}
-//-----------------------------------------------------------------------------
-bool ProcessAuthBy(const std::string &server,
-                   int port,
-                   const std::string &admLogin,
-                   const std::string &admPasswd,
-                   const std::string &login)
-{
-SERVCONF sc(server, port, admLogin, admPasswd);
-
-ResultData data;
-bool res = (sc.AuthBy(login.c_str(), RecvAuthByData, &data) == st_ok);
-
-if (res && data.result)
-    {
-    printf("Ok\n");
-    return true;
-    }
-
-printf("Error\n");
-if (!res)
-    printf("%s\n", sc.GetStrError().c_str());
-else
-    printf("%s\n", data.reason.c_str());
-return false;
-}
-//-----------------------------------------------------------------------------
diff --git a/projects/sgconf/common_sg.h b/projects/sgconf/common_sg.h
deleted file mode 100644 (file)
index 323a8cf..0000000
+++ /dev/null
@@ -1,77 +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 "stg/servconf.h"
-#include "stg/servconf_types.h"
-#include "request.h"
-
-#include <string>
-
-struct USER_CONF_RES;
-struct USER_STAT_RES;
-
-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);
-
-bool ProcessGetUser(const std::string & server,
-                    int port,
-                    const std::string & admLogin,
-                    const std::string & admPasswd,
-                    const std::string & login,
-                    REQUEST & request);
-
-bool ProcessAuthBy(const std::string & server,
-                   int port,
-                   const std::string & admLogin,
-                   const std::string & admPasswd,
-                   const std::string & login);
-
-bool ProcessSetUser(const std::string & server,
-                    int port,
-                    const std::string & admLogin,
-                    const std::string & admPasswd,
-                    const std::string & user,
-                    const USER_CONF_RES & conf,
-                    const USER_STAT_RES & stat);
-
-bool ProcessSendMessage(const std::string & server, uint16_t port,
-                        const std::string & login, const std::string & password,
-                        const std::string & user, const std::string & text);
-
-#endif
index 9ec9616eabebfc11ad40f6e5d8d30f0853fcf030..e52111e3fcd9eac231bd54ed335974609469aede 100644 (file)
@@ -35,6 +35,8 @@ 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;
 
@@ -46,6 +48,10 @@ struct CONFIG
         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())
@@ -57,19 +63,23 @@ struct CONFIG
     {
     std::string res("{ ");
     if (!configFile.empty())
-        res += "configFile: '" + configFile.data() + "'";
+        res += "configFile: '" + configFile.data() + "',";
     if (!server.empty())
-        res += ", server: '" + server.data() + "'";
+        res += " server: '" + server.data() + "',";
     if (!port.empty())
-        res += ", port: " + x2str(port.data());
+        res += " port: " + x2str(port.data()) + ",";
+    if (!localAddress.empty())
+        res += " local address: '" + localAddress.data() + "',";
+    if (!localPort.empty())
+        res += " local port: " + x2str(localPort.data()) + ",";
     if (!userName.empty())
-        res += ", userName: '" + userName.data() + "'";
+        res += " userName: '" + userName.data() + "',";
     if (!userPass.empty())
-        res += ", userPass: '" + userPass.data() + "'";
+        res += " userPass: '" + userPass.data() + "'";
     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
index 9025602e541288294bc25bf7d7880f2befb5f3b8..a93233f2bd1469be8073e7401d1b7fa3569dcadf 100644 (file)
  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
  */
 
-#include "request.h"
-#include "common_sg.h"
-#include "sg_error_codes.h"
-
 #include "xml.h"
+#include "admins.h"
+#include "tariffs.h"
+#include "users.h"
+#include "services.h"
+#include "corps.h"
+
+#include "api_action.h"
 #include "options.h"
 #include "actions.h"
 #include "config.h"
 
-#include "stg/user_conf.h"
-#include "stg/user_stat.h"
-#include "stg/common.h"
-
-#include <cerrno>
-#include <clocale>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
 #include <string>
-#include <sstream>
+#include <iostream>
 
-#include <unistd.h>
-#include <getopt.h>
-#include <iconv.h>
-#include <langinfo.h>
+#include <cstdlib> // getenv
+#include <cstring> // str*
 
-namespace
-{
-
-template <typename T>
-struct ARRAY_TYPE
-{
-typedef typename T::value_type type;
-};
-
-template <typename T>
-struct ARRAY_TYPE<T[]>
-{
-typedef T type;
-};
+#include <unistd.h> // access
+#include <libgen.h> // basename
 
-template <typename T, size_t N>
-struct ARRAY_TYPE<T[N]>
+namespace
 {
-typedef T type;
-};
 
 template <typename T>
 struct nullary_function
@@ -91,6 +68,16 @@ binder0<F> bind0(const F & func, const typename F::argument_type & arg)
 return binder0<F>(func, arg);
 }
 
+template <typename A, typename R>
+class FUNC1_ADAPTER : public std::unary_function<A, R>
+{
+    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>
 {
@@ -113,6 +100,12 @@ class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
         C & m_obj;
 };
 
+template <typename A, typename R>
+FUNC1_ADAPTER<A, R> Func1Adapt(R (func)(A))
+{
+return FUNC1_ADAPTER<A, R>(func);
+}
+
 template <typename C, typename A, typename R>
 METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
 {
@@ -125,38 +118,11 @@ CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
 return CONST_METHOD1_ADAPTER<C, A, R>(func, obj);
 }
 
-template <typename T>
-bool SetArrayItem(T & array, const char * index, const typename ARRAY_TYPE<T>::type & value)
-{
-size_t pos = 0;
-if (str2x(index, pos))
-    return false;
-array[pos] = value;
-return true;
-}
-
-void RawXMLCallback(bool result, const std::string & reason, const std::string & response, void * data)
+void Version(const std::string & self)
 {
-if (!result)
-    {
-    std::cerr << "Failed to get raw XML response. Reason: '" << reason << "'." << std::endl;
-    return;
-    }
-PrintXML(response);
+std::cout << self << ", version: 2.0.0-alpha.\n";
 }
 
-void Usage();
-void UsageAll();
-void UsageImpl(bool full);
-void UsageConnection();
-void UsageAdmins(bool full);
-void UsageTariffs(bool full);
-void UsageUsers(bool full);
-void UsageServices(bool full);
-void UsageCorporations(bool full);
-
-void Version();
-
 void ReadUserConfigFile(SGCONF::OPTION_BLOCK & block)
 {
 std::vector<std::string> paths;
@@ -187,7 +153,7 @@ namespace SGCONF
 class CONFIG_ACTION : public ACTION
 {
     public:
-        CONFIG_ACTION(CONFIG & config,
+        CONFIG_ACTION(SGCONF::CONFIG & config,
                       const std::string & paramDescription)
             : m_config(config),
               m_description(paramDescription)
@@ -198,10 +164,10 @@ class CONFIG_ACTION : public ACTION
         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);
+        virtual PARSER_STATE Parse(int argc, char ** argv, void * /*data*/);
 
     private:
-        CONFIG & m_config;
+        SGCONF::CONFIG & m_config;
         std::string m_description;
         OPTION_BLOCK m_suboptions;
 
@@ -209,67 +175,8 @@ class CONFIG_ACTION : public ACTION
         void ParseHostAndPort(const std::string & hostAndPort);
 };
 
-class COMMAND_FUNCTOR
-{
-    public:
-        virtual ~COMMAND_FUNCTOR() {}
-        virtual bool operator()(const std::string& arg, const std::map<std::string, std::string>& options) = 0;
-};
-
-class COMMAND_ACTION : public ACTION
-{
-    public:
-        COMMAND_ACTION(CONFIG & config,
-                       const std::string & paramDescription,
-                       bool needArgument,
-                       const OPTION_BLOCK& suboptions,
-                       COMMAND_FUNCTOR* funPtr)
-            : m_config(config),
-              m_description(paramDescription),
-              m_argument(needArgument),
-              m_suboptions(suboptions),
-              m_funPtr(funPtr)
-        {}
-
-        virtual ACTION * Clone() const { return new COMMAND_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)
-        {
-        PARSER_STATE state(false, argc, argv);
-        if (m_argument)
-            {
-            if (argc == 0 ||
-                argv == NULL ||
-                *argv == NULL)
-                throw ERROR("Missing argument.");
-            m_argument = *argv;
-            --state.argc;
-            ++state.argv;
-            }
-        std::list<OPTION_BLOCK>::iterator it(m_suboptions.begin());
-        while (!state.stop && it != m_suboptions.end())
-            {
-            state = it->Parse(state.argc, state.argv);
-            ++it;
-            }
-        m_funPtr(m_argument, m_params);
-        return state;
-        }
 
-    private:
-        CONFIG & m_config;
-        std::string m_description;
-        bool m_needArgument;
-        std::string m_argument;
-        OPTION_BLOCK m_suboptions;
-        std::map<std::string, std::string> m_params;
-        COMMAND_FUNCTOR* m_funPtr;
-};
-
-PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv)
+PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv, void * /*data*/)
 {
 if (argc == 0 ||
     argv == NULL ||
@@ -320,7 +227,7 @@ else
 }
 
 inline
-CONFIG_ACTION * MakeParamAction(CONFIG & config,
+CONFIG_ACTION * MakeParamAction(SGCONF::CONFIG & config,
                                 const std::string & paramDescription)
 {
 return new CONFIG_ACTION(config, paramDescription);
@@ -328,997 +235,33 @@ return new CONFIG_ACTION(config, paramDescription);
 
 } // namespace SGCONF
 
-time_t stgTime;
-
-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
-{"session-upload",   1, 0, 500},  //SU0
-{"session-download", 1, 0, 501},  //SD0
-{"month-upload",     1, 0, 502},  //MU0
-{"month-download",   1, 0, 503},  //MD0
-
-{"user-data",   1, 0, 700},  //UserData0
-
-{"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}};
-
-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
-{"session-upload",   1, 0, 500},  //U0
-{"session-download", 1, 0, 501},  //U1
-{"month-upload",     1, 0, 502},  //U2
-{"month-download",   1, 0, 503},  //U3
-
-{"user-data",        1, 0, 700},  //UserData
-
-{"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}};
-
-//-----------------------------------------------------------------------------
-CASH_INFO ParseCash(const char * str)
-{
-//-c 123.45:log message
-std::string cashString;
-std::string message;
-const char * pos = strchr(str, ':');
-if (pos != NULL)
-    {
-    cashString.append(str, pos);
-    message.append(pos + 1);
-    }
-else
-    cashString = str;
-
-double cash = 0;
-if (strtodouble2(cashString, cash) != 0)
-    {
-    printf("Incorrect cash value %s\n", str);
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-
-return CASH_INFO(cash, message);
-}
-//-----------------------------------------------------------------------------
-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';
-}
-//-----------------------------------------------------------------------------
-void ParseTariff(const char * str, RESETABLE<std::string> & tariffName, RESETABLE<std::string> & nextTariff)
-{
-const char * pos = strchr(str, ':');
-if (pos != NULL)
-    {
-    std::string tariff(str, pos);
-    if (strcmp(pos + 1, "now") == 0)
-        tariffName = tariff;
-    else if (strcmp(pos + 1, "delayed") == 0)
-        nextTariff = tariff;
-    else
-        {
-        printf("Incorrect tariff value '%s'. Should be '<tariff>', '<tariff>:now' or '<tariff>:delayed'.\n", str);
-        exit(PARAMETER_PARSING_ERR_CODE);
-        }
-    }
-else
-    tariffName = str;
-}
-//-----------------------------------------------------------------------------
-time_t ParseCreditExpire(const char * str)
-{
-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)
-{
-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;
-
-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);
-    }
-
-#if defined(FREE_BSD) || defined(FREE_BSD5)
-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)
-        {
-        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.empty())
-    {
-    string msg;
-    Encode12str(msg, req->usrMsg.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);
-    }
-
-if (!req->prepaidTraff.empty())
-    {
-    sprintf(str, "<FreeMb value=\"%f\"/>\n", req->prepaidTraff.const_data());
-    strcat(r, str);
-    }
-
-if (!req->cash.empty())
-    {
-    string msg;
-    Encode12str(msg, req->message);
-    sprintf(str, "<cash add=\"%f\" msg=\"%s\"/>\n", req->cash.const_data(), msg.c_str());
-    strcat(r, str);
-    }
-
-if (!req->setCash.empty())
-    {
-    string msg;
-    Encode12str(msg, req->message);
-    sprintf(str, "<cash set=\"%f\" msg=\"%s\"/>\n", req->setCash.const_data(), msg.c_str());
-    strcat(r, str);
-    }
-
-if (!req->usrPasswd.empty())
-    {
-    sprintf(str, "<password value=\"%s\" />\n", req->usrPasswd.const_data().c_str());
-    strcat(r, str);
-    }
-
-if (!req->down.empty())
-    {
-    sprintf(str, "<down value=\"%d\" />\n", req->down.const_data());
-    strcat(r, str);
-    }
-
-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())
-    {
-    sprintf(str, "<aonline value=\"%d\" />\n", req->alwaysOnline.const_data());
-    strcat(r, str);
-    }
-
-// IP-address of user
-if (!req->ips.empty())
-    {
-    sprintf(str, "<ip value=\"%s\" />\n", req->ips.const_data().c_str());
-    strcat(r, str);
-    }
-
-int uPresent = false;
-int dPresent = false;
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (!req->monthUpload[i].empty())
-        {
-        if (!uPresent && !dPresent)
-            {
-            sprintf(str, "<traff ");
-            strcat(r, str);
-            uPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->monthUpload[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->monthDownload[i].empty())
-        {
-        if (!uPresent && !dPresent)
-            {
-            sprintf(str, "<traff ");
-            strcat(r, str);
-            dPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->monthDownload[i].const_data();
-        sprintf(str, "MD%d=\"%s\" ", i, ss.str().c_str());
-        strcat(r, str);
-        }
-    if (!req->sessionUpload[i].empty())
-        {
-        if (!uPresent && !dPresent)
-            {
-            sprintf(str, "<traff ");
-            strcat(r, str);
-            uPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->sessionUpload[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->sessionDownload[i].empty())
-        {
-        if (!uPresent && !dPresent)
-            {
-            sprintf(str, "<traff ");
-            strcat(r, str);
-            dPresent = true;
-            }
-
-        stringstream ss;
-        ss << req->sessionDownload[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.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.empty())
-    {
-    string note;
-    Encode12str(note, req->note.data());
-    sprintf(str, "<note value=\"%s\"/>", note.c_str());
-    strcat(r, str);
-    }
-
-if (!req->name.empty())
-    {
-    string name;
-    Encode12str(name, req->name.data());
-    sprintf(str, "<name value=\"%s\"/>", name.c_str());
-    strcat(r, str);
-    }
-
-if (!req->address.empty())
-    {
-    string address;
-    Encode12str(address, req->address.data());
-    sprintf(str, "<address value=\"%s\"/>", address.c_str());
-    strcat(r, str);
-    }
-
-if (!req->email.empty())
-    {
-    string email;
-    Encode12str(email, req->email.data());
-    sprintf(str, "<email value=\"%s\"/>", email.c_str());
-    strcat(r, str);
-    }
-
-if (!req->phone.empty())
-    {
-    string phone;
-    Encode12str(phone, req->phone.data());
-    sprintf(str, "<phone value=\"%s\"/>", phone.c_str());
-    strcat(r, str);
-    }
-
-if (!req->group.empty())
-    {
-    string group;
-    Encode12str(group, req->group.data());
-    sprintf(str, "<group value=\"%s\"/>", group.c_str());
-    strcat(r, str);
-    }
-
-for (int i = 0; i < USERDATA_NUM; i++)
-    {
-    if (!req->userData[i].empty())
-        {
-        string ud;
-        Encode12str(ud, req->userData[i].data());
-        sprintf(str, "<userdata%d value=\"%s\"/>", i, ud.c_str());
-        strcat(r, str);
-        }
-    }
-
-strcat(r, "</SetUser>\n");
-}
-//-----------------------------------------------------------------------------
-int CheckParameters(REQUEST * req)
-{
-bool su = false;
-bool sd = false;
-bool mu = false;
-bool md = false;
-bool ud = false;
-bool a = !req->admLogin.empty()
-    && !req->admPasswd.empty()
-    && !req->server.empty()
-    && !req->port.empty()
-    && !req->login.empty();
-
-bool 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;
-
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->sessionUpload[i].empty())
-        {
-        su = true;
-        break;
-        }
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->sessionDownload[i].empty())
-        {
-        sd = true;
-        break;
-        }
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->monthUpload[i].empty())
-        {
-        mu = true;
-        break;
-        }
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->monthDownload[i].empty())
-        {
-        md = true;
-        break;
-        }
-    }
-
-for (int i = 0; i < DIR_NUM; i++)
-    {
-    if (req->userData[i].empty())
-        {
-        ud = true;
-        break;
-        }
-    }
-
-
-//printf("a=%d, b=%d, u=%d, d=%d ud=%d\n", a, b, u, d, ud);
-return a && (b || su || sd || mu || md || ud);
-}
-//-----------------------------------------------------------------------------
-int CheckParametersGet(REQUEST * req)
-{
-return CheckParameters(req);
-}
-//-----------------------------------------------------------------------------
-int CheckParametersSet(REQUEST * req)
-{
-return CheckParameters(req);
-}
-//-----------------------------------------------------------------------------
-bool 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
-            SetArrayItem(req.sessionUpload, optarg, 1);
-            //req.sessionUpload[optarg] = 1;
-            break;
-        case 501:
-            SetArrayItem(req.sessionDownload, optarg, 1);
-            //req.sessionDownload[optarg] = 1;
-            break;
-        case 502:
-            SetArrayItem(req.monthUpload, optarg, 1);
-            //req.monthUpload[optarg] = 1;
-            break;
-        case 503:
-            SetArrayItem(req.monthDownload, optarg, 1);
-            //req.monthDownload[optarg] = 1;
-            break;
-
-        case 700: //UserData
-            SetArrayItem(req.userData, optarg, std::string(" "));
-            //req.userData[optarg] = " ";
-            break;
-
-        case 800:
-            req.authBy = true;
-            break;
-
-        case '?':
-        case ':':
-            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);
-    }
-
-if (req.authBy)
-    return ProcessAuthBy(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data());
-else
-    return ProcessGetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), req);
-}
-//-----------------------------------------------------------------------------
-bool mainSet(int argc, char **argv)
-{
-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;
-
-USER_CONF_RES conf;
-USER_STAT_RES stat;
-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
-            conf.password = ParsePassword(optarg);
-            break;
-
-        case 'u': //user
-            req.login = ParseUser(optarg);
-            break;
-
-        case 'c': //add cash
-            stat.cashAdd = ParseCash(optarg);
-            break;
-
-        case 'v': //set cash
-            stat.cashSet = ParseCash(optarg);
-            break;
-
-        case 'r': //credit
-            conf.credit = ParseCredit(optarg);
-            break;
-
-        case 'E': //credit expire
-            conf.creditExpire = ParseCreditExpire(optarg);
-            break;
-
-        case 'd': //down
-            conf.disabled = ParseDownPassive(optarg);
-            break;
-
-        case 'i': //passive
-            conf.passive = ParseDownPassive(optarg);
-            break;
-
-        case 't': //tariff
-            ParseTariff(optarg, conf.tariffName, conf.nextTariff);
-            break;
-
-        case 'm': //message
-            ParseAnyString(optarg, &str);
-            req.usrMsg = str;
-            isMessage = true;
-            break;
-
-        case 'e': //Prepaid Traffic
-            stat.freeMb = 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");
-            conf.note = str;
-            break;
-
-        case 'A': //nAme
-            ParseAnyString(optarg, &str, "koi8-ru");
-            conf.realName = str;
-            break;
-
-        case 'D': //aDdress
-            ParseAnyString(optarg, &str, "koi8-ru");
-            conf.address = str;
-            break;
-
-        case 'L': //emaiL
-            ParseAnyString(optarg, &str, "koi8-ru");
-            conf.email = str;
-            break;
-
-        case 'P': //phone
-            ParseAnyString(optarg, &str);
-            conf.phone = str;
-            break;
-
-        case 'G': //Group
-            ParseAnyString(optarg, &str, "koi8-ru");
-            conf.group = str;
-            break;
-
-        case 'I': //IP-address of user
-            ParseAnyString(optarg, &str);
-            conf.ips = StrToIPS(str);
-            break;
-
-        case 'S':
-            conf.disabledDetailStat = ParseDownPassive(optarg);
-            break;
-
-        case 'O':
-            conf.alwaysOnline = ParseDownPassive(optarg);
-            break;
-
-        case 500: //U
-            SetArrayItem(stat.sessionUp, optarg, ParseTraff(argv[optind++]));
-            break;
-        case 501:
-            SetArrayItem(stat.sessionDown, optarg, ParseTraff(argv[optind++]));
-            break;
-        case 502:
-            SetArrayItem(stat.monthUp, optarg, ParseTraff(argv[optind++]));
-            break;
-        case 503:
-            SetArrayItem(stat.monthDown, optarg, ParseTraff(argv[optind++]));
-            break;
-
-        case 700: //UserData
-            ParseAnyString(argv[optind++], &str);
-            SetArrayItem(conf.userdata, optarg, str);
-            break;
-
-        case '?':
-            missedOptionArg = true;
-            break;
-
-        case ':':
-            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);
-
-if (isMessage)
-    return ProcessSendMessage(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), req.usrMsg.data());
-
-return ProcessSetUser(req.server.data(), req.port.data(), req.admLogin.data(), req.admPasswd.data(), req.login.data(), conf, stat);
-}
 //-----------------------------------------------------------------------------
 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(Version), "\t\tshow version information 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("Raw XML")
-      .Add("r", "raw", SGCONF::MakeFunc1Action(), "\t\tmake raw XML request")
-/*blocks.Add("Admins management options")
-      .Add("get-admins", SGCONF::MakeConfAction())
-      .Add("get-admin", SGCONF::MakeConfAction())
-      .Add("add-admin", SGCONF::MakeConfAction())
-      .Add("del-admin", SGCONF::MakeConfAction())
-      .Add("chg-admin", SGCONF::MakeConfAction());*/
-
+SGCONF::AppendXMLOptionBlock(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);
 
@@ -1358,117 +301,22 @@ else
     }
 
 config = configOverride;
+
+std::cerr << "Config: " << config.Serialize() << std::endl;
+return commands.Execute(config) ? 0 : -1;
 }
 catch (const std::exception& ex)
 {
 std::cerr << ex.what() << "\n";
 return -1;
 }
-
-std::cerr << "Config: " << config.Serialize() << std::endl;
-
-return 0;
-
-if (argc < 2)
-    {
-    Usage();
-    return 1;
-    }
-
-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");
-    if (mainSet(argc - 1, argv + 1) )
-        return 0;
-    return -1;
-    }
-else
-    {
-    UsageConf();
-    exit(PARAMETER_PARSING_ERR_CODE);
-    }
-return UNKNOWN_ERR_CODE;
 }
 //-----------------------------------------------------------------------------
 
 namespace
 {
 
-void Usage()
-{
-UsageImpl(false);
-}
-
-void UsageAll()
-{
-UsageImpl(true);
-}
-
-void UsageImpl(bool full)
-{
-std::cout << "sgconf is the Stargazer management utility.\n\n"
-          << "Usage:\n"
-          << "\tsgconf [options]\n\n"
-          << "General options:\n"
-          << "\t-c, --config <config file>\t\toverride default config file (default: \"~/.config/stg/sgconf.conf\")\n"
-          << "\t-h, --help\t\t\t\tshow this help and exit\n"
-          << "\t--help-all\t\t\t\tshow full help and exit\n"
-          << "\t-v, --version\t\t\t\tshow version information and exit\n\n";
-UsageConnection();
-UsageAdmins(full);
-UsageTariffs(full);
-UsageUsers(full);
-UsageServices(full);
-UsageCorporations(full);
-}
-//-----------------------------------------------------------------------------
-void UsageConnection()
-{
-std::cout << "Connection options:\n"
-          << "\t-s, --server <address>\t\t\thost to connect (ip or domain name, default: \"localhost\")\n"
-          << "\t-p, --port <port>\t\t\tport to connect (default: \"5555\")\n"
-          << "\t-u, --username <username>\t\tadministrative login (default: \"admin\")\n"
-          << "\t-w, --userpass <password>\t\tpassword for administrative login\n"
-          << "\t-a, --address <connection string>\tconnection params as a single string in format: <login>:<password>@<host>:<port>\n\n";
-}
-//-----------------------------------------------------------------------------
-void UsageAdmins(bool full)
-{
-std::cout << "Admins management options:\n"
-          << "\t--get-admins\t\t\t\tget a list of admins (subsequent options will define what to show)\n";
-if (full)
-    std::cout << "\t\t--login\t\t\t\tshow admin's login\n"
-              << "\t\t--priv\t\t\t\tshow admin's priviledges\n\n";
-std::cout << "\t--get-admin\t\t\t\tget the information about admin\n";
-if (full)
-    std::cout << "\t\t--login <login>\t\t\tlogin of the admin to show\n"
-              << "\t\t--priv\t\t\t\tshow admin's priviledges\n\n";
-std::cout << "\t--add-admin\t\t\t\tadd a new admin\n";
-if (full)
-    std::cout << "\t\t--login <login>\t\t\tlogin of the admin to add\n"
-              << "\t\t--password <password>\t\tpassword of the admin to add\n"
-              << "\t\t--priv <priv number>\t\tpriviledges of the admin to add\n\n";
-std::cout << "\t--del-admin\t\t\t\tdelete an existing admin\n";
-if (full)
-    std::cout << "\t\t--login <login>\t\t\tlogin of the admin to delete\n\n";
-std::cout << "\t--chg-admin\t\t\t\tchange an existing admin\n";
-if (full)
-    std::cout << "\t\t--login <login>\t\t\tlogin of the admin to change\n"
-              << "\t\t--priv <priv number>\t\tnew priviledges\n\n";
-}
-//-----------------------------------------------------------------------------
-void UsageTariffs(bool full)
+/*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";
@@ -1604,11 +452,6 @@ 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";
-}
-
-void Version()
-{
-std::cout << "sgconf, version: 2.0.0-alpha.\n";
-}
+}*/
 
 } // namespace anonymous
index 6a4eef1b6952cb9849945afffc857d59b36ff90d..49e04d648d958c75d7b395cc26a9ef53163d20de 100644 (file)
@@ -117,12 +117,12 @@ void OPTION::Help(size_t level) const
 if (!m_action)
     throw ERROR("Option is not defined.");
 std::string indent(level, '\t');
-std::cout << indent << "\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 + 1);
+m_action->Suboptions().Help(level);
 }
 
 bool OPTION::Check(const char * arg) const
@@ -134,25 +134,28 @@ if (*arg++ != '-')
     return false;
 
 if (*arg == '-')
+{
     return m_longName == arg + 1;
+}
 
 return m_shortName == arg;
 }
 
-PARSER_STATE OPTION::Parse(int argc, char ** argv)
+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);
+    return m_action->Parse(argc, argv, data);
     }
 catch (const ACTION::ERROR & ex)
     {
     if (m_longName.empty())
         throw ERROR("-" + m_shortName + ": " + ex.what());
     else
-        throw ERROR("--" + m_longName + ", -" + m_shortName + ": " + ex.what());
+        throw m_shortName.empty() ? ERROR("--" + m_longName + ": " + ex.what())
+                                  : ERROR("--" + m_longName + ", -" + m_shortName + ": " + ex.what());
     }
 }
 
@@ -191,20 +194,23 @@ void OPTION_BLOCK::Help(size_t level) const
 {
 if (m_options.empty())
     return;
-std::cout << m_description << ":\n";
+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)
+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);
+        state = it->Parse(--state.argc, ++state.argv, data);
     else
         break;
     ++it;
@@ -241,7 +247,7 @@ 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.stop && it != m_blocks.end())
+while (state.argc > 0 && !state.stop && it != m_blocks.end())
     {
     state = it->Parse(state.argc, state.argv);
     ++it;
index 6b33ee8c2ba263efaa9bb3d3474586b1feb5fd24..c00707bf2d0887d0e7a279f0125eaeecf47e1071 100644 (file)
@@ -50,7 +50,7 @@ class OPTION
         OPTION & operator=(const OPTION & rhs);
 
         void Help(size_t level = 0) const;
-        PARSER_STATE Parse(int argc, char ** argv);
+        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; }
@@ -85,7 +85,7 @@ class OPTION_BLOCK
 
         void Help(size_t level) const;
 
-        PARSER_STATE Parse(int argc, char ** argv);
+        PARSER_STATE Parse(int argc, char ** argv, void * data = NULL);
         void ParseFile(const std::string & filePath);
 
         class ERROR : public std::runtime_error
@@ -107,6 +107,7 @@ 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);
 
diff --git a/projects/sgconf/request.h b/projects/sgconf/request.h
deleted file mode 100644 (file)
index bca3c14..0000000
+++ /dev/null
@@ -1,113 +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++)
-        {
-        sessionUpload[i].reset();
-        sessionDownload[i].reset();
-        monthUpload[i].reset();
-        monthDownload[i].reset();
-        }
-
-    for (int i = 0; i < USERDATA_NUM; i++)
-        userData[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>  sessionUpload[DIR_NUM];
-RESETABLE<int64_t>  sessionDownload[DIR_NUM];
-
-RESETABLE<int64_t>  monthUpload[DIR_NUM];
-RESETABLE<int64_t>  monthDownload[DIR_NUM];
-
-RESETABLE<string>   userData[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..22a6401
--- /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: " << 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..663536f
--- /dev/null
@@ -0,0 +1,406 @@
+#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 PeriodToString(TARIFF::PERIOD period)
+{
+switch (period)
+    {
+    case TARIFF::DAY:
+        return "daily";
+    case TARIFF::MONTH:
+        return "monthly";
+    }
+return "unknown";
+}
+
+std::string TraffTypeToString(int traffType)
+{
+switch (traffType)
+    {
+    case TRAFF_UP:
+        return "upload";
+    case TRAFF_DOWN:
+        return "download";
+    case TRAFF_UP_DOWN:
+        return "upload + download";
+    case 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 ConvTraffType(const std::string & value, RESETABLE<int> & res)
+{
+std::string lowered = ToLower(value);
+lowered.erase(std::remove(lowered.begin(), lowered.end(), ' '), lowered.end());
+if (lowered == "upload")
+    res = TRAFF_UP;
+else if (lowered == "download")
+    res = TRAFF_DOWN;
+else if (lowered == "upload+download")
+    res = TRAFF_UP_DOWN;
+else if (lowered.substr(0, 3) == "max")
+    res = 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";
+}
+
+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("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, "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, "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
-
-
index 9e1d8f80c39948fffd9a13626f2e303f16c64ba1..abf2ccc62e96f8643a9ff808d5a344c7d3964bd7 100644 (file)
@@ -1,5 +1,15 @@
 #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
@@ -10,7 +20,7 @@ struct ParserState
 size_t level;
 };
 
-std::string Indent(size_t size)
+std::string Indent(size_t level)
 {
 return std::string(level * 4, ' ');
 }
@@ -34,21 +44,19 @@ 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 << PrintAttrs(attr) << ">\n";
+    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";
---state->level;
 }
 
-}
-
-void SGCONF::PrintXML(const std::string& xml)
+void PrintXML(const std::string& xml)
 {
 ParserState state = { 0 };
 
@@ -58,9 +66,40 @@ 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(sc->parser)
-              << ": '" << XML_ErrorString(XML_GetErrorCode(sc->parser)) << "'"
+    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");
+}
index 25ee35c309affd048ef68b16760fd534c100f7f4..453d5eb60bfadf4aa03ccf7c666691c88227914e 100644 (file)
 #ifndef __STG_SGCONF_XML_H__
 #define __STG_SGCONF_XML_H__
 
-#include <string>
-
 namespace SGCONF
 {
 
-void PrintXML(const std::string& xml);
+class OPTION_BLOCKS;
+class COMMANDS;
+
+void AppendXMLOptionBlock(COMMANDS & commands, OPTION_BLOCKS & blocks);
 
 }
 
index 9314452b73a5afa31773152d1c7eab17dc7c6fbf..689cc262d615e3aea0bae8cccd33353aa6bf57d5 100755 (executable)
@@ -44,17 +44,15 @@ then
     case $release in
         4) OS=bsd;;
         5) OS=bsd5;;
-        6) OS=bsd5;;   
+        6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     MAKE="gmake"
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but sgconf currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #\n"
     printf "#############################################################################\n"
@@ -66,9 +64,9 @@ printf "       Building sgconf for $sys $release\n"
 printf "#############################################################################\n"
 
 STG_LIBS="conffiles.lib
-         crypto.lib 
-         common.lib 
-         srvconf.lib"
+          crypto.lib
+          common.lib
+          srvconf.lib"
 
 if [ "$OS" = "linux" ]
 then
index 580d515a8a9e51eb6764ff02a84214569a5de06f..aa826138253d1ae1688f98830be24763c8e66728 100755 (executable)
@@ -47,15 +47,13 @@ then
         5) OS=bsd5;;
         6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     MAKE="gmake"
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but sgconv currently supported by Linux, FreeBSD 4.x, 5.x, 6.x     #\n"
     printf "#############################################################################\n"
@@ -66,12 +64,12 @@ printf "########################################################################
 printf "       Building sgconv for $sys $release\n"
 printf "#############################################################################\n"
 
-STG_LIBS="logger.lib 
+STG_LIBS="logger.lib
           locker.lib
-         crypto.lib 
-         common.lib 
-         conffiles.lib
-         dotconfpp.lib"
+          crypto.lib
+          common.lib
+          conffiles.lib
+          dotconfpp.lib"
 
 PLUGINS="store/files"
 
index d8ed30924e14203389571f83e1dab77825602140..754f83f77ffebd9f0e2a1a7b424aaa481f0a64aa 100755 (executable)
@@ -66,9 +66,7 @@ then
         5) OS=bsd5;;
         6) OS=bsd5;;
         7) OS=bsd7;;
-        8) OS=bsd7;;
-        9) OS=bsd7;;
-        *) OS=unknown;;
+        *) OS=bsd7;;
     esac
     ETC_DIR="./inst/freebsd/etc/stargazer"
     MAKE="gmake"
@@ -82,7 +80,7 @@ then
 fi
 
 if [ "$OS" = "unknown" ]
-then 
+then
     printf "#############################################################################\n"
     printf "# Sorry, but stargazer currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #\n"
     printf "#############################################################################\n"
@@ -93,14 +91,14 @@ printf "########################################################################
 printf "       Building STG 2.4 for $sys $release\n"
 printf "#############################################################################\n"
 
-STG_LIBS="logger.lib 
+STG_LIBS="logger.lib
           locker.lib
-         crypto.lib 
-         common.lib 
-         scriptexecuter.lib 
-         conffiles.lib
-         pinger.lib 
-         dotconfpp.lib
+          crypto.lib
+          common.lib
+          scriptexecuter.lib
+          conffiles.lib
+          pinger.lib
+          dotconfpp.lib
           smux.lib"
 
 PLUGINS="authorization/ao
@@ -344,6 +342,42 @@ else
     fi
 fi
 
+printf "Checking for -lpcap... "
+$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 "
+$CC $CFLAGS $LDFLAGS build_check.c -lnfnetlink -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_NFNETLINK=no
+    printf "no\n"
+else
+    CHECK_NFNETLINK=yes
+    printf "yes\n"
+fi
+rm -f fake
+
+printf "Checking for -lnetfilter_queue "
+$CC $CFLAGS $LDFLAGS build_check.c -lnetfilter_queue -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_NFQ=no
+    printf "no\n"
+else
+    CHECK_NFQ=yes
+    printf "yes\n"
+fi
+rm -f fake
+
 if [ "$OS" = "linux" ]
 then
     printf "Checking for linux/netfilter_ipv4/ip_queue.h... "
@@ -399,6 +433,19 @@ 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
+             capture/nfqueue"
+    NFQ_LIBS="-lnfnetlink -lnetfilter_queue"
+fi
+
 printf "OS=$OS\n" > $CONFFILE
 printf "STG_TIME=yes\n" >> $CONFFILE
 printf "DEBUG=$DEBUG\n" >> $CONFFILE
@@ -414,7 +461,11 @@ printf "CHECK_FBCLIENT=$CHECK_FBCLIENT\n" >> $CONFFILE
 printf "CHECK_MYSQLCLIENT=$CHECK_MYSQLCLIENT\n" >> $CONFFILE
 printf "CHECK_PQ=$CHECK_PQ\n" >> $CONFFILE
 printf "CHECK_XMLRPC=$CHECK_XMLRPC\n" >> $CONFFILE
+printf "CHECK_PCAP=$CHECK_PCAP\n" >> $CONFFILE
+printf "CHECK_NFNETLINK=$CHECK_NFNETLINK\n" >> $CONFFILE
+printf "CHECK_NFQ=$CHECK_NFQ\n" >> $CONFFILE
 printf "DEFS=$DEFS\n" >> $CONFFILE
+printf "NFQ_LIBS=$NFQ_LIBS\n" >> $CONFFILE
 printf "STG_LIBS=" >> $CONFFILE
 for lib in $STG_LIBS
 do
index 6ec8c3420e1dc3dd91d9f25bc848f2403c7e60f6..480ef202ba63deb67b13c23afc6e47705aa13ef1 100644 (file)
@@ -81,7 +81,7 @@ RAW_PACKET MakeTCPPacket(const char * src,
                          uint16_t len);
 std::string DEBUG_CAP::GetVersion() const
 {
-return "Debug_cap v.0.01a";
+return "cap_debug v.0.01a";
 }
 //-----------------------------------------------------------------------------
 DEBUG_CAP::DEBUG_CAP()
index 41ad9faed1ab4d769ba4359e11c3fac673cb642f..8c4fdc2dd350cf9dbc9306d59273cf39446d2366 100644 (file)
@@ -39,7 +39,7 @@ $Author: faust $
 
 #include <vector>
 
-#include "stg/common.h" 
+#include "stg/common.h"
 #include "stg/raw_ip_packet.h"
 #include "stg/traffcounter.h"
 #include "stg/plugin_creator.h"
@@ -123,7 +123,7 @@ if (portU > 0)
         runningUDP = false;
         CloseUDP();
         errorStr = "Cannot create UDP thread";
-       logger("Cannot create UDP thread.");
+        logger("Cannot create UDP thread.");
         printfd(__FILE__, "Error: Cannot create UDP thread\n");
         return -1;
         }
@@ -139,7 +139,7 @@ if (portT > 0)
         {
         runningTCP = false;
         CloseTCP();
-       logger("Cannot create TCP thread.");
+        logger("Cannot create TCP thread.");
         errorStr = "Cannot create TCP thread";
         printfd(__FILE__, "Error: Cannot create TCP thread\n");
         return -1;
@@ -168,7 +168,7 @@ if (portU && !stoppedUDP)
         if (pthread_kill(tidUDP, SIGUSR1))
             {
             errorStr = "Error sending signal to UDP thread";
-           logger("Error sending sugnal to UDP thread.");
+            logger("Error sending sugnal to UDP thread.");
             printfd(__FILE__, "Error: Error sending signal to UDP thread\n");
             return -1;
             }
@@ -193,12 +193,12 @@ if (portT && !stoppedTCP)
         if (pthread_kill(tidTCP, SIGUSR1))
             {
             errorStr = "Error sending signal to TCP thread";
-           logger("Error sending signal to TCP thread.");
+            logger("Error sending signal to TCP thread.");
             printfd(__FILE__, "Error: Error sending signal to TCP thread\n");
             return -1;
             }
         printfd(__FILE__, "TCP thread NOT stopped\n");
-       logger("Cannot stop TCP thread.");
+        logger("Cannot stop TCP thread.");
         }
     }
 return 0;
@@ -283,10 +283,10 @@ while (cap->runningUDP)
         break;
 
     if (res < 0)
-       {
-       cap->logger("recvfrom error: %s", strerror(errno));
-       continue;
-       }
+        {
+        cap->logger("recvfrom error: %s", strerror(errno));
+        continue;
+        }
 
     if (res == 0) // EOF
         {
@@ -334,7 +334,7 @@ while (cap->runningTCP)
     if (sd <= 0)
         {
         if (sd < 0)
-           cap->logger("accept error: %s", strerror(errno));
+            cap->logger("accept error: %s", strerror(errno));
         continue;
         }
 
index 23f7d7db2e18fc4f4f176581dce105c507b65949..bcb8b743619ac4658a49bb130a6b50bd5909a188 100644 (file)
@@ -39,7 +39,7 @@ $Author: faust $
 #include "stg/module_settings.h"
 #include "stg/logger.h"
 
-#define VERSION "CAP_NF v. 0.4"
+#define VERSION "cap_nf v. 0.4"
 #define START_POS 40
 #define STOP_POS 40
 
index 96476d4e204027ee8f1d556f7dc54544a52489d8..41817d92f7821aecf18da8c3f9443a22027dc8b0 100644 (file)
@@ -80,7 +80,7 @@ return dcc.GetPlugin();
 //-----------------------------------------------------------------------------
 std::string DIVERT_CAP::GetVersion() const
 {
-return "Divert_cap v.1.0";
+return "cap_divert v.1.0";
 }
 //-----------------------------------------------------------------------------
 DIVERT_CAP::DIVERT_CAP()
@@ -147,7 +147,7 @@ if (isRunning)
     if (pthread_kill(thread, SIGINT))
         {
         errorStr = "Cannot kill thread.";
-       logger("Cannot send signal to thread.");
+        logger("Cannot send signal to thread.");
         printfd(__FILE__, "Cannot kill thread\n");
         return -1;
         }
@@ -262,10 +262,10 @@ if ((bytes = recvfrom (cddiv.sock, buf, BUFF_LEN,
         *iface = cddiv.iface;
 
     if (!disableForwarding)
-       {
+        {
         if (sendto(cddiv.sock, buf, bytes, 0, (struct sockaddr*)&divertaddr, divertaddrSize) < 0)
-           logger("sendto error: %s", strerror(errno));
-       }
+            logger("sendto error: %s", strerror(errno));
+        }
     }
 else
     {
index 72e7f73bdcad694183f5cb94c03fe9dd33d1e241..254fd3f92d53d34d05c0f03dd43b805cede7ff06 100644 (file)
@@ -117,7 +117,7 @@ return iface[num];
 //-----------------------------------------------------------------------------
 std::string BPF_CAP::GetVersion() const
 {
-return "bpf_cap v.1.0";
+return "cap_bpf v.1.0";
 }
 //-----------------------------------------------------------------------------
 BPF_CAP::BPF_CAP()
@@ -131,7 +131,7 @@ BPF_CAP::BPF_CAP()
       capSock(-1),
       settings(),
       traffCnt(NULL),
-      logger(GetPluginLogger(GetStgLogger(), "cap_ether"))
+      logger(GetPluginLogger(GetStgLogger(), "cap_bpf"))
 {
 }
 //-----------------------------------------------------------------------------
@@ -197,7 +197,7 @@ if (isRunning)
     if (pthread_kill(thread, SIGINT))
         {
         errorStr = "Cannot kill thread.";
-       logger("Cannot send signal to thread.");
+        logger("Cannot send signal to thread.");
         printfd(__FILE__, "Cannot kill thread\n");
         return -1;
         }
@@ -347,7 +347,7 @@ if (bd->canRead)
     bd->r = read(bd->fd, bd->buffer, BUFF_LEN);
     if (bd->r < 0)
         {
-       logger("read error: %s", strerror(errno));
+        logger("read error: %s", strerror(errno));
         struct timespec ts = {0, 20000000};
         nanosleep(&ts, NULL);
         return -1;
index a97fa8e7d07e5490569f7f9c73e14d6107776717..fd83c48542b663028a7d202a10a36a43839c6ff6 100644 (file)
@@ -71,10 +71,10 @@ return ecc.GetPlugin();
 }
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------        
+//-----------------------------------------------------------------------------
 std::string ETHER_CAP::GetVersion() const
 {
-return "Ether_cap v.1.2";
+return "cap_ether v.1.2";
 }
 //-----------------------------------------------------------------------------
 ETHER_CAP::ETHER_CAP()
@@ -132,7 +132,7 @@ if (isRunning)
     if (pthread_kill(thread, SIGUSR1))
         {
         errorStr = "Cannot kill thread.";
-       logger("Cannot send signal to thread.");
+        logger("Cannot send signal to thread.");
         return -1;
         }
     for (int i = 0; i < 25 && isRunning; ++i)
@@ -143,7 +143,7 @@ if (isRunning)
     if (isRunning)
         {
         errorStr = "ETHER_CAP not stopped.";
-       logger("Cannot stop thread.");
+        logger("Cannot stop thread.");
         printfd(__FILE__, "Cannot stop thread\n");
         return -1;
         }
index 055993063d44b96d617f2b164ce89a11f9663aca..45ca9b1f76ce0fa1e461fe937a5f30768c7c91db 100644 (file)
@@ -58,7 +58,7 @@ return icc.GetPlugin();
 //-----------------------------------------------------------------------------
 std::string IPQ_CAP::GetVersion() const
 {
-return "ipq_cap v.1.2";
+return "cap_ipq v.1.2";
 }
 //-----------------------------------------------------------------------------
 IPQ_CAP::IPQ_CAP()
diff --git a/projects/stargazer/plugins/capture/nfqueue/Makefile b/projects/stargazer/plugins/capture/nfqueue/Makefile
new file mode 100644 (file)
index 0000000..a9f4a80
--- /dev/null
@@ -0,0 +1,13 @@
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_nfqueue.so
+
+SRCS = ./nfqueue.cpp
+
+LIBS += $(NFQ_LIBS) $(LIB_THREAD)
+
+STGLIBS = common \
+          logger
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/nfqueue/nfqueue.cpp b/projects/stargazer/plugins/capture/nfqueue/nfqueue.cpp
new file mode 100644 (file)
index 0000000..6a33952
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ *    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 "nfqueue.h"
+
+#include "stg/traffcounter.h"
+#include "stg/plugin_creator.h"
+#include "stg/common.h"
+#include "stg/raw_ip_packet.h"
+
+extern "C" {
+
+#include <linux/netfilter.h>  /* Defines verdicts (NF_ACCEPT, etc) */
+#include <libnetfilter_queue/libnetfilter_queue.h>
+
+}
+
+#include <cerrno>
+#include <csignal>
+
+#include <arpa/inet.h> // ntohl
+
+#include <unistd.h> // read
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+namespace
+{
+
+PLUGIN_CREATOR<NFQ_CAP> ncc;
+
+int Callback(struct nfq_q_handle * queueHandle, struct nfgenmsg * /*msg*/,
+             struct nfq_data * nfqData, void *data)
+{
+int id = 0;
+
+struct nfqnl_msg_packet_hdr * packetHeader = nfq_get_msg_packet_hdr(nfqData);
+if (packetHeader == NULL)
+    return 0;
+
+id = ntohl(packetHeader->packet_id);
+
+unsigned char * payload = NULL;
+
+if (nfq_get_payload(nfqData, &payload) < 0 || payload == NULL)
+    return id;
+
+RAW_PACKET packet;
+
+memcpy(&packet.rawPacket, payload, sizeof(packet.rawPacket));
+
+NFQ_CAP * cap = static_cast<NFQ_CAP *>(data);
+
+cap->Process(packet);
+
+return nfq_set_verdict(queueHandle, id, NF_ACCEPT, 0, NULL);
+}
+
+}
+
+extern "C" PLUGIN * GetPlugin();
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PLUGIN * GetPlugin()
+{
+return ncc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+std::string NFQ_CAP::GetVersion() const
+{
+return "cap_nfqueue v.1.0";
+}
+//-----------------------------------------------------------------------------
+NFQ_CAP::NFQ_CAP()
+    : errorStr(),
+      thread(),
+      nonstop(false),
+      isRunning(false),
+      queueNumber(0),
+      traffCnt(NULL),
+      logger(GetPluginLogger(GetStgLogger(), "cap_nfqueue"))
+{
+}
+//-----------------------------------------------------------------------------
+int NFQ_CAP::ParseSettings()
+{
+for (size_t i = 0; i < settings.moduleParams.size(); i++)
+    if (settings.moduleParams[i].param == "queueNumber")
+        if (str2x(settings.moduleParams[i].param, queueNumber) < 0)
+            {
+            errorStr = "Queue number should be a number. Got: '" + settings.moduleParams[i].param + "'";
+            logger(errorStr);
+            return -1;
+            }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NFQ_CAP::Start()
+{
+if (isRunning)
+    return 0;
+
+nfqHandle = nfq_open();
+if (nfqHandle == NULL)
+    {
+    errorStr = "Failed to initialize netfilter queue.";
+    logger(errorStr);
+    return -1;
+    }
+
+if (nfq_unbind_pf(nfqHandle, AF_INET) < 0)
+    {
+    errorStr = "Failed to unbind netfilter queue from IP handling.";
+    logger(errorStr);
+    return -1;
+    }
+
+if (nfq_bind_pf(nfqHandle, AF_INET) < 0)
+    {
+    errorStr = "Failed to bind netfilter queue to IP handling.";
+    logger(errorStr);
+    return -1;
+    }
+
+queueHandle = nfq_create_queue(nfqHandle, queueNumber, &Callback, this);
+if (queueHandle == NULL)
+    {
+    errorStr = "Failed to create queue " + x2str(queueNumber) + ".";
+    logger(errorStr);
+    return -1;
+    }
+
+if (nfq_set_mode(queueHandle, NFQNL_COPY_PACKET, 0xffFF) < 0)
+    {
+    errorStr = "Failed to set queue " + x2str(queueNumber) + " mode.";
+    logger(errorStr);
+    return -1;
+    }
+
+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 NFQ_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 = "NFQ_CAP not stopped.";
+        logger("Cannot stop thread.");
+        printfd(__FILE__, "Cannot stop thread\n");
+        return -1;
+        }
+    }
+
+pthread_join(thread, NULL);
+
+nfq_destroy_queue(queueHandle);
+nfq_close(nfqHandle);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * NFQ_CAP::Run(void * d)
+{
+sigset_t signalSet;
+sigfillset(&signalSet);
+pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
+
+NFQ_CAP * dc = static_cast<NFQ_CAP *>(d);
+dc->isRunning = true;
+
+int fd = nfq_fd(dc->nfqHandle);
+char buf[4096];
+
+while (dc->nonstop)
+    {
+        if (!WaitPackets(fd))
+            continue;
+
+        int rv = read(fd, buf, sizeof(buf));
+        if (rv < 0)
+            {
+            dc->errorStr = std::string("Read error: ") + strerror(errno);
+            dc->logger(dc->errorStr);
+            break;
+            }
+        nfq_handle_packet(dc->nfqHandle, buf, rv);
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void NFQ_CAP::Process(const RAW_PACKET & packet)
+{
+traffCnt->Process(packet);
+}
diff --git a/projects/stargazer/plugins/capture/nfqueue/nfqueue.h b/projects/stargazer/plugins/capture/nfqueue/nfqueue.h
new file mode 100644 (file)
index 0000000..8712478
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *    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 NFQ_CAP_H
+#define NFQ_CAP_H
+
+#include "stg/plugin.h"
+#include "stg/module_settings.h"
+#include "stg/logger.h"
+
+#include <string>
+#include <vector>
+
+#include <pthread.h>
+
+class USERS;
+class TARIFFS;
+class ADMINS;
+class TRAFFCOUNTER;
+class SETTINGS;
+class RAW_PACKET;
+
+class TRAFFCOUNTER;
+
+struct nfq_handle;
+struct nfq_q_handle;
+
+class NFQ_CAP : public PLUGIN {
+public:
+    NFQ_CAP();
+    virtual ~NFQ_CAP() {}
+
+    void                SetTraffcounter(TRAFFCOUNTER * tc) { traffCnt = tc; }
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { 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; }
+
+    void                Process(const RAW_PACKET & packet);
+
+private:
+    NFQ_CAP(const NFQ_CAP & rvalue);
+    NFQ_CAP & operator=(const NFQ_CAP & rvalue);
+
+    static void *       Run(void *);
+
+    mutable std::string errorStr;
+
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+    MODULE_SETTINGS     settings;
+
+    size_t              queueNumber;
+
+    struct nfq_handle * nfqHandle;
+    struct nfq_q_handle * queueHandle;
+
+    TRAFFCOUNTER *      traffCnt;
+
+    PLUGIN_LOGGER       logger;
+};
+//-----------------------------------------------------------------------------
+
+#endif
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..5e3e874
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *    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()
+    : errorStr(),
+      thread(),
+      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..bf050c1
--- /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() { 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 e76d8f4ca9b36ec5122bcd12a68f958f2c1ed431..3a667360523b27cc98320d4897e8f88d700a8c3e 100644 (file)
@@ -39,6 +39,7 @@ public:
     virtual ~BASE_PARSER() {}
     virtual int ParseStart(void *data, const char *el, const char **attr) = 0;
     virtual int ParseEnd(void *data, const char *el) = 0;
+    virtual void Reset() { answerList->clear(); depth = 0; }
 
     void SetAnswerList(std::list<std::string> * ansList) { answerList = ansList; }
 
@@ -50,7 +51,6 @@ public:
 
     void SetCurrAdmin(ADMIN & cua) { currAdmin = &cua; }
     std::string & GetStrError() { return strError; }
-    void Reset() { answerList->clear(); depth = 0; }
 
 protected:
     BASE_PARSER(const BASE_PARSER & rvalue);
index 3331a07d411692bfe957d6085b8e968afc903a75..66e452a9b9e4128bf0974a7eb06983cdbbead05c 100644 (file)
@@ -564,7 +564,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())
@@ -883,7 +883,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 7ba78e1d8b311e149ea0b705ee3b0102a3af423f..c27a387d647949bbb8a27791c955bff6de10f3ee 100644 (file)
@@ -531,6 +531,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];
@@ -807,7 +823,8 @@ return unsigned2str(x, s);
 const std::string & x2str(double x, std::string & s)
 {
 char buf[256];
-s = snprintf(buf, sizeof(buf), "%f", x);
+snprintf(buf, sizeof(buf), "%f", x);
+s = buf;
 return s;
 }
 //---------------------------------------------------------------------------
index f2e4e7e2432ab52aa75ed29efbe684726a7fe5ea..6af1309fab77bbe101c80c36831fd38187230d43 100644 (file)
@@ -33,6 +33,7 @@
 #include <ctime>
 #endif
 #include <string>
+#include <sstream>
 
 #include "stg/os_int.h"
 #include "stg/const.h"
@@ -77,6 +78,7 @@ int             DaysInCurrentMonth();
 int             Min8(int a);
 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);
@@ -100,7 +102,48 @@ std::string     Trim(const std::string & val);
 std::string     ToLower(const std::string & value);
 std::string     ToUpper(const std::string & value);
 
-std::string     IconvString(const std::string & source, const std::string & from, const std::string & to);
+template <typename C, typename F>
+inline
+C Split(const std::string & value, char delim, F conv)
+{
+C res;
+size_t startPos = 0;
+size_t pos = value.find_first_of(delim);
+while (pos != std::string::npos)
+    {
+    res.push_back(conv(value.substr(startPos, pos - startPos)));
+    startPos = pos + 1;
+    pos = value.find_first_of(delim, pos + 1);
+    }
+res.push_back(conv(value.substr(startPos, pos - startPos)));
+return res;
+}
+
+template <typename T>
+inline
+T FromString(const std::string & value)
+{
+T res;
+std::istringstream stream(value);
+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<typename C::value_type>);
+}
+
+std::string IconvString(const std::string & source, const std::string & from, const std::string & to);
 
 int ParseInt(const std::string & str, int * val);
 int ParseUnsigned(const std::string & str, unsigned * val);
@@ -114,6 +157,8 @@ bool WaitPackets(int sd);
 //-----------------------------------------------------------------------------
 int str2x(const std::string & str, int32_t & x);
 int str2x(const std::string & str, uint32_t & 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);
index c55801ac2a32570fb41348b2f74a2d604332122b..115d1fb3907a71e63e2c798cf3f1d18d3cd60a08 100644 (file)
@@ -30,6 +30,7 @@ public:
     ~STG_LOGGER();
     void SetLogFileName(const std::string & fn);
     void operator()(const char * fmt, ...) const;
+    void operator()(const std::string & line) const { LogString(line.c_str()); }
 
 private:
     STG_LOGGER();
@@ -37,6 +38,7 @@ private:
     STG_LOGGER & operator=(const STG_LOGGER & rvalue);
 
     const char * LogDate(time_t t) const;
+    void LogString(const char * str) const;
 
     std::string fileName;
     mutable pthread_mutex_t mutex;
@@ -49,6 +51,7 @@ friend PLUGIN_LOGGER GetPluginLogger(const STG_LOGGER & logger, const std::strin
 public:
     PLUGIN_LOGGER(const PLUGIN_LOGGER & rhs);
     void operator()(const char * fmt, ...) const;
+    void operator()(const std::string & line) const;
 
 private:
     PLUGIN_LOGGER(const STG_LOGGER & logger, const std::string & pn);
index 14c09591f0394147c3527a1ec253ad746e59c865..6289618e9b1895cf662c5c0381151e8bb0e2c1f5 100644 (file)
@@ -43,10 +43,33 @@ va_start(vl, fmt);
 vsnprintf(buff, sizeof(buff), fmt, vl);
 va_end(vl);
 
-FILE * f;
+LogString(buff);
+}
+//-----------------------------------------------------------------------------
+const char * STG_LOGGER::LogDate(time_t t) const
+{
+static char s[32];
+if (t == 0)
+    t = time(NULL);
+
+struct tm * tt = localtime(&t);
+
+snprintf(s, 32, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
+         tt->tm_year + 1900,
+         tt->tm_mon + 1 < 10 ? "0" : "", tt->tm_mon + 1,
+         tt->tm_mday    < 10 ? "0" : "", tt->tm_mday,
+         tt->tm_hour    < 10 ? "0" : "", tt->tm_hour,
+         tt->tm_min     < 10 ? "0" : "", tt->tm_min,
+         tt->tm_sec     < 10 ? "0" : "", tt->tm_sec);
+
+return s;
+}
+//-----------------------------------------------------------------------------
+void STG_LOGGER::LogString(const char * str) const
+{
 if (!fileName.empty())
     {
-    f = fopen(fileName.c_str(), "at");
+    FILE * f = fopen(fileName.c_str(), "at");
     if (f)
         {
         #ifdef STG_TIME
@@ -55,44 +78,25 @@ if (!fileName.empty())
         fprintf(f, "%s", LogDate(time(NULL)));
         #endif
         fprintf(f, " -- ");
-        fprintf(f, "%s", buff);
+        fprintf(f, "%s", str);
         fprintf(f, "\n");
         fclose(f);
         }
     else
         {
         openlog("stg", LOG_NDELAY, LOG_USER);
-        syslog(LOG_CRIT, "%s", buff);
+        syslog(LOG_CRIT, "%s", str);
         closelog();
         }
     }
 else
     {
     openlog("stg", LOG_NDELAY, LOG_USER);
-    syslog(LOG_CRIT, "%s", buff);
+    syslog(LOG_CRIT, "%s", str);
     closelog();
     }
 }
 //-----------------------------------------------------------------------------
-const char * STG_LOGGER::LogDate(time_t t) const
-{
-static char s[32];
-if (t == 0)
-    t = time(NULL);
-
-struct tm * tt = localtime(&t);
-
-snprintf(s, 32, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
-         tt->tm_year + 1900,
-         tt->tm_mon + 1 < 10 ? "0" : "", tt->tm_mon + 1,
-         tt->tm_mday    < 10 ? "0" : "", tt->tm_mday,
-         tt->tm_hour    < 10 ? "0" : "", tt->tm_hour,
-         tt->tm_min     < 10 ? "0" : "", tt->tm_min,
-         tt->tm_sec     < 10 ? "0" : "", tt->tm_sec);
-
-return s;
-}
-//-----------------------------------------------------------------------------
 PLUGIN_LOGGER::PLUGIN_LOGGER(const STG_LOGGER & logger, const std::string & pn)
     : STG_LOGGER(),
       pluginName(pn)
@@ -119,6 +123,11 @@ va_end(vl);
 STG_LOGGER::operator()("[%s] %s", pluginName.c_str(), buff);
 }
 //-----------------------------------------------------------------------------
+void PLUGIN_LOGGER::operator()(const std::string & line) const
+{
+STG_LOGGER::operator()("[%s] %s", pluginName.c_str(), line.c_str());
+}
+//-----------------------------------------------------------------------------
 PLUGIN_LOGGER GetPluginLogger(const STG_LOGGER & logger, const std::string & pluginName)
 {
 return PLUGIN_LOGGER(logger, pluginName);
index 2a2dbcaac0a13af69badfc3143eb3fd023c6fbb5..cd37e49e44b984ae84317c17ac3eeb8bc99baf88 100644 (file)
@@ -43,6 +43,9 @@ class SERVCONF
 public:
     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();
 
     int ServerInfo(SERVER_INFO::CALLBACK f, void * data);
@@ -72,7 +75,10 @@ public:
                 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, 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);
index f323e99e95a96325f10d09b89c2e466d0ba77dc9..998e3b4747d08e2c02fd1548d743759b2bf74842 100644 (file)
@@ -21,6 +21,7 @@
 #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...
 
@@ -107,7 +108,7 @@ struct INFO
     int         usersNum;
     std::string uname;
     int         dirNum;
-    std::string dirName[DIR_NUM];
+    ARRAY<std::string, DIR_NUM> dirName;
 };
 typedef void (* CALLBACK)(bool result, const std::string & reason, const INFO & info, void * data);
 
@@ -125,11 +126,10 @@ namespace GET_USER
 
 struct STAT
 {
-    long long  su[DIR_NUM];
-    long long  sd[DIR_NUM];
-    long long  mu[DIR_NUM];
-    long long  md[DIR_NUM];
-    double     freeMb;
+    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
@@ -139,9 +139,11 @@ struct INFO
     double      cash;
     double      credit;
     time_t      creditExpire;
-    double      lastCash;
+    double      lastCashAdd;
+    double      lastCashAddTime;
+    time_t      lastTimeCash;
     double      prepaidTraff;
-    int         down;
+    int         disabled;
     int         passive;
     int         disableDetailStat;
     int         connected;
@@ -155,8 +157,13 @@ struct INFO
     std::string name;
     std::string address;
     std::string phone;
+    std::string corp;
     STAT        stat;
-    std::string userData[USERDATA_NUM];
+    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);
index 164823d8395d42d41f81f11a728dfdba5c34c958..a8b36e5715514dad3b3f3f60af23b8cb5dc9da09 100644 (file)
@@ -53,6 +53,7 @@ const std::string::size_type MAX_XML_CHUNK_LENGTH = 2048;
 #define RECV_DATA_ANSWER_ERROR      "Recv data answer error!"
 #define UNKNOWN_ERROR               "Unknown error!"
 #define CONNECT_FAILED              "Connect failed!"
+#define BIND_FAILED                 "Bind failed!"
 #define INCORRECT_LOGIN             "Incorrect login!"
 #define INCORRECT_HEADER            "Incorrect header!"
 #define SEND_LOGIN_ERROR            "Send login error!"
@@ -73,6 +74,19 @@ NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
 {
 }
 //---------------------------------------------------------------------------
+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),
+      outerSocket(-1)
+{
+}
+//---------------------------------------------------------------------------
 int NETTRANSACT::Connect()
 {
 outerSocket = socket(PF_INET, SOCK_STREAM, 0);
@@ -82,6 +96,41 @@ if (outerSocket < 0)
     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 = "DNS error.\nCan 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(outerSocket, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0)
+        {
+        errorMsg = BIND_FAILED;
+        close(outerSocket);
+        return st_conn_fail;
+        }
+    }
+
 struct sockaddr_in outerAddr;
 memset(&outerAddr, 0, sizeof(outerAddr));
 
index f87fb3a864de758621200af456a21ec8e4dfbc0f..b6584ee57b46e68fdf75253b91e1202eb2304c04 100644 (file)
@@ -32,6 +32,9 @@ public:
 
     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);
     int Transact(const std::string & request, CALLBACK f, void * data);
     const std::string & GetError() const { return errorMsg; }
 
@@ -52,6 +55,8 @@ private:
 
     std::string server;
     uint16_t  port;
+    std::string localAddress;
+    uint16_t localPort;
     std::string login;
     std::string password;
     int outerSocket;
index 61f590bfcc927d3deb62534ee5908161753b17bd..143eee261dae838b82740716eead98999ffa5c0f 100644 (file)
 
 using namespace STG;
 
-AUTH_BY::PARSER::PARSER(CALLBACK f, void * d)
+AUTH_BY::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0),
       parsingAnswer(false)
 {
index f285d2bfb1039f5c11bd5c4b849bbf8c2bbd19ae..5b2dfe52fb6cbf9b3ef1f32c93da99902cf71f11 100644 (file)
@@ -35,13 +35,15 @@ namespace AUTH_BY
 class PARSER: public STG::PARSER
 {
 public:
-    PARSER(CALLBACK f, void * data);
+    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;
index 8d695a3a7049c2b9be2935f336e6159342656ffb..4f84d8746774a623269ff1de21f232081c5539d5 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef __STG_STGLIBS_SRVCONF_PARSER_H__
 #define __STG_STGLIBS_SRVCONF_PARSER_H__
 
+#include <string>
+
 namespace STG
 {
 
@@ -29,8 +31,9 @@ class PARSER
 {
 public:
     virtual ~PARSER() {}
-    virtual int ParseStart(const char *el, const char **attr) = 0;
-    virtual void ParseEnd(const char *el) = 0;
+    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
index a4265efa5b3278d99ae9e3da0df7ffe27071d98f..14679dff6f04c8d0c61d2d6bc6b914ff1e450279 100644 (file)
@@ -27,7 +27,7 @@
 
 using namespace STG;
 
-std::string CHG_ADMIN::Serialize(const ADMIN_CONF_RES & conf)
+std::string CHG_ADMIN::Serialize(const ADMIN_CONF_RES & conf, const std::string & /*encoding*/)
 {
 std::string params;
 if (!conf.login.empty())
index c10332cd71beb4fa7c491c64085f9c30fa5ad941..7041aa8ef60e34ebc9cb4350db3351ffd2f9915d 100644 (file)
@@ -34,7 +34,7 @@ namespace STG
 namespace CHG_ADMIN
 {
 
-std::string Serialize(const ADMIN_CONF_RES & conf);
+std::string Serialize(const ADMIN_CONF_RES & conf, const std::string & encoding);
 
 } // namespace CHG_ADMIN
 } // namespace STG
index dc884220d2a4d0519db9f61ef48dfd99b52f5327..daa54644801f7450511693e56d1fab30def6c8f2 100644 (file)
@@ -29,7 +29,7 @@
 
 using namespace STG;
 
-std::string CHG_CORP::Serialize(const CORP_CONF_RES & conf)
+std::string CHG_CORP::Serialize(const CORP_CONF_RES & conf, const std::string & /*encoding*/)
 {
 std::ostringstream stream;
 
index 8b75fbd44dd2ae51472c83edd9de513b9a702b55..b30482f7dec9f1593121fc5262d9e7301f938fc3 100644 (file)
@@ -34,7 +34,7 @@ namespace STG
 namespace CHG_CORP
 {
 
-std::string Serialize(const CORP_CONF_RES & conf);
+std::string Serialize(const CORP_CONF_RES & conf, const std::string & encoding);
 
 } // namespace CHG_CORP
 } // namespace STG
index f8627614c0327bf7e9eb34f96e28e8c39b5f8c53..7dac5ba9925eee29d3eb41d8a72171da684b2a82 100644 (file)
 
 using namespace STG;
 
-std::string CHG_SERVICE::Serialize(const SERVICE_CONF_RES & conf)
+std::string CHG_SERVICE::Serialize(const SERVICE_CONF_RES & conf, const std::string & /*encoding*/)
 {
 std::ostringstream stream;
 
 appendResetable(stream, "name", conf.name);
-appendResetable(stream, "comment", conf.comment);
+appendResetable(stream, "comment", MaybeEncode(conf.comment));
 appendResetable(stream, "cost", conf.cost);
 appendResetable(stream, "payDay", conf.payDay);
 
index 10fbf6fb0e45ee84b918a2887327214739e15629..09464a6e373b58f132cdaac46dbe5f2af498711c 100644 (file)
@@ -34,7 +34,7 @@ namespace STG
 namespace CHG_SERVICE
 {
 
-std::string Serialize(const SERVICE_CONF_RES & conf);
+std::string Serialize(const SERVICE_CONF_RES & conf, const std::string & encoding);
 
 } // namespace CHG_SERVICE
 } // namespace STG
index cb7d9475b2e8af3100ddc2cb3b463a5bd9dddf76..80bb4cb2dcc87c50a1c220066394815e4b180076 100644 (file)
@@ -51,7 +51,7 @@ stream << "<" << name << " value=\"" << res << "\"/>";
 
 } // namespace anonymous
 
-std::string CHG_TARIFF::Serialize(const TARIFF_DATA_RES & data)
+std::string CHG_TARIFF::Serialize(const TARIFF_DATA_RES & data, const std::string & /*encoding*/)
 {
 std::ostringstream stream;
 
@@ -68,6 +68,13 @@ if (!data.tariffConf.traffType.empty())
         case TRAFF_MAX: stream << "<traffType value=\"max\"/>"; break;
         }
 
+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;
+        }
+
 for (size_t i = 0; i < DIR_NUM; ++i)
     if (!data.dirPrice[i].hDay.empty() &&
         !data.dirPrice[i].mDay.empty() &&
index c5cc0f0ce3c80f41f0ddb658d0d3cd879ba90c7d..142b015565fece2e095794f0a2b8e6d96dac4e72 100644 (file)
@@ -34,7 +34,7 @@ namespace STG
 namespace CHG_TARIFF
 {
 
-std::string Serialize(const TARIFF_DATA_RES & data);
+std::string Serialize(const TARIFF_DATA_RES & data, const std::string & encoding);
 
 } // namespace CHG_TARIFF
 } // namespace STG
index ed2002bcf78b55065ccaff4556916b287efa1684..f00279684990bbd04fa904207b02d3e2658a5bfb 100644 (file)
 
 #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)
+CHG_USER::PARSER::PARSER(SIMPLE::CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0)
 {
 }
@@ -69,7 +72,7 @@ else
     callback(false, "Invalid response.", data);
 }
 
-std::string CHG_USER::Serialize(const USER_CONF_RES & conf, const USER_STAT_RES & stat)
+std::string CHG_USER::Serialize(const USER_CONF_RES & conf, const USER_STAT_RES & stat, const std::string & encoding)
 {
 std::ostringstream stream;
 
@@ -87,24 +90,33 @@ appendResetable(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.nextTariff.data() << "\"/>";
+    stream << "<tariff now=\"" << conf.tariffName.data() << "\"/>";
 
-appendResetable(stream, "note", conf.note);
-appendResetable(stream, "name", conf.realName); // TODO: name -> realName
-appendResetable(stream, "address", conf.address);
-appendResetable(stream, "email", conf.email);
-appendResetable(stream, "phone", conf.phone);
-appendResetable(stream, "group", conf.group);
+appendResetable(stream, "note", MaybeEncode(MaybeIconv(conf.note, encoding, "koi8-ru")));
+appendResetable(stream, "name", MaybeEncode(MaybeIconv(conf.realName, encoding, "koi8-ru"))); // TODO: name -> realName
+appendResetable(stream, "address", MaybeEncode(MaybeIconv(conf.address, encoding, "koi8-ru")));
+appendResetable(stream, "email", MaybeEncode(MaybeIconv(conf.email, encoding, "koi8-ru")));
+appendResetable(stream, "phone", MaybeEncode(MaybeIconv(conf.phone, encoding, "cp1251")));
+appendResetable(stream, "group", MaybeEncode(MaybeIconv(conf.group, encoding, "koi8-ru")));
+appendResetable(stream, "corp", conf.corp);
 
 for (size_t i = 0; i < conf.userdata.size(); ++i)
-    appendResetable(stream, "userdata", i, conf.userdata[i]);
+    appendResetable(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=\"" << stat.cashAdd.data().second << "\"/>";
+    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.cashAdd.data().first << "\" msg=\"" << stat.cashAdd.data().second << "\"/>";
+    stream << "<cash set=\"" << stat.cashSet.data().first << "\" msg=\"" << IconvString(Encode12str(stat.cashSet.data().second), encoding, "koi8-ru") << "\"/>";
 
 appendResetable(stream, "freeMb", stat.freeMb);
 
@@ -126,5 +138,6 @@ std::string traffData = traff.str();
 if (!traffData.empty())
     stream << "<traff" << traffData << "/>";
 
+std::cerr << stream.str() << "\n";
 return stream.str();
 }
index 9f8e6b031bdca9b7539d74d301f2b9e498ee5262..9ac559e043738906b517ebceda7a37a97e81a7c5 100644 (file)
@@ -37,19 +37,21 @@ namespace CHG_USER
 class PARSER: public STG::PARSER
 {
 public:
-    PARSER(SIMPLE::CALLBACK f, void * data);
+    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);
+std::string Serialize(const USER_CONF_RES & conf, const USER_STAT_RES & stat, const std::string & encoding);
 
 } // namespace CHG_USER
 } // namespace STG
index 41217dfb4408c69be298a204f5bab0129cf66019..3d0e135efa6a13f878d9d1ecb15469bf9e8a7c59 100644 (file)
@@ -34,10 +34,10 @@ namespace STG
 
 template <>
 inline
-bool GetValue<PRIV>(const char ** attr, PRIV & value)
+bool GetValue<PRIV>(const char ** attr, PRIV & value, const std::string & attrName)
 {
 uint32_t priv;
-if (!GetValue(attr, priv))
+if (!GetValue(attr, priv, attrName))
     return false;
 value = priv;
 return true;
@@ -45,9 +45,10 @@ return true;
 
 } // namespace STG
 
-GET_ADMIN::PARSER::PARSER(CALLBACK f, void * d)
+GET_ADMIN::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0),
       parsingAnswer(false)
 {
@@ -69,8 +70,8 @@ depth++;
 if (depth == 1)
     ParseAdmin(el, attr);
 
-if (depth == 2 && parsingAnswer)
-    ParseAdminParams(el, attr);
+/*if (depth == 2 && parsingAnswer)
+    ParseAdminParams(el, attr);*/
 
 return 0;
 }
@@ -101,15 +102,23 @@ if (strcasecmp(el, "admin") == 0)
                 error = "Admin not found.";
             }
         else
+            {
             parsingAnswer = true;
+            for (const char ** pos = attr; *pos != NULL; pos = pos + 2)
+                if (!TryParse(propertyParsers, ToLower(*pos), pos, *pos))
+                    {
+                    error = std::string("Invalid parameter '") + *pos + "'.";
+                    break;
+                    }
+            }
         }
     else
         parsingAnswer = true;
     }
 }
 //-----------------------------------------------------------------------------
-void GET_ADMIN::PARSER::ParseAdminParams(const char * el, const char ** attr)
+/*void GET_ADMIN::PARSER::ParseAdminParams(const char * el, const char ** attr)
 {
 if (!TryParse(propertyParsers, ToLower(el), attr))
     error = "Invalid parameter.";
-}
+}*/
index d8e2fe9ea0c795caf466c5d8db0ed10777150fd5..f7cb3084dd1d0430ce7084bd4d0fbcf550278522 100644 (file)
@@ -39,22 +39,24 @@ class PARSER: public STG::PARSER
 public:
     typedef GET_ADMIN::INFO INFO;
 
-    PARSER(CALLBACK f, void * data);
+    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);
+    //void ParseAdminParams(const char * el, const char ** attr);
 };
 
 } // namespace GET_ADMIN
index c07e9e14469aee806e56e561e44e829d544c32ca..cbfd1eaddc32afb61cbefee8b328a00e91847a5d 100644 (file)
@@ -38,9 +38,9 @@ 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)
-        : tag(t), callback(f), data(d),
-          elementParser(&PARSER<ELEMENT_PARSER>::ElementCallback, this),
+    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)
@@ -69,11 +69,13 @@ public:
         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;
index 339d1eb2f6ccc9f80b8a817a4f06ba537b530f4c..732a4d697abab779aa37f950944512833d3c3fb1 100644 (file)
 
 using namespace STG;
 
-GET_CORP::PARSER::PARSER(CALLBACK f, void * d)
+GET_CORP::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0),
       parsingAnswer(false)
 {
@@ -92,6 +93,6 @@ if (strcasecmp(el, "corp") == 0)
 //-----------------------------------------------------------------------------
 void GET_CORP::PARSER::ParseCorpParams(const char * el, const char ** attr)
 {
-if (!TryParse(propertyParsers, ToLower(el), attr))
+if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
     error = "Invalid parameter.";
 }
index a01fe2629d7744a8abaa9a16026779a9aa2412d5..b9d879833dad252cedcc8176fbd78dd32dbe949d 100644 (file)
@@ -39,16 +39,18 @@ class PARSER: public STG::PARSER
 public:
     typedef GET_CORP::INFO INFO;
 
-    PARSER(CALLBACK f, void * data);
+    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;
index 105b7395b4bac239f79bde6cf62f7cf731216210..6f98fc23fe2f5a04cf3d244a2584cde23ab0e45a 100644 (file)
 
 using namespace STG;
 
-GET_SERVICE::PARSER::PARSER(CALLBACK f, void * d)
+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);
+    AddParser(propertyParsers, "comment", info.comment, GetEncodedValue);
     AddParser(propertyParsers, "cost", info.cost);
     AddParser(propertyParsers, "payDay", info.payDay);
 }
@@ -94,6 +95,6 @@ if (strcasecmp(el, "service") == 0)
 //-----------------------------------------------------------------------------
 void GET_SERVICE::PARSER::ParseServiceParams(const char * el, const char ** attr)
 {
-if (!TryParse(propertyParsers, ToLower(el), attr))
+if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
     error = "Invalid parameter.";
 }
index 847d8bfda6c1af56d183e3c88e6cf6941ddb1c47..fe29ec09daaf463e0684991c7eebd99b9c21b0ab 100644 (file)
@@ -38,16 +38,18 @@ class PARSER: public STG::PARSER
 {
 public:
     typedef GET_SERVICE::INFO INFO;
-    PARSER(CALLBACK f, void * data);
+    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;
index e861843e3ee1157f750e6fb6dd3f0f3f8835e93c..0ffaabb6c02c17119a69ecf38c3b885fbf762524 100644 (file)
@@ -39,7 +39,7 @@ 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) { return func(attr, array, field); }
+        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;
@@ -53,13 +53,13 @@ void AddAOSParser(PROPERTY_PARSERS & parsers, const std::string & name, A & arra
     parsers.insert(std::make_pair(ToLower(name), new AOS_PARSER<A, T>(array, field, func)));
 }
 
-bool GetTimeSpan(const char ** attr, DIRPRICE_DATA & value)
+bool GetTimeSpan(const char ** attr, DIRPRICE_DATA & value, const std::string & attrName)
 {
 int hb = 0;
 int mb = 0;
 int he = 0;
 int me = 0;
-if (CheckValue(attr))
+if (CheckValue(attr, attrName))
     if (ParseTariffTimeStr(attr[1], hb, mb, he, me) == 0)
         {
         value.hDay = hb;
@@ -72,9 +72,9 @@ return false;
 }
 
 template <typename T>
-bool GetTraffType(const char ** attr, T & value)
+bool GetTraffType(const char ** attr, T & value, const std::string & attrName)
 {
-if (!CheckValue(attr))
+if (!CheckValue(attr, attrName))
     return false;
 std::string type(attr[1]);
 if (type == "up")
@@ -90,10 +90,25 @@ else
 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 A, typename T>
 bool GetSlashedValue(const char ** attr, A & array, T A::value_type:: * field)
 {
-if (!CheckValue(attr))
+if (!CheckValue(attr, "value"))
     return false;
 const char * start = attr[1];
 size_t item = 0;
@@ -112,9 +127,10 @@ return true;
 
 } // namespace anonymous
 
-GET_TARIFF::PARSER::PARSER(CALLBACK f, void * d)
+GET_TARIFF::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0),
       parsingAnswer(false)
 {
@@ -122,6 +138,7 @@ GET_TARIFF::PARSER::PARSER(CALLBACK f, void * d)
     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);
     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);
@@ -178,7 +195,11 @@ if (strcasecmp(el, "tariff") == 0)
                 error = "Tariff not found.";
             }
         else
+            {
             parsingAnswer = true;
+            if (strcasecmp(attr[0], "name") == 0)
+                info.tariffConf.name = attr[1];
+            }
         }
     else
         parsingAnswer = true;
@@ -187,6 +208,6 @@ if (strcasecmp(el, "tariff") == 0)
 //-----------------------------------------------------------------------------
 void GET_TARIFF::PARSER::ParseTariffParams(const char * el, const char ** attr)
 {
-if (!TryParse(propertyParsers, ToLower(el), attr))
-    error = "Invalid parameter.";
+if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
+    error = std::string("Invalid parameter '") + el + "'.";
 }
index e6558259dd4a78ee7a3196aa41162b432a886a9c..be78fdbd114dde6c7c584d0a1969f153b0bdd39a 100644 (file)
@@ -39,15 +39,17 @@ class PARSER: public STG::PARSER
 public:
     typedef GET_TARIFF::INFO INFO;
 
-    PARSER(CALLBACK f, void * data);
+    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;
index 54cfc0f95f8a873df573043229bf3615b87557e5..03327c4dc588a6f9c4d2c86fbcb2d373957ea4d2 100644 (file)
@@ -34,7 +34,7 @@ namespace STG
 {
 
 template <>
-bool GetValue<GET_USER::STAT>(const char ** attr, GET_USER::STAT & value)
+bool GetValue<GET_USER::STAT>(const char ** attr, GET_USER::STAT & value, const std::string & /*attrName*/)
 {
 if (!attr)
     return false;
@@ -60,9 +60,10 @@ return true;
 
 }
 
-GET_USER::PARSER::PARSER(CALLBACK f, void * d)
+GET_USER::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0),
       parsingAnswer(false)
 {
@@ -71,26 +72,30 @@ GET_USER::PARSER::PARSER(CALLBACK f, void * d)
     AddParser(propertyParsers, "cash", info.cash);
     AddParser(propertyParsers, "credit", info.credit);
     AddParser(propertyParsers, "creditExpire", info.creditExpire);
-    AddParser(propertyParsers, "lastCash", info.lastCash);
-    AddParser(propertyParsers, "prepaidTraff", info.prepaidTraff);
-    AddParser(propertyParsers, "down", info.down);
+    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, "connected", info.connected);
+    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, GetEncodedValue);
-    AddParser(propertyParsers, "note", info.note, GetEncodedValue);
-    AddParser(propertyParsers, "email", info.email, GetEncodedValue);
-    AddParser(propertyParsers, "name", info.name, GetEncodedValue);
-    AddParser(propertyParsers, "address", info.address, GetEncodedValue);
-    AddParser(propertyParsers, "phone", info.phone, GetEncodedValue);
+    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], GetEncodedValue);
+        AddParser(propertyParsers, "userData" + unsigned2str(i), info.userData[i], "koi8-ru", GetEncodedValue);
 }
 //-----------------------------------------------------------------------------
 GET_USER::PARSER::~PARSER()
@@ -109,6 +114,12 @@ if (depth == 1)
 if (depth == 2 && parsingAnswer)
     ParseUserParams(el, attr);
 
+if (depth == 3 && parsingAnswer)
+    {
+    ParseAuthBy(el, attr);
+    ParseServices(el, attr);
+    }
+
 return 0;
 }
 //-----------------------------------------------------------------------------
@@ -137,16 +148,35 @@ if (strcasecmp(el, "user") == 0)
             else
                 error = "User not found.";
             }
-        else
-            parsingAnswer = true;
+        else if (strcasecmp(attr[0], "login") == 0 && attr[1])
+            info.login = attr[1];
         }
-    else
-        parsingAnswer = true;
+    parsingAnswer = true;
     }
 }
 //-----------------------------------------------------------------------------
 void GET_USER::PARSER::ParseUserParams(const char * el, const char ** attr)
 {
-if (!TryParse(propertyParsers, ToLower(el), 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]);
 }
index 519d67b6587c0a0425b89cb3d40542b03d1699d4..a0e3e3a4a8eaab59ebd8a60d9d0796eaeee133be 100644 (file)
@@ -39,15 +39,17 @@ class PARSER: public STG::PARSER
 public:
     typedef GET_USER::INFO INFO;
 
-    PARSER(CALLBACK f, void * data);
+    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;
@@ -55,6 +57,8 @@ private:
 
     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
index 8a78fe76593a2336178db51a58892588940b542c..eb9c2dfb66eb4d41d0df0e00a8db388da4d2c75b 100644 (file)
 
 #include <strings.h>
 
-bool STG::CheckValue(const char ** attr)
+bool STG::CheckValue(const char ** attr, const std::string & attrName)
 {
-return attr && attr[0] && attr[1] && strcasecmp(attr[0], "value") == 0;
+return attr && attr[0] && attr[1] && strcasecmp(attr[0], attrName.c_str()) == 0;
 }
 
-bool STG::GetEncodedValue(const char ** attr, std::string & value)
+bool STG::GetEncodedValue(const char ** attr, std::string & value, const std::string & attrName)
 {
-if (!CheckValue(attr))
+if (!CheckValue(attr, attrName))
     return false;
 Decode21str(value, attr[1]);
 return true;
 }
 
-bool STG::GetIPValue(const char ** attr, uint32_t & value)
+bool STG::GetIPValue(const char ** attr, uint32_t & value, const std::string & attrName)
 {
-if (!CheckValue(attr))
+if (!CheckValue(attr, attrName))
     return false;
 std::string ip(attr[1]);
 value = inet_strington(attr[1]);
@@ -46,10 +46,10 @@ if (value == 0 && ip != "0.0.0.0")
 return true;
 }
 
-bool STG::TryParse(PROPERTY_PARSERS & parsers, const std::string & name, const char ** attr)
+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);
+        return it->second->Parse(attr, attrName, toEncoding);
     return true; // Assume that non-existing params are ok.
 }
index 3469b9873fe8c04f46274f319a201d7008382945..7aa98aebca16fbe057f798b0c942fb9fc8331ff1 100644 (file)
@@ -33,30 +33,48 @@ class BASE_PROPERTY_PARSER
 {
     public:
         virtual ~BASE_PROPERTY_PARSER() {}
-        virtual bool Parse(const char ** attr) = 0;
+        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 &);
+        typedef bool (* FUNC)(const char **, T &, const std::string &);
         PROPERTY_PARSER(T & v, FUNC f) : value(v), func(f) {}
-        virtual bool Parse(const char ** attr) { return func(attr, value); }
+        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);
+bool CheckValue(const char ** attr, const std::string & attrName);
 
 template <typename T>
 inline
-bool GetValue(const char ** attr, T & value)
+bool GetValue(const char ** attr, T & value, const std::string & attrName)
 {
-if (CheckValue(attr))
+if (CheckValue(attr, attrName))
     if (str2x(attr[1], value) < 0)
         return false;
 return true;
@@ -64,9 +82,9 @@ return true;
 
 template <>
 inline
-bool GetValue<std::string>(const char ** attr, std::string & value)
+bool GetValue<std::string>(const char ** attr, std::string & value, const std::string & attrName)
 {
-if (!CheckValue(attr))
+if (!CheckValue(attr, attrName))
     return false;
 value = attr[1];
 return true;
@@ -74,29 +92,33 @@ return true;
 
 template <>
 inline
-bool GetValue<double>(const char ** attr, double & value)
+bool GetValue<double>(const char ** attr, double & value, const std::string & attrName)
 {
-if (CheckValue(attr))
+if (CheckValue(attr, attrName))
     if (strtodouble2(attr[1], value))
         return false;
 return true;
 }
 
-bool GetEncodedValue(const char ** attr, std::string & value);
+bool GetEncodedValue(const char ** attr, std::string & value, const std::string & attrName);
 
-bool GetIPValue(const char ** attr, uint32_t& value);
+bool GetIPValue(const char ** attr, uint32_t& value, const std::string & attrName);
 
 template <typename T>
-void AddParser(PROPERTY_PARSERS & parsers, const std::string & name, T & value, const typename PROPERTY_PARSER<T>::FUNC & func = GetValue<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 typename PROPERTY_PARSER<T>::FUNC & func)
+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)));
+    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);
+bool TryParse(PROPERTY_PARSERS & parsers, const std::string & name, const char ** attr, const std::string & fromEncoding, const std::string & attrName = "value");
 
 } // namespace STG
 
index ed1cd305112db475e282c3fb928e17c8de56fd74..088cb327e0ac22cfff35722ffe4f2cee39b4cc5b 100644 (file)
@@ -22,6 +22,7 @@
 #define __STG_STGLIBS_SRVCONF_RESETABLE_UTILS_H__
 
 #include "stg/resetable.h"
+#include "stg/common.h"
 
 #include <string>
 #include <ostream>
@@ -30,6 +31,7 @@ namespace STG
 {
 
 template <typename T>
+inline
 void appendResetable(std::ostream & stream, const std::string & name, const T & value)
 {
 if (!value.empty())
@@ -37,12 +39,31 @@ if (!value.empty())
 }
 
 template <typename T>
+inline
 void appendResetable(std::ostream & stream, const std::string & name, size_t suffix, const T & value)
 {
 if (!value.empty())
     stream << "<" << name << suffix << " value=\"" << value.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
index fbefb2d45ae0049de569c2d437060325c0b9f32c..50dbb2ccc7e4ad0a63a4be2d067b1f6ebadb00cc 100644 (file)
@@ -38,9 +38,10 @@ const size_t DIRNAME_LEN  = 16;
 
 }
 
-SERVER_INFO::PARSER::PARSER(CALLBACK f, void * d)
+SERVER_INFO::PARSER::PARSER(CALLBACK f, void * d, const std::string & e)
     : callback(f),
       data(d),
+      encoding(e),
       depth(0),
       parsingAnswer(false)
 {
@@ -66,7 +67,7 @@ if (depth == 1)
 else
     {
     if (depth == 2 && parsingAnswer)
-        if (!TryParse(propertyParsers, ToLower(el), attr))
+        if (!TryParse(propertyParsers, ToLower(el), attr, encoding))
             error = "Invalid parameter.";
     }
 return 0;
index 7f5b8e9b978e6b9584630f41e90541ad48ed3ed9..039063890866bac13f783a1ef15bd9407ea1938b 100644 (file)
@@ -37,14 +37,16 @@ namespace SERVER_INFO
 class PARSER: public STG::PARSER
 {
 public:
-    PARSER(CALLBACK f, void * data);
+    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;
index 89537f2cc143adb11be1df18594811b49bacb749..4749c70f3a1ceaf812690ce4b49781172601d161 100644 (file)
 
 using namespace STG;
 
-SIMPLE::PARSER::PARSER(const std::string & t, CALLBACK f, void * d)
+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)
 {
 }
index 03c950bccb6222012d8e02bc7a898bc33b03f315..244e8ef08eef544193510b844da534870c7b0461 100644 (file)
@@ -35,14 +35,16 @@ namespace SIMPLE
 class PARSER: public STG::PARSER
 {
 public:
-    PARSER(const std::string & tag, CALLBACK f, void * data);
+    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);
index c7bf3d0091b2b026948d30eee26528a8ac8bf941..4c69c813da26bf8d066ddfa89e33a8be2801a6aa 100644 (file)
 
 #include <cstdio>
 #include <cstring>
+#include <clocale>
 
 #include <expat.h>
+#include <langinfo.h>
 
 using namespace STG;
 
@@ -60,6 +62,9 @@ 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;
@@ -71,20 +76,23 @@ public:
     template <class P, typename C>
     int Exec(const std::string & request, C callback, void * data)
     {
-        P cp(callback, data);
+        P cp(callback, data, encoding);
         return ExecImpl(request, cp);
     }
 
     template <class P, typename C>
     int Exec(const std::string & tag, const std::string & request, C callback, void * data)
     {
-        P cp(tag, callback, data);
+        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;
 
@@ -121,6 +129,13 @@ SERVCONF::SERVCONF(const std::string & server, uint16_t port,
 {
 }
 
+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))
+{
+}
+
 SERVCONF::~SERVCONF()
 {
 delete pImpl;
@@ -150,7 +165,7 @@ return pImpl->Exec<GET_ADMIN::PARSER>("<GetAdmin login=\"" + login + "\"/>", f,
 
 int SERVCONF::ChgAdmin(const ADMIN_CONF_RES & conf, SIMPLE::CALLBACK f, void * data)
 {
-return pImpl->Exec<SIMPLE::PARSER>("ChgAdmin", "<ChgAdmin" + CHG_ADMIN::Serialize(conf) + "/>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("ChgAdmin", "<ChgAdmin" + CHG_ADMIN::Serialize(conf, pImpl->Encoding()) + "/>", f, data);
 }
 
 int SERVCONF::AddAdmin(const std::string & login,
@@ -160,7 +175,7 @@ int SERVCONF::AddAdmin(const std::string & login,
 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) + "/>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("ChgAdmin", "<ChgAdmin" + CHG_ADMIN::Serialize(conf, pImpl->Encoding()) + "/>", f, data);
 }
 
 int SERVCONF::DelAdmin(const std::string & login, SIMPLE::CALLBACK f, void * data)
@@ -182,7 +197,7 @@ return pImpl->Exec<GET_TARIFF::PARSER>("<GetTariff name=\"" + name + "\"/>", f,
 
 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) + "</SetTariff>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SetTariff", "<SetTariff name=\"" + tariffData.tariffConf.name.data() + "\">" + CHG_TARIFF::Serialize(tariffData, pImpl->Encoding()) + "</SetTariff>", f, data);
 }
 
 int SERVCONF::AddTariff(const std::string & name,
@@ -192,7 +207,7 @@ int SERVCONF::AddTariff(const std::string & name,
 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) + "</SetTariff>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SetTariff", "<SetTariff name=\"" + name + "\">" + CHG_TARIFF::Serialize(tariffData, pImpl->Encoding()) + "</SetTariff>", f, data);
 }
 
 int SERVCONF::DelTariff(const std::string & name, SIMPLE::CALLBACK f, void * data)
@@ -217,7 +232,7 @@ int SERVCONF::ChgUser(const std::string & login,
                       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) + "</SetUser>", f, data);
+return pImpl->Exec<CHG_USER::PARSER>("<SetUser><Login value=\"" + login + "\"/>" + CHG_USER::Serialize(conf, stat, pImpl->Encoding()) + "</SetUser>", f, data);
 }
 
 int SERVCONF::DelUser(const std::string & login, SIMPLE::CALLBACK f, void * data)
@@ -225,9 +240,15 @@ int SERVCONF::DelUser(const std::string & login, SIMPLE::CALLBACK f, void * data
 return pImpl->Exec<SIMPLE::PARSER>("DelUser", "<DelUser login=\"" + login + "\"/>", f, data);
 }
 
-int SERVCONF::AddUser(const std::string & login, SIMPLE::CALLBACK f, void * data)
+int SERVCONF::AddUser(const std::string & login,
+                      const USER_CONF_RES & conf,
+                      const USER_STAT_RES & stat,
+                      SIMPLE::CALLBACK f, void * data)
 {
-return pImpl->Exec<SIMPLE::PARSER>("AddUser", "<AddUser><Login value=\"" + login + "\"/></AddUser>", f, 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);
 }
 
 int SERVCONF::AuthBy(const std::string & login, AUTH_BY::CALLBACK f, void * data)
@@ -237,7 +258,7 @@ return pImpl->Exec<AUTH_BY::PARSER>("<GetUserAuthBy login=\"" + login + "\"/>",
 
 int SERVCONF::SendMessage(const std::string & login, const std::string & text, SIMPLE::CALLBACK f, void * data)
 {
-return pImpl->Exec<SIMPLE::PARSER>("SendMessage", "<Message login=\"" + login + "\" msgver=\"1\" msgtype=\"1\" repeat=\"0\" repeatperiod=\"0\" showtime=\"0\" text=\"" + Encode12str(text) + "\"/>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SendMessageResult", "<Message login=\"" + login + "\" msgver=\"1\" msgtype=\"1\" repeat=\"0\" repeatperiod=\"0\" showtime=\"0\" text=\"" + Encode12str(text) + "\"/>", f, data);
 }
 
 int SERVCONF::CheckUser(const std::string & login, const std::string & password, SIMPLE::CALLBACK f, void * data)
@@ -259,7 +280,7 @@ return pImpl->Exec<GET_SERVICE::PARSER>("<GetService name=\"" + name + "\"/>", f
 
 int SERVCONF::ChgService(const SERVICE_CONF_RES & conf, SIMPLE::CALLBACK f, void * data)
 {
-return pImpl->Exec<SIMPLE::PARSER>("SetService", "<SetService name=\"" + conf.name.data() + "\">" + CHG_SERVICE::Serialize(conf) + "</SetService>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SetService", "<SetService name=\"" + conf.name.data() + "\">" + CHG_SERVICE::Serialize(conf, pImpl->Encoding()) + "</SetService>", f, data);
 }
 
 int SERVCONF::AddService(const std::string & name,
@@ -269,7 +290,7 @@ int SERVCONF::AddService(const std::string & name,
 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 name=\"" + name + "\">" + CHG_SERVICE::Serialize(conf) + "</SetService>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SetService", "<SetService name=\"" + name + "\">" + CHG_SERVICE::Serialize(conf, pImpl->Encoding()) + "</SetService>", f, data);
 }
 
 int SERVCONF::DelService(const std::string & name, SIMPLE::CALLBACK f, void * data)
@@ -291,7 +312,7 @@ return pImpl->Exec<GET_CORP::PARSER>("<GetCorp name=\"" + name + "\"/>", f, data
 
 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) + "</SetCorp>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SetCorp", "<SetCorp name=\"" + conf.name.data() + "\">" + CHG_CORP::Serialize(conf, pImpl->Encoding()) + "</SetCorp>", f, data);
 }
 
 int SERVCONF::AddCorp(const std::string & name,
@@ -301,7 +322,7 @@ int SERVCONF::AddCorp(const std::string & name,
 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) + "</SetCorp>", f, data);
+return pImpl->Exec<SIMPLE::PARSER>("SetCorp", "<SetCorp name=\"" + name + "\">" + CHG_CORP::Serialize(conf, pImpl->Encoding()) + "</SetCorp>", f, data);
 }
 
 int SERVCONF::DelCorp(const std::string & name, SIMPLE::CALLBACK f, void * data)
@@ -317,8 +338,20 @@ return pImpl->GetStrError();
 //-----------------------------------------------------------------------------
 SERVCONF::IMPL::IMPL(const std::string & server, uint16_t port,
                      const std::string & login, const std::string & password)
-    : nt( server, port, login, password )
+    : nt(server, port, login, password)
+{
+setlocale(LC_ALL, "");
+encoding = nl_langinfo(CODESET);
+parser = XML_ParserCreate(NULL);
+}
+//-----------------------------------------------------------------------------
+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)
 {
+setlocale(LC_ALL, "");
+encoding = nl_langinfo(CODESET);
 parser = XML_ParserCreate(NULL);
 }
 //-----------------------------------------------------------------------------
@@ -349,11 +382,13 @@ int ret = 0;
 if ((ret = nt.Connect()) != st_ok)
     {
     errorMsg = nt.GetError();
+    cp.Failure(errorMsg);
     return ret;
     }
 if ((ret = nt.Transact(request, ParserRecv, this)) != st_ok)
     {
     errorMsg = nt.GetError();
+    cp.Failure(errorMsg);
     return ret;
     }