]> git.stg.codes - stg.git/commitdiff
Добавление исходников
authorMaxim Mamontov <faust.madf@gmail.com>
Sun, 7 Nov 2010 09:20:26 +0000 (11:20 +0200)
committerMaxim Mamontov <faust.madf@gmail.com>
Sun, 7 Nov 2010 09:20:26 +0000 (11:20 +0200)
457 files changed:
.gitignore [new file with mode: 0644]
include/Makefile [new file with mode: 0644]
include/admin_conf.h [new file with mode: 0644]
include/admin_conf.inc.h [new file with mode: 0644]
include/base_auth.h [new file with mode: 0644]
include/base_db.h [new file with mode: 0644]
include/base_plugin.h [new file with mode: 0644]
include/base_settings.h [new file with mode: 0644]
include/base_store.h [new file with mode: 0644]
include/corp_conf.h [new file with mode: 0644]
include/ia_packets.h [new file with mode: 0644]
include/ibpp.h [new file with mode: 0644]
include/lp2_blocks.h [new file with mode: 0644]
include/mimetype.h [new file with mode: 0644]
include/noncopyable.h [new file with mode: 0644]
include/notifer.h [new file with mode: 0644]
include/os_int.h [new file with mode: 0644]
include/rad_packets.h [new file with mode: 0644]
include/raw_ip_packet.h [new file with mode: 0644]
include/resetable.h [new file with mode: 0644]
include/rs_packets.h [new file with mode: 0644]
include/service_conf.h [new file with mode: 0644]
include/stdstring.h [new file with mode: 0644]
include/stg_common.h [new file with mode: 0644]
include/stg_comp_stat.h [new file with mode: 0644]
include/stg_const.h [new file with mode: 0644]
include/stg_int.h [new file with mode: 0644]
include/stg_message.h [new file with mode: 0644]
include/tariff_conf.h [new file with mode: 0644]
include/user_conf.h [new file with mode: 0644]
include/user_ips.h [new file with mode: 0644]
include/user_stat.h [new file with mode: 0644]
include/user_traff.h [new file with mode: 0644]
include/utime.h [new file with mode: 0644]
include/version.h [new file with mode: 0644]
include/vpn_stg_packets.h [new file with mode: 0644]
projects/convertor/Makefile [new file with mode: 0644]
projects/convertor/build [new file with mode: 0755]
projects/convertor/convertor.conf [new file with mode: 0644]
projects/convertor/main.cpp [new file with mode: 0644]
projects/convertor/settings.cpp [new file with mode: 0644]
projects/convertor/settings.h [new file with mode: 0644]
projects/make_tarball/get_from_cvs [new file with mode: 0755]
projects/make_tarball/mt.sh [new file with mode: 0755]
projects/rlm_stg/Makefile [new file with mode: 0644]
projects/rlm_stg/build [new file with mode: 0755]
projects/rlm_stg/build_check.c [new file with mode: 0644]
projects/rlm_stg/conf.h [new file with mode: 0644]
projects/rlm_stg/conffile.h [new file with mode: 0644]
projects/rlm_stg/event.h [new file with mode: 0644]
projects/rlm_stg/libradius.h [new file with mode: 0644]
projects/rlm_stg/modules.h [new file with mode: 0644]
projects/rlm_stg/radiusd.h [new file with mode: 0644]
projects/rlm_stg/realms.h [new file with mode: 0644]
projects/rlm_stg/rlm_stg.cpp [new file with mode: 0644]
projects/rlm_stg/stats.h [new file with mode: 0644]
projects/rlm_stg/stg_client.cpp [new file with mode: 0644]
projects/rlm_stg/stg_client.h [new file with mode: 0644]
projects/rscriptd/Makefile [new file with mode: 0644]
projects/rscriptd/build [new file with mode: 0755]
projects/rscriptd/listener.cpp [new file with mode: 0644]
projects/rscriptd/listener.h [new file with mode: 0644]
projects/rscriptd/main.cpp [new file with mode: 0644]
projects/rscriptd/pidfile.cpp [new file with mode: 0644]
projects/rscriptd/pidfile.h [new file with mode: 0644]
projects/rscriptd/rscriptd.conf [new file with mode: 0644]
projects/sgauth/Makefile [new file with mode: 0644]
projects/sgauth/build [new file with mode: 0755]
projects/sgauth/main.cpp [new file with mode: 0644]
projects/sgauth/make_css.sh [new file with mode: 0755]
projects/sgauth/readme [new file with mode: 0644]
projects/sgauth/sgauth.conf [new file with mode: 0644]
projects/sgauth/sgauth.css [new file with mode: 0644]
projects/sgauth/web.cpp [new file with mode: 0644]
projects/sgauth/web.h [new file with mode: 0644]
projects/sgconf/CHANGES [new file with mode: 0644]
projects/sgconf/Makefile [new file with mode: 0644]
projects/sgconf/README.txt [new file with mode: 0644]
projects/sgconf/build [new file with mode: 0755]
projects/sgconf/common_sg.cpp [new file with mode: 0644]
projects/sgconf/common_sg.h [new file with mode: 0644]
projects/sgconf/main.cpp [new file with mode: 0644]
projects/sgconf/parser.cpp [new file with mode: 0644]
projects/sgconf/request.h [new file with mode: 0644]
projects/sgconf/sg_error_codes.h [new file with mode: 0644]
projects/sgconf/sgconfg [new file with mode: 0755]
projects/sgconf/sgconfs [new file with mode: 0755]
projects/sgconf/sginfo.cpp [new file with mode: 0644]
projects/sgconf/version_sg.h [new file with mode: 0644]
projects/stargazer/.#Makefile.1.45 [new file with mode: 0644]
projects/stargazer/BUGS [new file with mode: 0644]
projects/stargazer/CHANGES [new file with mode: 0644]
projects/stargazer/Makefile [new file with mode: 0644]
projects/stargazer/README [new file with mode: 0644]
projects/stargazer/TODO [new file with mode: 0644]
projects/stargazer/actions.h [new file with mode: 0644]
projects/stargazer/actions.inl.h [new file with mode: 0644]
projects/stargazer/admin.cpp [new file with mode: 0644]
projects/stargazer/admin.h [new file with mode: 0644]
projects/stargazer/admins.cpp [new file with mode: 0644]
projects/stargazer/admins.h [new file with mode: 0644]
projects/stargazer/build [new file with mode: 0755]
projects/stargazer/devbuild [new file with mode: 0755]
projects/stargazer/eventloop.cpp [new file with mode: 0644]
projects/stargazer/eventloop.h [new file with mode: 0644]
projects/stargazer/inst/freebsd/etc/stargazer/OnChange [new file with mode: 0755]
projects/stargazer/inst/freebsd/etc/stargazer/OnConnect [new file with mode: 0755]
projects/stargazer/inst/freebsd/etc/stargazer/OnDisconnect [new file with mode: 0755]
projects/stargazer/inst/freebsd/etc/stargazer/OnUserAdd [new file with mode: 0755]
projects/stargazer/inst/freebsd/etc/stargazer/OnUserDel [new file with mode: 0755]
projects/stargazer/inst/freebsd/etc/stargazer/rules [new file with mode: 0644]
projects/stargazer/inst/freebsd/etc/stargazer/stargazer.conf [new file with mode: 0644]
projects/stargazer/inst/linux/etc/init.d/stargazer.gentoo.2007 [new file with mode: 0755]
projects/stargazer/inst/linux/etc/init.d/stargazer.suse.9.3 [new file with mode: 0755]
projects/stargazer/inst/linux/etc/init.d/stargazer.ubuntu.7.10 [new file with mode: 0755]
projects/stargazer/inst/linux/etc/stargazer/OnChange [new file with mode: 0755]
projects/stargazer/inst/linux/etc/stargazer/OnConnect [new file with mode: 0755]
projects/stargazer/inst/linux/etc/stargazer/OnDisconnect [new file with mode: 0755]
projects/stargazer/inst/linux/etc/stargazer/OnUserAdd [new file with mode: 0755]
projects/stargazer/inst/linux/etc/stargazer/OnUserDel [new file with mode: 0755]
projects/stargazer/inst/linux/etc/stargazer/rules [new file with mode: 0644]
projects/stargazer/inst/linux/etc/stargazer/stargazer.conf [new file with mode: 0644]
projects/stargazer/inst/var/00-alter-01.postgresql.sql [new file with mode: 0644]
projects/stargazer/inst/var/00-alter-01.sql [new file with mode: 0644]
projects/stargazer/inst/var/00-base-00.postgresql.sql [new file with mode: 0644]
projects/stargazer/inst/var/00-base-00.sql [new file with mode: 0644]
projects/stargazer/inst/var/00-mysql-01.sql [new file with mode: 0644]
projects/stargazer/inst/var/base.dia [new file with mode: 0644]
projects/stargazer/inst/var/stargazer/admins/admin.adm [new file with mode: 0644]
projects/stargazer/inst/var/stargazer/tariffs/tariff.tf [new file with mode: 0644]
projects/stargazer/inst/var/stargazer/users/test/conf [new file with mode: 0644]
projects/stargazer/inst/var/stargazer/users/test/stat [new file with mode: 0644]
projects/stargazer/main.cpp [new file with mode: 0644]
projects/stargazer/pidfile.cpp [new file with mode: 0644]
projects/stargazer/pidfile.h [new file with mode: 0644]
projects/stargazer/plugin_runner.cpp [new file with mode: 0644]
projects/stargazer/plugin_runner.h [new file with mode: 0644]
projects/stargazer/plugins/Makefile [new file with mode: 0644]
projects/stargazer/plugins/Makefile.in [new file with mode: 0644]
projects/stargazer/plugins/authorization/ao/Makefile [new file with mode: 0644]
projects/stargazer/plugins/authorization/ao/ao.cpp [new file with mode: 0644]
projects/stargazer/plugins/authorization/ao/ao.h [new file with mode: 0644]
projects/stargazer/plugins/authorization/inetaccess/Makefile [new file with mode: 0644]
projects/stargazer/plugins/authorization/inetaccess/antiflood.cpp [new file with mode: 0644]
projects/stargazer/plugins/authorization/inetaccess/antiflood.h [new file with mode: 0644]
projects/stargazer/plugins/authorization/inetaccess/inetaccess.cpp [new file with mode: 0644]
projects/stargazer/plugins/authorization/inetaccess/inetaccess.h [new file with mode: 0644]
projects/stargazer/plugins/authorization/stress/Makefile [new file with mode: 0644]
projects/stargazer/plugins/authorization/stress/stress.cpp [new file with mode: 0644]
projects/stargazer/plugins/authorization/stress/stress.h [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/checksum.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/checksum.h [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/constants.h [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/debug_cap.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/debug_cap.h [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/icmp.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/ip.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/libpal.h [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/misc.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/packet.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/socket.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/tcp.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/types.h [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_debug/udp.c [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_nf/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/cap_nf/cap_nf.h [new file with mode: 0644]
projects/stargazer/plugins/capture/divert_freebsd/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/divert_freebsd/divert_cap.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/divert_freebsd/divert_cap.h [new file with mode: 0644]
projects/stargazer/plugins/capture/ether_freebsd/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/ether_freebsd/ether_cap.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/ether_freebsd/ether_cap.h [new file with mode: 0644]
projects/stargazer/plugins/capture/ether_linux/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/ether_linux/ether_cap.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/ether_linux/ether_cap.h [new file with mode: 0644]
projects/stargazer/plugins/capture/ipq_linux/.#ipq_cap.cpp.1.3 [new file with mode: 0644]
projects/stargazer/plugins/capture/ipq_linux/Makefile [new file with mode: 0644]
projects/stargazer/plugins/capture/ipq_linux/ipq_cap.cpp [new file with mode: 0644]
projects/stargazer/plugins/capture/ipq_linux/ipq_cap.h [new file with mode: 0644]
projects/stargazer/plugins/capture/ipq_linux/libipq.c [new file with mode: 0644]
projects/stargazer/plugins/capture/ipq_linux/libipq.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/Makefile [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/admins_methods.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/admins_methods.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/deps [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/info_methods.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/info_methods.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/messages_methods.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/messages_methods.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/tariffs_methods.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/tariffs_methods.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/user_helper.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/users_methods.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/utils.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/rpcconfig/utils.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/Makefile [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/configproto.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/configproto.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/net_configurator.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/net_configurator.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser_admin.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/parser_tariff.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/stgconfig.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig/stgconfig.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/Makefile [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/configproto.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/configproto.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/net_configurator.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/net_configurator.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/parser.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/parser.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/parser_admin.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/parser_tariff.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/proto.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/rsconf.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/stgconfig.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/sgconfig2/stgconfig.h [new file with mode: 0644]
projects/stargazer/plugins/configuration/xrconfig/Makefile [new file with mode: 0644]
projects/stargazer/plugins/configuration/xrconfig/xrconfig.cpp [new file with mode: 0644]
projects/stargazer/plugins/configuration/xrconfig/xrconfig.h [new file with mode: 0644]
projects/stargazer/plugins/other/ping/Makefile [new file with mode: 0644]
projects/stargazer/plugins/other/ping/ping.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/ping/ping.h [new file with mode: 0644]
projects/stargazer/plugins/other/radius/Makefile [new file with mode: 0644]
projects/stargazer/plugins/other/radius/radius.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/radius/radius.h [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/Makefile [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/nrmap_parser.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/nrmap_parser.h [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/rscript.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/rscript.h [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/send_functor.h [new file with mode: 0644]
projects/stargazer/plugins/other/rscript/ur_functor.h [new file with mode: 0644]
projects/stargazer/plugins/other/userstat/Makefile [new file with mode: 0644]
projects/stargazer/plugins/other/userstat/datathread.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/userstat/datathread.h [new file with mode: 0644]
projects/stargazer/plugins/other/userstat/userstat.cpp [new file with mode: 0644]
projects/stargazer/plugins/other/userstat/userstat.h [new file with mode: 0644]
projects/stargazer/plugins/store/db/.libs/pg_driver.la [new symlink]
projects/stargazer/plugins/store/db/Makefile [new file with mode: 0644]
projects/stargazer/plugins/store/db/pg_driver.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/db/pg_driver.h [new file with mode: 0644]
projects/stargazer/plugins/store/db/pg_driver.la [new file with mode: 0644]
projects/stargazer/plugins/store/db/pg_driver.lo [new file with mode: 0644]
projects/stargazer/plugins/store/db/test_pg_driver.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/files/Makefile [new file with mode: 0644]
projects/stargazer/plugins/store/files/file_store.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/files/file_store.h [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/Makefile [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/deps [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store.h [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_admins.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_corporations.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_messages.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_services.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_users.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/firebird_store_utils.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/firebird/mod_store_firebird.so [new file with mode: 0755]
projects/stargazer/plugins/store/mysql/.#mysql_store.cpp.1.3 [new file with mode: 0644]
projects/stargazer/plugins/store/mysql/.#mysql_store.h.1.1.1.1 [new file with mode: 0644]
projects/stargazer/plugins/store/mysql/Makefile [new file with mode: 0644]
projects/stargazer/plugins/store/mysql/deps [new file with mode: 0644]
projects/stargazer/plugins/store/mysql/mod_store_mysql.so [new file with mode: 0755]
projects/stargazer/plugins/store/mysql/mysql_store.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/mysql/mysql_store.h [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/Makefile [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store.h [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_admins.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_corporations.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_services.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp [new file with mode: 0644]
projects/stargazer/plugins/store/postgresql/postgresql_store_utils.h [new file with mode: 0644]
projects/stargazer/sandboxstart [new file with mode: 0755]
projects/stargazer/script_executer.cpp [new file with mode: 0644]
projects/stargazer/scripts/clean_db [new file with mode: 0755]
projects/stargazer/scripts/monitor [new file with mode: 0755]
projects/stargazer/scripts/shaper/OnConnect [new file with mode: 0755]
projects/stargazer/scripts/shaper/OnDisconnect [new file with mode: 0755]
projects/stargazer/scripts/shaper/Readme.txt [new file with mode: 0644]
projects/stargazer/scripts/shaper/shaper.sh [new file with mode: 0755]
projects/stargazer/scripts/shaper/shaper.stop.sh [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/Readme [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/firewall/firewall [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/freeradius/clients.conf [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/freeradius/radiusd.conf [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/ppp/ip-down.d/stg [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/ppp/ip-up.d/stg [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/ppp/pptpd-options [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/pptpd.conf [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/radiusclient/servers [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnChange [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnConnect [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnDisconnect [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnUserAdd [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnUserDel [new file with mode: 0755]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/rules [new file with mode: 0644]
projects/stargazer/scripts/shaper_vpn_radius/stargazer/stargazer.conf [new file with mode: 0644]
projects/stargazer/settings.cpp [new file with mode: 0644]
projects/stargazer/settings.h [new file with mode: 0644]
projects/stargazer/stargazer.vpj [new file with mode: 0644]
projects/stargazer/stargazer.vpw [new file with mode: 0644]
projects/stargazer/stargazer.vpwhistu [new file with mode: 0644]
projects/stargazer/startstg [new file with mode: 0755]
projects/stargazer/stg_timer.cpp [new file with mode: 0644]
projects/stargazer/stg_timer.h [new file with mode: 0644]
projects/stargazer/store_loader.cpp [new file with mode: 0644]
projects/stargazer/store_loader.h [new file with mode: 0644]
projects/stargazer/tariff.cpp [new file with mode: 0644]
projects/stargazer/tariff.h [new file with mode: 0644]
projects/stargazer/tariffs.cpp [new file with mode: 0644]
projects/stargazer/tariffs.h [new file with mode: 0644]
projects/stargazer/traffcounter.cpp [new file with mode: 0644]
projects/stargazer/traffcounter.h [new file with mode: 0644]
projects/stargazer/user.cpp [new file with mode: 0644]
projects/stargazer/user.h [new file with mode: 0644]
projects/stargazer/user_property.cpp [new file with mode: 0644]
projects/stargazer/user_property.h [new file with mode: 0644]
projects/stargazer/users.cpp [new file with mode: 0644]
projects/stargazer/users.h [new file with mode: 0644]
projects/traffcounter/Makefile [new file with mode: 0644]
projects/traffcounter/capturer_tc_iface.h [new file with mode: 0644]
projects/traffcounter/configure [new file with mode: 0755]
projects/traffcounter/lock.cpp [new file with mode: 0644]
projects/traffcounter/lock.h [new file with mode: 0644]
projects/traffcounter/logger.cpp [new file with mode: 0644]
projects/traffcounter/logger.h [new file with mode: 0644]
projects/traffcounter/rf_tester.cpp [new file with mode: 0644]
projects/traffcounter/rules [new file with mode: 0644]
projects/traffcounter/rules.cpp [new file with mode: 0644]
projects/traffcounter/rules.h [new file with mode: 0644]
projects/traffcounter/rules_finder.cpp [new file with mode: 0644]
projects/traffcounter/rules_finder.h [new file with mode: 0644]
projects/traffcounter/rules_tester.cpp [new file with mode: 0644]
projects/traffcounter/table [new file with mode: 0644]
projects/traffcounter/tc_packets.h [new file with mode: 0644]
projects/traffcounter/tc_tester.cpp [new file with mode: 0644]
projects/traffcounter/test_rules [new file with mode: 0644]
projects/traffcounter/test_rules_bad_address [new file with mode: 0644]
projects/traffcounter/test_rules_bad_dir [new file with mode: 0644]
projects/traffcounter/test_rules_bad_dir_prefix [new file with mode: 0644]
projects/traffcounter/test_rules_bad_dir_range [new file with mode: 0644]
projects/traffcounter/test_rules_bad_mask [new file with mode: 0644]
projects/traffcounter/test_rules_bad_port [new file with mode: 0644]
projects/traffcounter/test_rules_bad_proto [new file with mode: 0644]
projects/traffcounter/traffcounter.cpp [new file with mode: 0644]
projects/traffcounter/traffcounter.h [new file with mode: 0644]
projects/traffcounter/user_tc_iface.h [new file with mode: 0644]
projects/traffcounter/utils.cpp [new file with mode: 0644]
projects/traffcounter/utils.h [new file with mode: 0644]
stglibs/Makefile [new file with mode: 0644]
stglibs/Makefile.in [new file with mode: 0644]
stglibs/common.lib/Makefile [new file with mode: 0644]
stglibs/common.lib/common.bpf [new file with mode: 0644]
stglibs/common.lib/common.bpr [new file with mode: 0644]
stglibs/common.lib/common.cpp [new file with mode: 0644]
stglibs/common.lib/common.h [new file with mode: 0644]
stglibs/common.lib/debug.c [new file with mode: 0644]
stglibs/common.lib/debug.h [new file with mode: 0644]
stglibs/common.lib/stg_common.h [new file with mode: 0644]
stglibs/common.lib/stg_error.c [new file with mode: 0644]
stglibs/common.lib/stg_error.h [new file with mode: 0644]
stglibs/common.lib/stg_strptime.cpp [new file with mode: 0644]
stglibs/common.lib/test.cpp [new file with mode: 0644]
stglibs/common.lib/test.h [new file with mode: 0644]
stglibs/common_settings.lib/Makefile [new file with mode: 0644]
stglibs/common_settings.lib/common_settings.cpp [new file with mode: 0644]
stglibs/common_settings.lib/common_settings.h [new file with mode: 0644]
stglibs/conffiles.lib/Makefile [new file with mode: 0644]
stglibs/conffiles.lib/conffiles.cpp [new file with mode: 0644]
stglibs/conffiles.lib/conffiles.h [new file with mode: 0644]
stglibs/crypto.lib/Makefile [new file with mode: 0644]
stglibs/crypto.lib/ag_md5.cpp [new file with mode: 0644]
stglibs/crypto.lib/ag_md5.h [new file with mode: 0644]
stglibs/crypto.lib/blowfish.cpp [new file with mode: 0644]
stglibs/crypto.lib/blowfish.h [new file with mode: 0644]
stglibs/crypto.lib/crypto.bpf [new file with mode: 0644]
stglibs/crypto.lib/crypto.bpr [new file with mode: 0644]
stglibs/dotconfpp.lib/Makefile [new file with mode: 0644]
stglibs/dotconfpp.lib/dotconfpp.cpp [new file with mode: 0644]
stglibs/dotconfpp.lib/dotconfpp.h [new file with mode: 0644]
stglibs/dotconfpp.lib/mempool.cpp [new file with mode: 0644]
stglibs/dotconfpp.lib/mempool.h [new file with mode: 0644]
stglibs/hostallow.lib/Makefile [new file with mode: 0644]
stglibs/hostallow.lib/hostallow.cpp [new file with mode: 0644]
stglibs/hostallow.lib/hostallow.h [new file with mode: 0644]
stglibs/ia_auth_c.lib/Makefile [new file with mode: 0644]
stglibs/ia_auth_c.lib/ia_auth_c.bpf [new file with mode: 0644]
stglibs/ia_auth_c.lib/ia_auth_c.bpr [new file with mode: 0644]
stglibs/ia_auth_c.lib/ia_auth_c.cpp [new file with mode: 0644]
stglibs/ia_auth_c.lib/ia_auth_c.h [new file with mode: 0644]
stglibs/ibpp.lib/Makefile [new file with mode: 0644]
stglibs/ibpp.lib/_dpb.cpp [new file with mode: 0644]
stglibs/ibpp.lib/_ibpp.cpp [new file with mode: 0644]
stglibs/ibpp.lib/_ibpp.h [new file with mode: 0644]
stglibs/ibpp.lib/_ibs.cpp [new file with mode: 0644]
stglibs/ibpp.lib/_rb.cpp [new file with mode: 0644]
stglibs/ibpp.lib/_spb.cpp [new file with mode: 0644]
stglibs/ibpp.lib/_tpb.cpp [new file with mode: 0644]
stglibs/ibpp.lib/all_in_one.cpp [new file with mode: 0644]
stglibs/ibpp.lib/array.cpp [new file with mode: 0644]
stglibs/ibpp.lib/blob.cpp [new file with mode: 0644]
stglibs/ibpp.lib/database.cpp [new file with mode: 0644]
stglibs/ibpp.lib/date.cpp [new file with mode: 0644]
stglibs/ibpp.lib/dbkey.cpp [new file with mode: 0644]
stglibs/ibpp.lib/deps [new file with mode: 0644]
stglibs/ibpp.lib/events.cpp [new file with mode: 0644]
stglibs/ibpp.lib/exception.cpp [new file with mode: 0644]
stglibs/ibpp.lib/ibase.h [new file with mode: 0644]
stglibs/ibpp.lib/iberror.h [new file with mode: 0644]
stglibs/ibpp.lib/ibpp.h [new file with mode: 0644]
stglibs/ibpp.lib/libibpp.so [new file with mode: 0755]
stglibs/ibpp.lib/row.cpp [new file with mode: 0644]
stglibs/ibpp.lib/service.cpp [new file with mode: 0644]
stglibs/ibpp.lib/statement.cpp [new file with mode: 0644]
stglibs/ibpp.lib/time.cpp [new file with mode: 0644]
stglibs/ibpp.lib/transaction.cpp [new file with mode: 0644]
stglibs/ibpp.lib/user.cpp [new file with mode: 0644]
stglibs/pinger.lib/Makefile [new file with mode: 0644]
stglibs/pinger.lib/pinger.cpp [new file with mode: 0644]
stglibs/pinger.lib/pinger.h [new file with mode: 0644]
stglibs/pinger.lib/test.cpp [new file with mode: 0644]
stglibs/script_executer.lib/Makefile [new file with mode: 0644]
stglibs/script_executer.lib/script_executer.cpp [new file with mode: 0644]
stglibs/script_executer.lib/script_executer.h [new file with mode: 0644]
stglibs/srvconf.lib/Makefile [new file with mode: 0644]
stglibs/srvconf.lib/netunit.cpp [new file with mode: 0644]
stglibs/srvconf.lib/netunit.h [new file with mode: 0644]
stglibs/srvconf.lib/parser.cpp [new file with mode: 0644]
stglibs/srvconf.lib/servconf.cpp [new file with mode: 0644]
stglibs/srvconf.lib/servconf.h [new file with mode: 0644]
stglibs/srvconf.lib/servconf.vpj [new file with mode: 0644]
stglibs/srvconf.lib/servconf.vpw [new file with mode: 0644]
stglibs/srvconf.lib/test.cpp [new file with mode: 0644]
stglibs/srvconf.lib/test.sh [new file with mode: 0755]
stglibs/stg_locker.lib/Makefile [new file with mode: 0644]
stglibs/stg_locker.lib/stg_locker.cpp [new file with mode: 0644]
stglibs/stg_locker.lib/stg_locker.h [new file with mode: 0644]
stglibs/stg_logger.lib/Makefile [new file with mode: 0644]
stglibs/stg_logger.lib/stg_logger.cpp [new file with mode: 0644]
stglibs/stg_logger.lib/stg_logger.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ef73510
--- /dev/null
@@ -0,0 +1,6 @@
+*.[ao]
+*.so
+*.swp
+*.diff
+*.patch
+CVS*
diff --git a/include/Makefile b/include/Makefile
new file mode 100644 (file)
index 0000000..416f82d
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.2 2005/10/11 12:18:55 nobunaga Exp $
+###############################################################################
+
+#LIB_NAME = includes
+
+#INCS = *.h
+#include ../Makefile.in
+
+all:
+       echo hi
+
+install:
+       echo install
\ No newline at end of file
diff --git a/include/admin_conf.h b/include/admin_conf.h
new file mode 100644 (file)
index 0000000..88eebdc
--- /dev/null
@@ -0,0 +1,77 @@
+ /*
+ $Revision: 1.9 $
+ $Date: 2010/09/10 05:02:08 $
+ $Author: faust $
+ */
+
+#ifndef ADMIN_CONF_H
+#define ADMIN_CONF_H
+
+#include <string>
+
+#include "os_int.h"
+
+#define ADM_LOGIN_LEN   (32)
+#define ADM_PASSWD_LEN  (32)
+//-----------------------------------------------------------------------------
+struct PRIV
+{
+    PRIV()
+        : userStat(0),
+          userConf(0),
+          userCash(0),
+          userPasswd(0),
+          userAddDel(0),
+          adminChg(0),
+          tariffChg(0)
+    {};
+    PRIV(uint16_t p)
+        : userStat((p & 0x0003) >> 0x00),
+          userConf((p & 0x000C) >> 0x02),
+          userCash((p & 0x0030) >> 0x04),
+          userPasswd((p & 0x00C0) >> 0x06),
+          userAddDel((p & 0x0300) >> 0x08),
+          adminChg((p & 0x0C00) >> 0x0A),
+          tariffChg((p & 0x3000) >> 0x0C)
+    {}
+
+    uint16_t ToInt() const;
+    void FromInt(uint16_t p);
+
+    uint16_t userStat;
+    uint16_t userConf;
+    uint16_t userCash;
+    uint16_t userPasswd;
+    uint16_t userAddDel;
+    uint16_t adminChg;
+    uint16_t tariffChg;
+};
+//-----------------------------------------------------------------------------
+struct ADMIN_CONF
+{
+    ADMIN_CONF()
+        : priv(),
+          login(),
+          password("* NO PASSWORD *")
+    {}
+    ADMIN_CONF(const ADMIN_CONF & rvalue)
+        : priv(rvalue.priv),
+          login(rvalue.login),
+          password(rvalue.password)
+    {}
+    ADMIN_CONF(const PRIV pr, const std::string & l, const std::string & p)
+        : priv(pr),
+          login(l),
+          password(p)
+    {}
+    PRIV          priv;
+    std::string   login;
+    std::string   password;
+};
+//-----------------------------------------------------------------------------
+
+#include "admin_conf.inc.h"
+
+#endif
+
+
diff --git a/include/admin_conf.inc.h b/include/admin_conf.inc.h
new file mode 100644 (file)
index 0000000..44897a0
--- /dev/null
@@ -0,0 +1,35 @@
+ /*
+ $Revision: 1.1 $
+ $Date: 2010/09/10 01:45:24 $
+ $Author: faust $
+ */
+
+#ifndef ADMIN_CONF_INC_H
+#define ADMIN_CONF_INC_H
+
+inline
+uint16_t PRIV::ToInt() const
+{
+uint16_t p = (userStat   << 0)  |
+             (userConf   << 2)  |
+             (userCash   << 4)  |
+             (userPasswd << 6)  |
+             (userAddDel << 8)  |
+             (adminChg   << 10) |
+             (tariffChg  << 12);
+return p;
+}
+
+inline
+void PRIV::FromInt(uint16_t p)
+{
+userStat   = (p & 0x0003) >> 0x00; // 1+2
+userConf   = (p & 0x000C) >> 0x02; // 4+8
+userCash   = (p & 0x0030) >> 0x04; // 10+20
+userPasswd = (p & 0x00C0) >> 0x06; // 40+80
+userAddDel = (p & 0x0300) >> 0x08; // 100+200
+adminChg   = (p & 0x0C00) >> 0x0A; // 400+800
+tariffChg  = (p & 0x3000) >> 0x0C; // 1000+2000
+}
+
+#endif
diff --git a/include/base_auth.h b/include/base_auth.h
new file mode 100644 (file)
index 0000000..55152de
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.6 $
+ $Date: 2009/03/18 17:24:57 $
+ */
+
+#ifndef BASE_AUTH_H
+#define BASE_AUTH_H
+
+#include <time.h>
+#include <string>
+
+#include "base_plugin.h"
+#include "stg_message.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+class BASE_AUTH : public BASE_PLUGIN
+{
+public:
+    virtual ~BASE_AUTH() {};
+    virtual int SendMessage(const STG_MSG & msg, uint32_t ip) const = 0;
+};
+//-----------------------------------------------------------------------------
+#endif
+
+
diff --git a/include/base_db.h b/include/base_db.h
new file mode 100644 (file)
index 0000000..8aa0550
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef __BASE_DB_H__
+#define __BASE_DB_H__
+
+#include <string>
+#include <vector>
+#include <map>
+
+class BASE_DB {
+public:
+
+    typedef std::map<std::string, std::string> TUPLE;
+    typedef std::vector<TUPLE> TUPLES;
+    typedef std::vector<std::string> COLUMNS;
+
+    BASE_DB() {};
+    BASE_DB(std::string & dbHost,
+           std::string & dbDatabase,
+           std::string & dbUser,
+           std::string & dbPassword)
+       : host(dbHost),
+         database(dbDatabase),
+         user(dbUser),
+         password(dbPassword)
+    {};
+    virtual ~BASE_DB() {};
+
+    void SetHost(const std::string & h) { host = h; };
+    void SetDatabase(const std::string & db) { database = db; };
+    void SetUser(const std::string & u) { user = u; };
+    void SetPassword(const std::string & p) { password = p; };
+
+    const std::string & GetHost() const { return host; };
+    const std::string & GetDatabase() const { return database; };
+    const std::string & GetUser() const { return user; };
+    const std::string & GetPassword() const { return password; };
+
+    const std::string & GetErrorMsg() const { return errorMsg; };
+
+    virtual bool Connect() { return true; };
+    virtual bool Disconnect() { return true; };
+    virtual bool Query(const std::string & q) { return true; };
+    virtual bool Start() { return true; };
+    virtual bool Commit() { return true; };
+    virtual bool Rollback() { return true; };
+
+    int GetTuples() const { return tuples; };
+    int GetColumns() const { return columns; };
+    int GetAffectedRows() const { return affected; };
+
+    virtual TUPLES GetResult() const { return TUPLES(); };
+    virtual TUPLE GetTuple(int n = 0) const { return TUPLE(); };
+    const COLUMNS & GetColumnsNames() const { return cols; };
+
+protected:
+    std::string host;
+    std::string database;
+    std::string user;
+    std::string password;
+
+    std::string errorMsg;
+
+    COLUMNS cols;
+
+    int columns;
+    int tuples;
+    int affected;
+};
+
+extern "C" BASE_DB * CreateDriver();
+extern "C" void DestroyDriver(BASE_DB *);
+
+typedef BASE_DB * (* CreateDriverFn)();
+typedef void (* DestroyDriverFn)(BASE_DB *);
+
+#endif
diff --git a/include/base_plugin.h b/include/base_plugin.h
new file mode 100644 (file)
index 0000000..16dfa5f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.12 $
+ $Date: 2010/03/04 11:53:14 $
+ $Author: faust $
+*/
+
+
+#ifndef BASE_PLUGIN_H
+#define BASE_PLUGIN_H
+
+#include <string>
+#include "base_settings.h"
+#include "noncopyable.h"
+#include "os_int.h"
+
+using namespace std;
+
+class ADMINS;
+class USERS;
+class TARIFFS;
+class TRAFFCOUNTER;
+class SETTINGS;
+class BASE_STORE;
+
+//-----------------------------------------------------------------------------
+class BASE_PLUGIN : private NONCOPYABLE
+{
+public:
+    virtual                 ~BASE_PLUGIN(){};
+    virtual void            SetUsers(USERS * u) = 0;
+    virtual void            SetTariffs(TARIFFS * t) = 0;
+    virtual void            SetAdmins(ADMINS * a) = 0;
+    virtual void            SetTraffcounter(TRAFFCOUNTER * tc) = 0;
+    virtual void            SetStore(BASE_STORE * st) = 0;
+    virtual void            SetStgSettings(const SETTINGS * s) = 0;
+    virtual void            SetSettings(const MODULE_SETTINGS & s) = 0;
+    virtual int             ParseSettings() = 0;
+
+    virtual int             Start() = 0;
+    virtual int             Stop() = 0;
+    virtual int             Reload() = 0;
+    virtual bool            IsRunning() = 0;
+    virtual const string  & GetStrError() const = 0;
+    virtual const string    GetVersion() const = 0;
+    virtual uint16_t        GetStartPosition() const = 0;
+    virtual uint16_t        GetStopPosition() const = 0;
+};
+//-----------------------------------------------------------------------------
+#endif
+
+
diff --git a/include/base_settings.h b/include/base_settings.h
new file mode 100644 (file)
index 0000000..1b9366e
--- /dev/null
@@ -0,0 +1,55 @@
+ /*
+ $Revision: 1.5 $
+ $Date: 2010/03/04 11:49:52 $
+ $Author: faust $
+ */
+
+#ifndef BASE_SETTINGS_H
+#define BASE_SETTINGS_H
+
+#include <string.h>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+struct PARAM_VALUE
+{
+    PARAM_VALUE()
+        : param(),
+          value()
+    {};
+    bool operator==(const PARAM_VALUE & rhs) const
+        { return !strcasecmp(param.c_str(), rhs.param.c_str()); };
+
+    bool operator<(const PARAM_VALUE & rhs) const
+        { return strcasecmp(param.c_str(), rhs.param.c_str()) < 0; };
+
+    string param;
+    vector<string> value;
+};
+//-----------------------------------------------------------------------------
+struct MODULE_SETTINGS
+{
+    MODULE_SETTINGS()
+        : moduleName(),
+          moduleParams()
+    {};
+    MODULE_SETTINGS(const MODULE_SETTINGS & rvalue)
+        : moduleName(rvalue.moduleName),
+          moduleParams(rvalue.moduleParams)
+    {};
+    bool operator==(const MODULE_SETTINGS & rhs) const
+        { return !strcasecmp(moduleName.c_str(), rhs.moduleName.c_str()); };
+
+    bool operator<(const MODULE_SETTINGS & rhs) const
+        { return strcasecmp(moduleName.c_str(), rhs.moduleName.c_str()) < 0; };
+
+string              moduleName;
+vector<PARAM_VALUE> moduleParams;
+};
+//-----------------------------------------------------------------------------
+#endif //BASE_SETTINGS_H
+
+
diff --git a/include/base_store.h b/include/base_store.h
new file mode 100644 (file)
index 0000000..e593962
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.16 $
+ $Date: 2010/01/19 11:09:48 $
+ $Author: faust $
+ */
+
+#ifndef BASE_STORE_H
+#define BASE_STORE_H
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "user_stat.h"
+#include "user_conf.h"
+#include "corp_conf.h"
+#include "service_conf.h"
+#include "admin_conf.h"
+#include "tariff_conf.h"
+#include "base_settings.h"
+#include "stg_message.h"
+
+using namespace std;
+//-----------------------------------------------------------------------------
+class BASE_STORE
+{
+public:
+    virtual     ~BASE_STORE(){};
+    virtual int GetUsersList(vector<string> * usersList) const = 0;
+    virtual int AddUser(const string & login) const = 0;
+    virtual int DelUser(const string & login) const = 0;
+    virtual int SaveUserStat(const USER_STAT & stat, const string & login) const = 0;
+    virtual int SaveUserConf(const USER_CONF & conf, const string & login) const = 0;
+    virtual int RestoreUserStat(USER_STAT * stat, const string & login) const = 0;
+    virtual int RestoreUserConf(USER_CONF * conf, const string & login) const = 0;
+
+    virtual int WriteUserChgLog(const string & login,
+                                const string & admLogin,
+                                uint32_t       admIP,
+                                const string & paramName,
+                                const string & oldValue,
+                                const string & newValue,
+                                const string & message = "") const = 0;
+
+    virtual int WriteUserConnect(const string & login, uint32_t ip) const = 0;
+
+    virtual int WriteUserDisconnect(const string & login,
+                                    const DIR_TRAFF & up,
+                                    const DIR_TRAFF & down,
+                                    const DIR_TRAFF & sessionUp,
+                                    const DIR_TRAFF & sessionDown,
+                                    double cash,
+                                    double freeMb,
+                                    const std::string & reason) const = 0;
+
+    virtual int WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                  time_t lastStat,
+                                  const string & login) const = 0;
+
+    virtual int AddMessage(STG_MSG * msg, const string & login) const = 0;
+    virtual int EditMessage(const STG_MSG & msg, const string & login) const = 0;
+    virtual int GetMessage(uint64_t id, STG_MSG * msg, const string & login) const = 0;
+    virtual int DelMessage(uint64_t id, const string & login) const = 0;
+    virtual int GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const = 0;
+
+
+    virtual int SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const = 0;
+
+    virtual int GetAdminsList(vector<string> * adminsList) const = 0;
+    virtual int SaveAdmin(const ADMIN_CONF & ac) const = 0;
+    virtual int RestoreAdmin(ADMIN_CONF * ac, const string & login) const = 0;
+    virtual int AddAdmin(const string & login) const = 0;
+    virtual int DelAdmin(const string & login) const = 0;
+
+    virtual int GetTariffsList(vector<string> * tariffsList) const = 0;
+    virtual int AddTariff(const string & name) const = 0;
+    virtual int DelTariff(const string & name) const = 0;
+    virtual int SaveTariff(const TARIFF_DATA & td, const string & tariffName) const = 0;
+    virtual int RestoreTariff(TARIFF_DATA * td, const string & tariffName) const = 0;
+
+    virtual int GetCorpsList(vector<string> * corpsList) const = 0;
+    virtual int SaveCorp(const CORP_CONF & cc) const = 0;
+    virtual int RestoreCorp(CORP_CONF * cc, const string & name) const = 0;
+    virtual int AddCorp(const string & name) const = 0;
+    virtual int DelCorp(const string & name) const = 0;
+
+    virtual int GetServicesList(vector<string> * corpsList) const = 0;
+    virtual int SaveService(const SERVICE_CONF & sc) const = 0;
+    virtual int RestoreService(SERVICE_CONF * sc, const string & name) const = 0;
+    virtual int AddService(const string & name) const = 0;
+    virtual int DelService(const string & name) const = 0;
+
+    virtual void            SetSettings(const MODULE_SETTINGS & s) = 0;
+    virtual int             ParseSettings() = 0;
+    virtual const string &  GetStrError() const = 0;
+    virtual const string &  GetVersion() const = 0;
+};
+//-----------------------------------------------------------------------------
+
+#endif //BASE_STORE_H
+
diff --git a/include/corp_conf.h b/include/corp_conf.h
new file mode 100644 (file)
index 0000000..88a84f1
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef CORP_CONF_H
+#define CORP_CONF_H
+
+struct CORP_CONF
+{
+string  name;
+double  cash;
+};
+
+#endif //CORP_CONF_H
diff --git a/include/ia_packets.h b/include/ia_packets.h
new file mode 100644 (file)
index 0000000..bd8be53
--- /dev/null
@@ -0,0 +1,307 @@
+#ifndef PACKETH
+#define PACKETH
+
+#include "os_int.h"
+
+#define CONN_SYN_N          0
+#define CONN_SYN_ACK_N      1
+#define CONN_ACK_N          2
+#define ALIVE_SYN_N         3
+#define ALIVE_ACK_N         4
+#define DISCONN_SYN_N       5
+#define DISCONN_SYN_ACK_N   6
+#define DISCONN_ACK_N       7
+#define FIN_N               8
+#define ERROR_N             9
+#define INFO_N              10
+#define INFO_7_N            11
+#define INFO_8_N            12
+#define UPDATE_N            13
+
+#define DIR_NUM             (10)
+
+#define IA_FREEMB_LEN       (16)
+#define IA_LOGIN_LEN        (32)
+#define IA_PASSWD_LEN       (32)
+#define IA_MAX_TYPE_LEN     (16)
+#define IA_MAX_MSG_LEN      (235)
+#define IA_MAX_MSG_LEN_8    (1030)
+#define IA_DIR_NAME_LEN     (16)
+#define IA_MAGIC_LEN        (6)
+#define IA_PROTO_VER_LEN    (2)
+
+#define ST_NOT_INETABLE     (0)
+#define ST_INETABLE         (1)
+
+#define IA_ID "00100"
+
+typedef int8_t string16[IA_DIR_NAME_LEN];
+//-----------------------------------------------------------------------------
+struct HDR_8
+{
+int8_t          magic[IA_MAGIC_LEN];
+int8_t          protoVer[IA_PROTO_VER_LEN];
+//uint32_t        ip;
+//int8_t          padding[4];
+};
+//-----------------------------------------------------------------------------
+struct CONN_SYN_6
+{
+int8_t          magic[IA_MAGIC_LEN];
+int8_t          protoVer[IA_PROTO_VER_LEN];
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          login[IA_LOGIN_LEN];
+int8_t          padding[2];
+};
+//-----------------------------------------------------------------------------
+struct CONN_SYN_8
+{
+HDR_8           hdr;
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          login[IA_LOGIN_LEN];
+uint32_t        dirs;   // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct CONN_SYN_ACK_6
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+int32_t         userTimeOut;    // Byte-order dependent
+int32_t         aliveDelay;     // Byte-order dependent
+string16        dirName[DIR_NUM];
+};
+//-----------------------------------------------------------------------------
+struct CONN_SYN_ACK_8
+{
+HDR_8           hdr;
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+int32_t         userTimeOut;    // Byte-order dependent
+int32_t         aliveDelay;     // Byte-order dependent
+string16        dirName[DIR_NUM];
+};
+//-----------------------------------------------------------------------------
+struct CONN_ACK_6
+{
+int8_t          magic[IA_MAGIC_LEN];
+int8_t          protoVer[IA_PROTO_VER_LEN];
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct CONN_ACK_8
+{
+HDR_8           hdr;
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct ALIVE_SYN_6
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+
+int64_t         mu[DIR_NUM];    // Byte-order dependent
+int64_t         md[DIR_NUM];    // Byte-order dependent
+
+int64_t         su[DIR_NUM];    // Byte-order dependent
+int64_t         sd[DIR_NUM];    // Byte-order dependent
+
+int64_t         cash;           // Byte-order dependent
+
+int8_t          freeMb[IA_FREEMB_LEN];
+};
+//-----------------------------------------------------------------------------
+struct ALIVE_SYN_8
+{
+HDR_8           hdr;
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+
+int64_t         mu[DIR_NUM];    // Byte-order dependent
+int64_t         md[DIR_NUM];    // Byte-order dependent
+
+int64_t         su[DIR_NUM];    // Byte-order dependent
+int64_t         sd[DIR_NUM];    // Byte-order dependent
+
+int64_t         cash; // Äåíüãè óìíîæåííûå íà 1000 - Byte-order dependent
+int8_t          freeMb[IA_FREEMB_LEN];
+
+uint32_t        status; // Byte-order dependent
+int8_t          padding[4];
+};
+//-----------------------------------------------------------------------------
+struct ALIVE_ACK_6
+{
+int8_t          magic[IA_MAGIC_LEN];
+int8_t          protoVer[IA_PROTO_VER_LEN];
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct ALIVE_ACK_8
+{
+HDR_8           hdr;
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct DISCONN_SYN_6
+{
+int8_t          magic[IA_MAGIC_LEN];
+int8_t          protoVer[IA_PROTO_VER_LEN];
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          login[IA_LOGIN_LEN];
+int8_t          padding[2];
+};
+//-----------------------------------------------------------------------------
+struct DISCONN_SYN_8
+{
+HDR_8           hdr;
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          login[IA_LOGIN_LEN];
+int8_t          padding[4];
+};
+//-----------------------------------------------------------------------------
+struct DISCONN_SYN_ACK_6
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct DISCONN_SYN_ACK_8
+{
+HDR_8           hdr;
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct DISCONN_ACK_6
+{
+int8_t          magic[IA_MAGIC_LEN];
+int8_t          protoVer[IA_PROTO_VER_LEN];
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct DISCONN_ACK_8
+{
+HDR_8           hdr;
+int8_t          loginS[IA_LOGIN_LEN];
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+uint32_t        rnd;    // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+struct FIN_6
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          ok[3];
+int8_t          padding[1];
+};
+//-----------------------------------------------------------------------------
+struct FIN_8
+{
+HDR_8           hdr;
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          ok[3];
+int8_t          padding[1];
+};
+//-----------------------------------------------------------------------------
+struct ERR
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          text[236];
+};
+//-----------------------------------------------------------------------------
+struct ERR_8
+{
+HDR_8           hdr;
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          text[236];
+};
+//-----------------------------------------------------------------------------
+struct INFO_6
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          infoType;
+int8_t          text[IA_MAX_MSG_LEN];
+};
+//-----------------------------------------------------------------------------
+struct INFO_7
+{
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          infoType;
+uint32_t        sendTime;   // Byte-order dependent
+int8_t          showTime;
+int8_t          text[IA_MAX_MSG_LEN];
+int8_t          padding[5];
+};
+//-----------------------------------------------------------------------------
+struct INFO_8
+{
+HDR_8           hdr;
+int32_t         len;    // Byte-order dependent
+int8_t          type[IA_MAX_TYPE_LEN];
+int8_t          infoType;
+uint32_t        sendTime;   // Byte-order dependent
+int8_t          showTime;
+int8_t          text[IA_MAX_MSG_LEN_8];
+};
+//-----------------------------------------------------------------------------
+struct LOADSTAT
+{
+int64_t         mu[DIR_NUM];    // Byte-order dependent
+int64_t         md[DIR_NUM];    // Byte-order dependent
+
+int64_t         su[DIR_NUM];    // Byte-order dependent
+int64_t         sd[DIR_NUM];    // Byte-order dependent
+
+int64_t         cash;   // Äåíüãè óìíîæåííûå íà 1000 - Byte-order dependent
+int8_t          freeMb[IA_FREEMB_LEN];
+int32_t         status; // Byte-order dependent
+};
+//-----------------------------------------------------------------------------
+#define CONN_SYN_7          CONN_SYN_6
+#define CONN_SYN_ACK_7      CONN_SYN_ACK_6
+#define CONN_ACK_7          CONN_ACK_6
+#define ALIVE_SYN_7         ALIVE_SYN_6
+#define ALIVE_ACK_7         ALIVE_ACK_6
+#define DISCONN_SYN_7       DISCONN_SYN_6
+#define DISCONN_SYN_ACK_7   DISCONN_SYN_ACK_6
+#define DISCONN_ACK_7       DISCONN_ACK_6
+#define FIN_7               FIN_6
+
+#endif
+
+
diff --git a/include/ibpp.h b/include/ibpp.h
new file mode 100644 (file)
index 0000000..7795c7d
--- /dev/null
@@ -0,0 +1,929 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: ibpp.h,v 1.3 2007/10/28 11:17:44 nobunaga Exp $\r
+//     Subject : IBPP public header file. This is _the_ only file you include in\r
+//                       your application files when developing with IBPP.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+//     Contributor(s):\r
+//\r
+//             Olivier Mascia, main coding\r
+//             Matt Hortman, initial linux port\r
+//             Mark Jordan, design contributions\r
+//             Maxim Abrashkin, enhancement patches\r
+//             Torsten Martinsen, enhancement patches\r
+//             Michael Hieke, darwin (OS X) port, enhancement patches\r
+//             Val Samko, enhancement patches and debugging\r
+//             Mike Nordell, invaluable C++ advices\r
+//             Claudio Valderrama, help with not-so-well documented IB/FB features\r
+//             Many others, excellent suggestions, bug finding, and support\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     Tabulations should be set every four characters when editing this file.\r
+//\r
+//     When compiling a project using IBPP, the following defines should be made\r
+//     on the command-line (or in makefiles) according to the OS platform and\r
+//     compiler used.\r
+//\r
+//     Select the platform:    IBPP_WINDOWS | IBPP_LINUX | IBPP_DARWIN\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef __IBPP_H__\r
+#define __IBPP_H__\r
+\r
+#if !defined(IBPP_WINDOWS) && !defined(IBPP_LINUX) && !defined(IBPP_DARWIN)\r
+#error Please define IBPP_WINDOWS/IBPP_LINUX/IBPP_DARWIN before compiling !\r
+#endif\r
+\r
+#if !defined(__BCPLUSPLUS__) && !defined(__GNUC__) && !defined(_MSC_VER) && !defined(__DMC__)
+#error Your compiler is not recognized.\r
+#endif\r
+\r
+#if defined(IBPP_LINUX) || defined(IBPP_DARWIN)\r
+#define IBPP_UNIX      // IBPP_UNIX stands as a common denominator to *NIX flavours\r
+#endif\r
+\r
+// IBPP is written for 32 bits systems or higher.\r
+// The standard type 'int' is assumed to be at least 32 bits.\r
+// And the standard type 'short' is assumed to be exactly 16 bits.\r
+// Everywhere possible, where the exact size of an integer does not matter,\r
+// the standard type 'int' is used. And where an exact integer size is required\r
+// the standard exact precision types definitions of C 99 standard are used.\r
+\r
+#if defined(_MSC_VER) || defined(__DMC__) || defined(__BCPLUSPLUS__)\r
+// C99 §7.18.1.1 Exact-width integer types (only those used by IBPP)\r
+#if defined(_MSC_VER) && (_MSC_VER < 1300)     // MSVC 6 should be < 1300\r
+       typedef short int16_t;\r
+       typedef int int32_t;\r
+       typedef unsigned int uint32_t;\r
+#else\r
+       typedef __int16 int16_t;\r
+       typedef __int32 int32_t;\r
+       typedef unsigned __int32 uint32_t;\r
+#endif\r
+       typedef __int64 int64_t;\r
+#else\r
+       #include <os_int.h>                     // C99 (§7.18) integer types definitions\r
+#endif\r
+\r
+#if !defined(_)\r
+#define _(s)   s\r
+#endif\r
+\r
+#include <exception>\r
+#include <string>\r
+#include <vector>\r
+\r
+namespace IBPP\r
+{\r
+       //      Typically you use this constant in a call IBPP::CheckVersion as in:\r
+       //      if (! IBPP::CheckVersion(IBPP::Version)) { throw .... ; }\r
+       const uint32_t Version = (2<<24) + (5<<16) + (3<<8) + 0; // Version == 2.5.3.0\r
+\r
+       //      Dates range checking\r
+       const int MinDate = -693594;    //  1 JAN 0001\r
+       const int MaxDate = 2958464;    // 31 DEC 9999\r
+       \r
+       //      Transaction Access Modes\r
+       enum TAM {amWrite, amRead};\r
+\r
+       //      Transaction Isolation Levels\r
+       enum TIL {ilConcurrency, ilReadDirty, ilReadCommitted, ilConsistency};\r
+\r
+       //      Transaction Lock Resolution\r
+       enum TLR {lrWait, lrNoWait};\r
+\r
+       // Transaction Table Reservation\r
+       enum TTR {trSharedWrite, trSharedRead, trProtectedWrite, trProtectedRead};\r
+\r
+       //      Prepared Statement Types\r
+       enum STT {stUnknown, stUnsupported,\r
+               stSelect, stInsert, stUpdate, stDelete, stDDL, stExecProcedure,\r
+               stSelectUpdate, stSetGenerator, stSavePoint};\r
+\r
+       //      SQL Data Types\r
+       enum SDT {sdArray, sdBlob, sdDate, sdTime, sdTimestamp, sdString,\r
+               sdSmallint, sdInteger, sdLargeint, sdFloat, sdDouble};\r
+\r
+       //      Array Data Types\r
+       enum ADT {adDate, adTime, adTimestamp, adString,\r
+               adBool, adInt16, adInt32, adInt64, adFloat, adDouble};\r
+\r
+       // Database::Shutdown Modes\r
+       enum DSM {dsForce, dsDenyTrans, dsDenyAttach};\r
+\r
+       // Service::StartBackup && Service::StartRestore Flags\r
+       enum BRF {\r
+               brVerbose = 0x1,\r
+               // Backup flags\r
+               brIgnoreChecksums = 0x100, brIgnoreLimbo = 0x200,\r
+               brMetadataOnly = 0x400, brNoGarbageCollect = 0x800,\r
+               brNonTransportable = 0x1000, brConvertExtTables = 0x2000,\r
+               // Restore flags\r
+               brReplace = 0x10000, brDeactivateIdx = 0x20000,\r
+               brNoShadow = 0x40000, brNoValidity = 0x80000,\r
+               brPerTableCommit = 0x100000, brUseAllSpace = 0x200000\r
+       };\r
+\r
+       // Service::Repair Flags\r
+       enum RPF\r
+       {\r
+               // Mandatory and mutually exclusives\r
+               rpMendRecords = 0x1, rpValidatePages = 0x2, rpValidateFull = 0x4,\r
+               // Options\r
+               rpReadOnly = 0x100, rpIgnoreChecksums = 0x200, rpKillShadows = 0x400\r
+       };\r
+\r
+       // TransactionFactory Flags\r
+       enum TFF {tfIgnoreLimbo = 0x1, tfAutoCommit = 0x2, tfNoAutoUndo = 0x4};\r
+\r
+       /* IBPP never return any error codes. It throws exceptions.\r
+        * On database engine reported errors, an IBPP::SQLException is thrown.\r
+        * In all other cases, IBPP throws IBPP::LogicException.\r
+        * Also note that the runtime and the language might also throw exceptions\r
+        * while executing some IBPP methods. A failing new operator will throw\r
+        * std::bad_alloc, IBPP does nothing to alter the standard behaviour.\r
+        *\r
+        *                    std::exception\r
+        *                           |\r
+        *                   IBPP::Exception\r
+        *                 /                 \\r
+        *    IBPP::LogicException    IBPP::SQLException\r
+        *             |\r
+        *      IBPP::WrongType\r
+        */\r
+\r
+       class Exception : public std::exception\r
+       {\r
+       public:\r
+               virtual const char* Origin() const throw() = 0;\r
+               virtual const char* ErrorMessage() const throw() = 0;   // Deprecated, use what()\r
+               virtual const char* what() const throw() = 0;\r
+               virtual ~Exception() throw();\r
+       };\r
+\r
+       class LogicException : public Exception\r
+       {\r
+       public:\r
+               virtual ~LogicException() throw();\r
+       };\r
+\r
+       class SQLException : public Exception\r
+       {\r
+       public:\r
+               virtual int SqlCode() const throw() = 0;\r
+               virtual int EngineCode() const throw() = 0;\r
+               \r
+               virtual ~SQLException() throw();\r
+       };\r
+\r
+       class WrongType : public LogicException\r
+       {\r
+       public:\r
+               virtual ~WrongType() throw();\r
+       };\r
+       \r
+       /* Classes Date, Time, Timestamp and DBKey are 'helper' classes.  They help\r
+        * in retrieving or setting some special SQL types. Dates, times and dbkeys\r
+        * are often read and written as strings in SQL scripts. When programming\r
+        * with IBPP, we handle those data with these specific classes, which\r
+        * enhance their usefullness and free us of format problems (M/D/Y, D/M/Y,\r
+        * Y-M-D ?, and so on...). */\r
+\r
+       /* Class Date represent purely a Date (no time part specified). It is\r
+        * usefull in interactions with the SQL DATE type of Interbase.  You can add\r
+        * or substract a number from a Date, that will modify it to represent the\r
+        * correct date, X days later or sooner. All the Y2K details taken into\r
+        * account.\r
+        * The full range goes from integer values IBPP::MinDate to IBPP::MaxDate\r
+        * which means from 01 Jan 0001 to 31 Dec 9999. ( Which is inherently\r
+        * incorrect as this assumes Gregorian calendar. ) */\r
+       \r
+       class Timestamp;        // Cross-reference between Timestamp, Date and Time\r
+       \r
+       class Date\r
+       {\r
+       protected:\r
+               int mDate;      // The date : 1 == 1 Jan 1900\r
+\r
+       public:\r
+               void Clear()    { mDate = MinDate - 1; };\r
+               void Today();\r
+               void SetDate(int year, int month, int day);\r
+               void SetDate(int dt);\r
+               void GetDate(int& year, int& month, int& day) const;\r
+               int GetDate() const     { return mDate; }\r
+               int Year() const;\r
+               int Month() const;\r
+               int Day() const;\r
+               void Add(int days);\r
+               void StartOfMonth();\r
+               void EndOfMonth();\r
+       \r
+               Date()                  { Clear(); };\r
+               Date(int dt)    { SetDate(dt); }\r
+               Date(int year, int month, int day);\r
+               Date(const Date&);                                                      // Copy Constructor\r
+               Date& operator=(const Timestamp&);                      // Timestamp Assignment operator\r
+               Date& operator=(const Date&);                           // Date Assignment operator\r
+\r
+               bool operator==(const Date& rv) const { return mDate == rv.GetDate(); }\r
+               bool operator!=(const Date& rv) const { return mDate != rv.GetDate(); }\r
+               bool operator<(const Date& rv) const { return mDate < rv.GetDate(); }\r
+               bool operator>(const Date& rv) const { return mDate > rv.GetDate(); }\r
+\r
+               virtual ~Date() { };\r
+       };\r
+\r
+       /* Class Time represent purely a Time. It is usefull in interactions\r
+        * with the SQL TIME type of Interbase. */\r
+\r
+       class Time\r
+       {\r
+       protected:\r
+               int mTime;      // The time, in ten-thousandths of seconds since midnight\r
+\r
+       public:\r
+               void Clear()    { mTime = 0; }\r
+               void Now();\r
+               void SetTime(int hour, int minute, int second, int tenthousandths = 0);\r
+               void SetTime(int tm);\r
+               void GetTime(int& hour, int& minute, int& second) const;\r
+               void GetTime(int& hour, int& minute, int& second, int& tenthousandths) const;\r
+               int GetTime() const     { return mTime; }\r
+               int Hours() const;\r
+               int Minutes() const;\r
+               int Seconds() const;\r
+               int SubSeconds() const;         // Actually tenthousandths of seconds\r
+               Time()                  { Clear(); }\r
+               Time(int tm)    { SetTime(tm); }\r
+               Time(int hour, int minute, int second, int tenthousandths = 0);\r
+               Time(const Time&);                                                      // Copy Constructor\r
+               Time& operator=(const Timestamp&);                      // Timestamp Assignment operator\r
+               Time& operator=(const Time&);                           // Time Assignment operator\r
+\r
+               bool operator==(const Time& rv) const { return mTime == rv.GetTime(); }\r
+               bool operator!=(const Time& rv) const { return mTime != rv.GetTime(); }\r
+               bool operator<(const Time& rv) const { return mTime < rv.GetTime(); }\r
+               bool operator>(const Time& rv) const { return mTime > rv.GetTime(); }\r
+\r
+               virtual ~Time() { };\r
+       };\r
+\r
+       /* Class Timestamp represent a date AND a time. It is usefull in\r
+        * interactions with the SQL TIMESTAMP type of Interbase. This class\r
+        * inherits from Date and Time and completely inline implements its small\r
+        * specific details. */\r
+\r
+       class Timestamp : public Date, public Time\r
+       {\r
+       public:\r
+               void Clear()    { Date::Clear(); Time::Clear(); }\r
+               void Today()    { Date::Today(); Time::Clear(); }\r
+               void Now()              { Date::Today(); Time::Now(); }\r
+\r
+               Timestamp()             { Clear(); }\r
+\r
+               Timestamp(int y, int m, int d)\r
+                       { Date::SetDate(y, m, d); Time::Clear(); }\r
+\r
+               Timestamp(int y, int mo, int d, int h, int mi, int s, int t = 0)\r
+                       { Date::SetDate(y, mo, d); Time::SetTime(h, mi, s, t); }\r
+\r
+               Timestamp(const Timestamp& rv)\r
+                       : Date(rv.mDate), Time(rv.mTime) {}     // Copy Constructor\r
+\r
+               Timestamp(const Date& rv)\r
+                       { mDate = rv.GetDate(); mTime = 0; }\r
+\r
+               Timestamp(const Time& rv)\r
+                       { mDate = 0; mTime = rv.GetTime(); }\r
+\r
+               Timestamp& operator=(const Timestamp& rv)       // Timestamp Assignment operator\r
+                       { mDate = rv.mDate; mTime = rv.mTime; return *this; }\r
+\r
+               Timestamp& operator=(const Date& rv)            // Date Assignment operator\r
+                       { mDate = rv.GetDate(); return *this; }\r
+\r
+               Timestamp& operator=(const Time& rv)            // Time Assignment operator\r
+                       { mTime = rv.GetTime(); return *this; }\r
+\r
+               bool operator==(const Timestamp& rv) const\r
+                       { return (mDate == rv.GetDate()) && (mTime == rv.GetTime()); }\r
+\r
+               bool operator!=(const Timestamp& rv) const\r
+                       { return (mDate != rv.GetDate()) || (mTime != rv.GetTime()); }\r
+\r
+               bool operator<(const Timestamp& rv) const\r
+                       { return (mDate < rv.GetDate()) ||\r
+                               (mDate == rv.GetDate() && mTime < rv.GetTime()); }\r
+\r
+               bool operator>(const Timestamp& rv) const\r
+                       { return (mDate > rv.GetDate()) ||\r
+                               (mDate == rv.GetDate() && mTime > rv.GetTime()); }\r
+\r
+               ~Timestamp() { }\r
+       };\r
+\r
+       /* Class DBKey can store a DBKEY, that special value which the hidden\r
+        * RDB$DBKEY can give you from a select statement. A DBKey is nothing\r
+        * specific to IBPP. It's a feature of the Firebird database engine. See its\r
+        * documentation for more information. */\r
+\r
+       class DBKey\r
+       {\r
+       private:\r
+               std::string mDBKey;                     // Stores the binary DBKey\r
+               mutable std::string mString;// String (temporary) representation of it\r
+\r
+       public:\r
+               void Clear();\r
+               int Size() const        { return (int)mDBKey.size(); }\r
+               void SetKey(const void*, int size);\r
+               void GetKey(void*, int size) const;\r
+               const char* AsString() const;\r
+\r
+               DBKey& operator=(const DBKey&); // Assignment operator\r
+               DBKey(const DBKey&);                    // Copy Constructor\r
+               DBKey() { }\r
+               ~DBKey() { }\r
+       };\r
+\r
+       /* Class User wraps all the information about a user that the engine can manage. */\r
+\r
+       class User\r
+       {\r
+       public:\r
+               std::string username;\r
+               std::string password;\r
+               std::string firstname;\r
+               std::string middlename;\r
+               std::string lastname;\r
+               uint32_t userid;                // Only relevant on unixes\r
+               uint32_t groupid;               // Only relevant on unixes\r
+\r
+       private:\r
+               void copyfrom(const User& r);\r
+\r
+       public:\r
+               void clear();\r
+               User& operator=(const User& r)  { copyfrom(r); return *this; }\r
+               User(const User& r)                             { copyfrom(r); }\r
+               User() : userid(0), groupid(0)  { }\r
+               ~User() { };\r
+       };\r
+\r
+       //      Interface Wrapper\r
+       template <class T>\r
+       class Ptr\r
+       {\r
+       private:\r
+               T* mObject;\r
+\r
+       public:\r
+               void clear()\r
+               {\r
+                       if (mObject != 0) { mObject->Release(); mObject = 0; }\r
+               }\r
+\r
+               T* intf() const                                         { return mObject; }\r
+               T* operator->() const                           { return mObject; }\r
+\r
+               bool operator==(const T* p) const       { return mObject == p; }\r
+               bool operator==(const Ptr& r) const     { return mObject == r.mObject; }\r
+               bool operator!=(const T* p) const       { return mObject != p; }\r
+               bool operator!=(const Ptr& r) const     { return mObject != r.mObject; }\r
+\r
+               Ptr& operator=(T* p)\r
+               {\r
+                       // AddRef _before_ Release gives correct behaviour on self-assigns\r
+                       T* tmp = (p == 0 ? 0 : p->AddRef());    // Take care of 0\r
+                       if (mObject != 0) mObject->Release();\r
+                       mObject = tmp; return *this;\r
+               }\r
+\r
+               Ptr& operator=(const Ptr& r)\r
+               {\r
+                       // AddRef _before_ Release gives correct behaviour on self-assigns\r
+                       T* tmp = (r.intf() == 0 ? 0 : r->AddRef());// Take care of 0\r
+                       if (mObject != 0) mObject->Release();\r
+                       mObject = tmp; return *this;\r
+               }\r
+\r
+               Ptr(T* p) : mObject(p == 0 ? 0 : p->AddRef()) { }\r
+               Ptr(const Ptr& r) : mObject(r.intf() == 0 ? 0 : r->AddRef()) {  }\r
+\r
+               Ptr() : mObject(0) { }\r
+               ~Ptr() { clear(); }\r
+       };\r
+\r
+       //      --- Interface Classes --- //\r
+\r
+       /* Interfaces IBlob, IArray, IService, IDatabase, ITransaction and\r
+        * IStatement are at the core of IBPP. Though it is possible to program your\r
+        * applications by using theses interfaces directly (as was the case with\r
+        * IBPP 1.x), you should refrain from using them and prefer the new IBPP\r
+        * Objects Blob, Array, ... (without the I in front). Those new objects are\r
+        * typedef'd right after each interface class definition as you can read\r
+        * below. If you program using the Blob (instead of the IBlob interface\r
+        * itself), you'll never have to care about AddRef/Release and you'll never\r
+        * have to care about deleting your objects. */\r
+\r
+       class IBlob;                    typedef Ptr<IBlob> Blob;\r
+       class IArray;                   typedef Ptr<IArray> Array;\r
+       class IService;                 typedef Ptr<IService> Service;\r
+       class IDatabase;                typedef Ptr<IDatabase> Database;\r
+       class ITransaction;             typedef Ptr<ITransaction> Transaction;\r
+       class IStatement;               typedef Ptr<IStatement> Statement;\r
+       class IEvents;                  typedef Ptr<IEvents> Events;\r
+       class IRow;                             typedef Ptr<IRow> Row;\r
+\r
+       /* IBlob is the interface to the blob capabilities of IBPP. Blob is the\r
+        * object class you actually use in your programming. In Firebird, at the\r
+        * row level, a blob is merely a handle to a blob, stored elsewhere in the\r
+        * database. Blob allows you to retrieve such a handle and then read from or\r
+        * write to the blob, much in the same manner than you would do with a file. */\r
+\r
+       class IBlob\r
+       {\r
+       public:\r
+               virtual void Create() = 0;\r
+               virtual void Open() = 0;\r
+               virtual void Close() = 0;\r
+               virtual void Cancel() = 0;\r
+               virtual int Read(void*, int size) = 0;\r
+               virtual void Write(const void*, int size) = 0;\r
+               virtual void Info(int* Size, int* Largest, int* Segments) = 0;\r
+       \r
+               virtual void Save(const std::string& data) = 0;\r
+               virtual void Load(std::string& data) = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IBlob* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+               virtual ~IBlob() { };\r
+       };\r
+\r
+       /*      IArray is the interface to the array capabilities of IBPP. Array is the\r
+       * object class you actually use in your programming. With an Array object, you\r
+       * can create, read and write Interbase Arrays, as a whole or in slices. */\r
+\r
+       class IArray\r
+       {\r
+       public:\r
+               virtual void Describe(const std::string& table, const std::string& column) = 0;\r
+               virtual void ReadTo(ADT, void* buffer, int elemcount) = 0;\r
+               virtual void WriteFrom(ADT, const void* buffer, int elemcount) = 0;\r
+               virtual SDT ElementType() = 0;\r
+               virtual int ElementSize() = 0;\r
+               virtual int ElementScale() = 0;\r
+               virtual int Dimensions() = 0;\r
+               virtual void Bounds(int dim, int* low, int* high) = 0;\r
+               virtual void SetBounds(int dim, int low, int high) = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IArray* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+               virtual ~IArray() { };\r
+       };\r
+\r
+       /* IService is the interface to the service capabilities of IBPP. Service is\r
+        * the object class you actually use in your programming. With a Service\r
+        * object, you can do some maintenance work of databases and servers\r
+        * (backup, restore, create/update users, ...) */\r
+\r
+       class IService\r
+       {\r
+       public:\r
+           virtual void Connect() = 0;\r
+               virtual bool Connected() = 0;\r
+               virtual void Disconnect() = 0;\r
+\r
+               virtual void GetVersion(std::string& version) = 0;\r
+\r
+               virtual void AddUser(const User&) = 0;\r
+               virtual void GetUser(User&) = 0;\r
+               virtual void GetUsers(std::vector<User>&) = 0;\r
+               virtual void ModifyUser(const User&) = 0;\r
+               virtual void RemoveUser(const std::string& username) = 0;\r
+\r
+               virtual void SetPageBuffers(const std::string& dbfile, int buffers) = 0;\r
+               virtual void SetSweepInterval(const std::string& dbfile, int sweep) = 0;\r
+               virtual void SetSyncWrite(const std::string& dbfile, bool) = 0;\r
+               virtual void SetReadOnly(const std::string& dbfile, bool) = 0;\r
+               virtual void SetReserveSpace(const std::string& dbfile, bool) = 0;\r
+\r
+               virtual void Shutdown(const std::string& dbfile, DSM mode, int sectimeout) = 0;\r
+               virtual void Restart(const std::string& dbfile) = 0;\r
+               virtual void Sweep(const std::string& dbfile) = 0;\r
+               virtual void Repair(const std::string& dbfile, RPF flags) = 0;\r
+\r
+               virtual void StartBackup(const std::string& dbfile,\r
+                       const std::string& bkfile, BRF flags = BRF(0)) = 0;\r
+               virtual void StartRestore(const std::string& bkfile, const std::string& dbfile,\r
+                       int pagesize = 0, BRF flags = BRF(0)) = 0;\r
+\r
+               virtual const char* WaitMsg() = 0;      // With reporting (does not block)\r
+               virtual void Wait() = 0;                        // Without reporting (does block)\r
+\r
+               virtual IService* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+               virtual ~IService() { };\r
+       };\r
+\r
+       /*      IDatabase is the interface to the database connections in IBPP. Database\r
+        * is the object class you actually use in your programming. With a Database\r
+        * object, you can create/drop/connect databases. */\r
+\r
+       class EventInterface;   // Cross-reference between EventInterface and IDatabase\r
+       \r
+       class IDatabase\r
+       {\r
+       public:\r
+               virtual const char* ServerName() const = 0;\r
+               virtual const char* DatabaseName() const = 0;\r
+               virtual const char* Username() const = 0;\r
+               virtual const char* UserPassword() const = 0;\r
+               virtual const char* RoleName() const = 0;\r
+               virtual const char* CharSet() const = 0;\r
+               virtual const char* CreateParams() const = 0;\r
+\r
+               virtual void Info(int* ODS, int* ODSMinor, int* PageSize,\r
+                       int* Pages,     int* Buffers, int* Sweep, bool* Sync,\r
+                       bool* Reserve) = 0;\r
+               virtual void Statistics(int* Fetches, int* Marks,\r
+                       int* Reads, int* Writes) = 0;\r
+               virtual void Counts(int* Insert, int* Update, int* Delete, \r
+                       int* ReadIdx, int* ReadSeq) = 0;\r
+               virtual void Users(std::vector<std::string>& users) = 0;\r
+               virtual int Dialect() = 0;\r
+\r
+               virtual void Create(int dialect) = 0;\r
+               virtual void Connect() = 0;\r
+               virtual bool Connected() = 0;\r
+               virtual void Inactivate() = 0;\r
+               virtual void Disconnect() = 0;\r
+               virtual void Drop() = 0;\r
+\r
+               virtual IDatabase* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IDatabase() { };\r
+       };\r
+\r
+       /* ITransaction is the interface to the transaction connections in IBPP.\r
+        * Transaction is the object class you actually use in your programming. A\r
+        * Transaction object can be associated with more than one Database,\r
+        * allowing for distributed transactions spanning multiple databases,\r
+        * possibly located on different servers. IBPP is one among the few\r
+        * programming interfaces to Firebird that allows you to support distributed\r
+        * transactions. */\r
+\r
+       class ITransaction\r
+       {\r
+       public:\r
+           virtual void AttachDatabase(Database db, TAM am = amWrite,\r
+                       TIL il = ilConcurrency, TLR lr = lrWait, TFF flags = TFF(0)) = 0;\r
+           virtual void DetachDatabase(Database db) = 0;\r
+               virtual void AddReservation(Database db,\r
+                               const std::string& table, TTR tr) = 0;\r
+\r
+               virtual void Start() = 0;\r
+               virtual bool Started() = 0;\r
+           virtual void Commit() = 0;\r
+           virtual void Rollback() = 0;\r
+           virtual void CommitRetain() = 0;\r
+               virtual void RollbackRetain() = 0;\r
+\r
+               virtual ITransaction* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~ITransaction() { };\r
+       };\r
+\r
+       /*\r
+        *      Class Row can hold all the values of a row (from a SELECT for instance).\r
+        */\r
+\r
+       class IRow\r
+       {\r
+       public:\r
+               virtual void SetNull(int) = 0;\r
+               virtual void Set(int, bool) = 0;\r
+               virtual void Set(int, const void*, int) = 0;            // byte buffers\r
+               virtual void Set(int, const char*) = 0;                         // c-string\r
+               virtual void Set(int, const std::string&) = 0;\r
+               virtual void Set(int, int16_t) = 0;\r
+               virtual void Set(int, int32_t) = 0;\r
+               virtual void Set(int, int64_t) = 0;\r
+               virtual void Set(int, float) = 0;\r
+               virtual void Set(int, double) = 0;\r
+               virtual void Set(int, const Timestamp&) = 0;\r
+               virtual void Set(int, const Date&) = 0;\r
+               virtual void Set(int, const Time&) = 0;\r
+               virtual void Set(int, const DBKey&) = 0;\r
+               virtual void Set(int, const Blob&) = 0;\r
+               virtual void Set(int, const Array&) = 0;\r
+\r
+               virtual bool IsNull(int) = 0;\r
+               virtual bool Get(int, bool&) = 0;\r
+               virtual bool Get(int, void*, int&) = 0; // byte buffers\r
+               virtual bool Get(int, std::string&) = 0;\r
+               virtual bool Get(int, int16_t&) = 0;\r
+               virtual bool Get(int, int32_t&) = 0;\r
+               virtual bool Get(int, int64_t&) = 0;\r
+               virtual bool Get(int, float&) = 0;\r
+               virtual bool Get(int, double&) = 0;\r
+               virtual bool Get(int, Timestamp&) = 0;\r
+               virtual bool Get(int, Date&) = 0;\r
+               virtual bool Get(int, Time&) = 0;\r
+               virtual bool Get(int, DBKey&) = 0;\r
+               virtual bool Get(int, Blob&) = 0;\r
+               virtual bool Get(int, Array&) = 0;\r
+\r
+               virtual bool IsNull(const std::string&) = 0;\r
+               virtual bool Get(const std::string&, bool&) = 0;\r
+               virtual bool Get(const std::string&, void*, int&) = 0;  // byte buffers\r
+               virtual bool Get(const std::string&, std::string&) = 0;\r
+               virtual bool Get(const std::string&, int16_t&) = 0;\r
+               virtual bool Get(const std::string&, int32_t&) = 0;\r
+               virtual bool Get(const std::string&, int64_t&) = 0;\r
+               virtual bool Get(const std::string&, float&) = 0;\r
+               virtual bool Get(const std::string&, double&) = 0;\r
+               virtual bool Get(const std::string&, Timestamp&) = 0;\r
+               virtual bool Get(const std::string&, Date&) = 0;\r
+               virtual bool Get(const std::string&, Time&) = 0;\r
+               virtual bool Get(const std::string&, DBKey&) = 0;\r
+               virtual bool Get(const std::string&, Blob&) = 0;\r
+               virtual bool Get(const std::string&, Array&) = 0;\r
+\r
+               virtual int ColumnNum(const std::string&) = 0;\r
+               virtual const char* ColumnName(int) = 0;\r
+               virtual const char* ColumnAlias(int) = 0;\r
+               virtual const char* ColumnTable(int) = 0;\r
+               virtual SDT ColumnType(int) = 0;\r
+               virtual int ColumnSubtype(int) = 0;\r
+               virtual int ColumnSize(int) = 0;\r
+               virtual int ColumnScale(int) = 0;\r
+               virtual int Columns() = 0;\r
+               \r
+               virtual bool ColumnUpdated(int) = 0;\r
+               virtual bool Updated() = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IRow* Clone() = 0;\r
+               virtual IRow* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IRow() {};\r
+       };\r
+\r
+       /* IStatement is the interface to the statements execution in IBPP.\r
+        * Statement is the object class you actually use in your programming. A\r
+        * Statement object is the work horse of IBPP. All your data manipulation\r
+        * statements will be done through it. It is also used to access the result\r
+        * set of a query (when the statement is such), one row at a time and in\r
+        * strict forward direction. */\r
+\r
+       class IStatement\r
+       {\r
+       public:\r
+               virtual void Prepare(const std::string&) = 0;\r
+               virtual void Execute() = 0;\r
+               virtual void Execute(const std::string&) = 0;\r
+               virtual void ExecuteImmediate(const std::string&) = 0;\r
+               virtual void CursorExecute(const std::string& cursor) = 0;\r
+               virtual void CursorExecute(const std::string& cursor, const std::string&) = 0;\r
+               virtual bool Fetch() = 0;\r
+               virtual bool Fetch(Row&) = 0;\r
+               virtual int AffectedRows() = 0;\r
+               virtual void Close() = 0;\r
+               virtual std::string& Sql() = 0;\r
+               virtual STT Type() = 0;\r
+\r
+               virtual void SetNull(int) = 0;\r
+               virtual void Set(int, bool) = 0;\r
+               virtual void Set(int, const void*, int) = 0;            // byte buffers\r
+               virtual void Set(int, const char*) = 0;                         // c-string\r
+               virtual void Set(int, const std::string&) = 0;\r
+               virtual void Set(int, int16_t value) = 0;\r
+               virtual void Set(int, int32_t value) = 0;\r
+               virtual void Set(int, int64_t value) = 0;\r
+               virtual void Set(int, float value) = 0;\r
+               virtual void Set(int, double value) = 0;\r
+               virtual void Set(int, const Timestamp& value) = 0;\r
+               virtual void Set(int, const Date& value) = 0;\r
+               virtual void Set(int, const Time& value) = 0;\r
+               virtual void Set(int, const DBKey& value) = 0;\r
+               virtual void Set(int, const Blob& value) = 0;\r
+               virtual void Set(int, const Array& value) = 0;\r
+\r
+               virtual bool IsNull(int) = 0;\r
+               virtual bool Get(int, bool&) = 0;\r
+               virtual bool Get(int, void*, int&) = 0; // byte buffers\r
+               virtual bool Get(int, std::string&) = 0;\r
+               virtual bool Get(int, int16_t&) = 0;\r
+               virtual bool Get(int, int32_t&) = 0;\r
+               virtual bool Get(int, int64_t&) = 0;\r
+               virtual bool Get(int, float&) = 0;\r
+               virtual bool Get(int, double&) = 0;\r
+               virtual bool Get(int, Timestamp& value) = 0;\r
+               virtual bool Get(int, Date& value) = 0;\r
+               virtual bool Get(int, Time& value) = 0;\r
+               virtual bool Get(int, DBKey& value) = 0;\r
+               virtual bool Get(int, Blob& value) = 0;\r
+               virtual bool Get(int, Array& value) = 0;\r
+\r
+               virtual bool IsNull(const std::string&) = 0;\r
+               virtual bool Get(const std::string&, bool&) = 0;\r
+               virtual bool Get(const std::string&, void*, int&) = 0;  // byte buffers\r
+               virtual bool Get(const std::string&, std::string&) = 0;\r
+               virtual bool Get(const std::string&, int16_t&) = 0;\r
+               virtual bool Get(const std::string&, int32_t&) = 0;\r
+               virtual bool Get(const std::string&, int64_t&) = 0;\r
+               virtual bool Get(const std::string&, float&) = 0;\r
+               virtual bool Get(const std::string&, double&) = 0;\r
+               virtual bool Get(const std::string&, Timestamp& value) = 0;\r
+               virtual bool Get(const std::string&, Date& value) = 0;\r
+               virtual bool Get(const std::string&, Time& value) = 0;\r
+               virtual bool Get(const std::string&, DBKey& value) = 0;\r
+               virtual bool Get(const std::string&, Blob& value) = 0;\r
+               virtual bool Get(const std::string&, Array& value) = 0;\r
+\r
+               virtual int ColumnNum(const std::string&) = 0;\r
+               virtual const char* ColumnName(int) = 0;\r
+               virtual const char* ColumnAlias(int) = 0;\r
+               virtual const char* ColumnTable(int) = 0;\r
+               virtual SDT ColumnType(int) = 0;\r
+               virtual int ColumnSubtype(int) = 0;\r
+               virtual int ColumnSize(int) = 0;\r
+               virtual int ColumnScale(int) = 0;\r
+               virtual int Columns() = 0;\r
+\r
+               virtual SDT ParameterType(int) = 0;\r
+               virtual int ParameterSubtype(int) = 0;\r
+               virtual int ParameterSize(int) = 0;\r
+               virtual int ParameterScale(int) = 0;\r
+               virtual int Parameters() = 0;\r
+\r
+               virtual void Plan(std::string&) = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IStatement* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IStatement() { };\r
+\r
+               // DEPRECATED METHODS (WON'T BE AVAILABLE IN VERSIONS 3.x)\r
+               virtual bool Get(int, char*) = 0;                                       // DEPRECATED\r
+               virtual bool Get(const std::string&, char*) = 0;        // DEPRECATED\r
+               virtual bool Get(int, bool*) = 0;                                       // DEPRECATED\r
+               virtual bool Get(const std::string&, bool*) = 0;        // DEPRECATED\r
+               virtual bool Get(int, int16_t*) = 0;                            // DEPRECATED\r
+               virtual bool Get(const std::string&, int16_t*) = 0;     // DEPRECATED\r
+               virtual bool Get(int, int32_t*) = 0;                            // DEPRECATED\r
+               virtual bool Get(const std::string&, int32_t*) = 0;     // DEPRECATED\r
+               virtual bool Get(int, int64_t*) = 0;                            // DEPRECATED\r
+               virtual bool Get(const std::string&, int64_t*) = 0;     // DEPRECATED\r
+               virtual bool Get(int, float*) = 0;                                      // DEPRECATED\r
+               virtual bool Get(const std::string&, float*) = 0;       // DEPRECATED\r
+               virtual bool Get(int, double*) = 0;                                     // DEPRECATED\r
+               virtual bool Get(const std::string&, double*) = 0;      // DEPRECATED\r
+       };\r
+       \r
+       class IEvents\r
+       {\r
+       public:\r
+               virtual void Add(const std::string&, EventInterface*) = 0;\r
+               virtual void Drop(const std::string&) = 0;\r
+               virtual void List(std::vector<std::string>&) = 0;\r
+               virtual void Clear() = 0;                               // Drop all events\r
+               virtual void Dispatch() = 0;                    // Dispatch events (calls handlers)\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+\r
+               virtual IEvents* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IEvents() { };\r
+       };\r
+       \r
+       /* Class EventInterface is merely a pure interface.\r
+        * It is _not_ implemented by IBPP. It is only a base class definition from\r
+        * which your own event interface classes have to derive from.\r
+        * Please read the reference guide at http://www.ibpp.org for more info. */\r
+\r
+       class EventInterface\r
+       {\r
+       public:\r
+               virtual void ibppEventHandler(Events, const std::string&, int) = 0;\r
+               virtual ~EventInterface() { };\r
+       };\r
+\r
+       //      --- Factories ---\r
+       //      These methods are the only way to get one of the above\r
+       //      Interfaces.  They are at the heart of how you program using IBPP.  For\r
+       //      instance, to get access to a database, you'll write code similar to this:\r
+       //      {\r
+       //              Database db = DatabaseFactory("server", "databasename",\r
+       //                                              "user", "password");\r
+       //              db->Connect();\r
+       //              ...\r
+       //              db->Disconnect();\r
+       //      }\r
+\r
+       Service ServiceFactory(const std::string& ServerName,\r
+               const std::string& UserName, const std::string& UserPassword);\r
+\r
+       Database DatabaseFactory(const std::string& ServerName,\r
+               const std::string& DatabaseName, const std::string& UserName,\r
+                       const std::string& UserPassword, const std::string& RoleName,\r
+                               const std::string& CharSet, const std::string& CreateParams);\r
+\r
+       inline Database DatabaseFactory(const std::string& ServerName,\r
+               const std::string& DatabaseName, const std::string& UserName,\r
+                       const std::string& UserPassword)\r
+               { return DatabaseFactory(ServerName, DatabaseName, UserName, UserPassword, "", "", ""); }\r
+\r
+       Transaction TransactionFactory(Database db, TAM am = amWrite,\r
+               TIL il = ilConcurrency, TLR lr = lrWait, TFF flags = TFF(0));\r
+\r
+       Statement StatementFactory(Database db, Transaction tr,\r
+               const std::string& sql);\r
+\r
+       inline Statement StatementFactory(Database db, Transaction tr)\r
+               { return StatementFactory(db, tr, ""); }\r
+\r
+       Blob BlobFactory(Database db, Transaction tr);\r
+       \r
+       Array ArrayFactory(Database db, Transaction tr);\r
+       \r
+       Events EventsFactory(Database db);\r
+\r
+       /* IBPP uses a self initialization system. Each time an object that may\r
+        * require the usage of the Interbase client C-API library is used, the\r
+        * library internal handling details are automatically initialized, if not\r
+        * already done. You can kick this initialization at the start of an\r
+        * application by calling IBPP::CheckVersion(). This is recommended, because\r
+        * IBPP::CheckVersion will assure you that YOUR code has been compiled\r
+        * against a compatible version of the library. */\r
+\r
+       bool CheckVersion(uint32_t);\r
+       int GDSVersion();\r
+       \r
+       /* On Win32 platform, ClientLibSearchPaths() allows to setup\r
+        * one or multiple additional paths (separated with a ';') where IBPP\r
+        * will look for the client library (before the default implicit search\r
+        * locations). This is usefull for applications distributed with a 'private'\r
+        * copy of Firebird, when the registry is useless to identify the location\r
+        * from where to attempt loading the fbclient.dll / gds32.dll.\r
+        * If called, this function must be called *early* by the application,\r
+        * before *any* other function or object methods of IBPP.\r
+        * Currently, this is a NO-OP on platforms other than Win32. */\r
+        \r
+       void ClientLibSearchPaths(const std::string&);\r
+\r
+       /* Finally, here are some date and time conversion routines used by IBPP and\r
+        * that may be helpful at the application level. They do not depend on\r
+        * anything related to Firebird/Interbase. Just a bonus. dtoi and itod\r
+        * return false on invalid parameters or out of range conversions. */\r
+\r
+       bool dtoi(int date, int* py, int* pm, int* pd);\r
+       bool itod(int* pdate, int year, int month, int day);\r
+       void ttoi(int itime, int* phour, int* pminute, int* psecond, int* ptt);\r
+       void itot(int* ptime, int hour, int minute, int second = 0, int tenthousandths = 0);\r
+\r
+}\r
+\r
+#endif\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/include/lp2_blocks.h b/include/lp2_blocks.h
new file mode 100644 (file)
index 0000000..fddab42
--- /dev/null
@@ -0,0 +1,82 @@
+#define setPBlockStart(qwer) asm("subb $0x20,l_"#qwer"SC1\n"\
+"l_"#qwer"SC1: .byte 0x80\n"\
+"              addb $0x20,l_"#qwer"SC1\n"\
+" jmp l_"#qwer"Decryptor\n\t"\
+ ".string \"m_TCodeStart\"\n\t"\
+  "    l_"#qwer"TCodeStart: nop\n\t")
+
+
+#define setPBlockEnd(qwer) asm("               jmp l_"#qwer"Cryptor\n"\
+"              .string \"m_TCodeEnd\"\n"\
+"              nop\n"\
+"              nop\n"\
+"              nop\n"\
+"              nop\n"\
+"      .string \"m_PCodeEP\"\n"\
+"l_"#qwer"Cryptor:     movl d_"#qwer"Length,%edx\n"\
+"              subl $4,%edx \n"\
+"l_"#qwer"Cryptor_l1:  movl $28,%eax\n"\
+"l_"#qwer"Cryptor_l2:  movl $d_"#qwer"Password,%ebx\n"\
+"              movl (%eax,%ebx),%ecx\n"\
+"              movl d_"#qwer"Start_Adr,%ebx\n"\
+"              xorl %ecx,(%ebx,%edx)\n"\
+"              rorl %cl,(%ebx,%edx)\n"\
+"              subl $4,%edx\n"\
+"              js   l_"#qwer"Cryptor_ex1\n"\
+"              subl $4,%eax\n"\
+"              js   l_"#qwer"Cryptor_l1\n"\
+"              jmp l_"#qwer"Cryptor_l2\n"\
+"l_"#qwer"Cryptor_ex1: jmp l_"#qwer"Exit\n"\
+"l_"#qwer"Decryptor:   movl d_"#qwer"Length,%edx\n"\
+"              subl $4,%edx \n"\
+"l_"#qwer"Decryptor_l1:movl $28,%eax\n"\
+"l_"#qwer"Decryptor_l2:movl $d_"#qwer"Password,%ebx\n"\
+"              movl (%eax,%ebx),%ecx\n"\
+"              movl d_"#qwer"Start_Adr,%ebx\n"\
+"              roll %cl,(%ebx,%edx)\n"\
+"              xorl %ecx,(%ebx,%edx)\n"\
+"              subl $4,%edx\n"\
+"              js l_"#qwer"Decryptor_ex1\n"\
+"              subl $4,%eax\n"\
+"              js l_"#qwer"Decryptor_l1\n"\
+"              jmp l_"#qwer"Decryptor_l2\n"\
+"l_"#qwer"Decryptor_ex1:jmp l_"#qwer"TCodeStart\n"\
+"d_"#qwer"Start_Adr:   .string \"m_TCodeStartAdr\"\n"\
+"d_"#qwer"Length:      .string \"m_TCodeLength\"\n"\
+"d_"#qwer"Password:.string \"m_TCodePass\"\n"\
+"           .string  \"_trfgfgfgfdfgfdfgfdfg\"\n"\
+"      .string \"m_PCodeRet\"\n"\
+"l_"#qwer"Exit:        addb $0x19,l_"#qwer"SC2\n"\
+"l_"#qwer"SC2:         .byte 0x48\n"\
+"              subb $0x19,l_"#qwer"SC2\n")
+
+#define DecryptROData \
+asm(\
+"                      .string \"m_ROEP\"\n"\
+"                      subb $0x20,l_ro_SC1\n"\
+"l_ro_SC1:             .byte 0x80\n"\
+"                      addb $0x20,l_ro_SC1\n"\
+"l_ro_Decryptor:       movl d_ro_Length,%edx\n"\
+"                      subl $4,%edx \n"\
+"l_ro_Decryptor_l1:    movl $28,%eax\n"\
+"l_ro_Decryptor_l2:    movl $d_ro_Password,%ebx\n"\
+"                      movl (%eax,%ebx),%ecx\n"\
+"                      movl d_ro_Start_Adr,%ebx\n"\
+"                      roll %cl,(%ebx,%edx)\n"\
+"                      subl $4,%edx\n"\
+"                      js l_ro_Exit\n"\
+"                      subl $4,%eax\n"\
+"                      js l_ro_Decryptor_l1\n"\
+"                      jmp l_ro_Decryptor_l2\n"\
+"d_ro_Start_Adr:       .string \"m_ROStartAdr\"\n"\
+"d_ro_Length:          .string \"m_ROLength\"\n"\
+"d_ro_ExitAdr:         .string \"m_ROExitAdr\"\n"\
+"d_ro_Password:                .string \"m_ROPass\"\n"\
+"                      .string  \"_trfgfgfgfdfgfdfgfdfg____\"\n"\
+"l_ro_Exit:            .byte 0x61\n"\
+"                      push d_ro_ExitAdr\n"\
+"                      ret\n")
+
+
+
+
diff --git a/include/mimetype.h b/include/mimetype.h
new file mode 100644 (file)
index 0000000..a5f8487
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+ *****************************************************************************\r
+ *\r
+ * File:        mimetype.h\r
+ *\r
+ * Description: TODO:\r
+ *\r
+ * $Id: mimetype.h,v 1.1.1.1 2005/10/09 11:00:45 nobunaga Exp $\r
+ *\r
+ *****************************************************************************\r
+ */\r
+\r
+#ifndef _MIMETYPE_H\r
+#define _MIMETYPE_H_\r
+\r
+\r
+struct MIMETYPE\r
+    {\r
+    char *ext;\r
+    char *type;\r
+    };\r
+\r
+const MIMETYPE mTypes[]=\r
+{\r
+    { ".jpg" , "image/jpeg" },\r
+    { ".gif", "image/gif" },\r
+    { ".jpeg", "image/jpeg" },\r
+    { ".htm", "text/html" },\r
+    { ".html", "text/html" },\r
+    { ".txt", "text/plain" },\r
+    { ".css", "text/css" }\r
+};\r
+\r
+#endif /* _MIMETYPE_H_ */\r
+\r
+/* EOF */\r
+\r
diff --git a/include/noncopyable.h b/include/noncopyable.h
new file mode 100644 (file)
index 0000000..3d4c53b
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __NONCOPYABLE_H__
+#define __NONCOPYABLE_H__
+
+class NONCOPYABLE
+{
+protected:
+    NONCOPYABLE() {}
+    virtual ~NONCOPYABLE() {}
+private:  // emphasize the following members are private
+    NONCOPYABLE(const NONCOPYABLE &);
+    const NONCOPYABLE & operator=(const NONCOPYABLE &);
+};
+
+#endif
diff --git a/include/notifer.h b/include/notifer.h
new file mode 100644 (file)
index 0000000..57f9928
--- /dev/null
@@ -0,0 +1,29 @@
+ /*
+ $Revision: 1.6 $
+ $Date: 2007/12/03 09:00:17 $
+ $Author: nobunaga $
+ */
+
+#ifndef PROPERTY_NOTIFER_H
+#define PROPERTY_NOTIFER_H
+
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class PROPERTY_NOTIFIER_BASE
+{
+public:
+    virtual      ~PROPERTY_NOTIFIER_BASE(){};
+    virtual void Notify(const varParamType & oldValue, const varParamType & newValue) = 0;
+};
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class NOTIFIER_BASE
+{
+public:
+    virtual      ~NOTIFIER_BASE(){};
+    virtual void Notify(const varParamType & value) = 0;
+};
+//-----------------------------------------------------------------------------
+#endif //PROPERTY_NOTIFER_H
+
+
diff --git a/include/os_int.h b/include/os_int.h
new file mode 100644 (file)
index 0000000..cc017b8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.4 $
+ $Date: 2008/03/25 17:41:50 $
+ */
+
+
+#ifndef OS_INT_H
+#define OS_INT_H
+
+#ifdef LINUX
+#include <stdint.h>
+#endif
+
+#ifdef FREE_BSD5
+#include <inttypes.h>
+#endif
+
+#ifdef FREE_BSD
+#include <sys/inttypes.h>
+#endif
+
+#ifdef WIN32
+
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+typedef short int int16_t;
+typedef short unsigned int uint16_t;
+
+typedef char int8_t;
+typedef unsigned char uint8_t;
+
+
+#endif
+
+
+#endif
+
diff --git a/include/rad_packets.h b/include/rad_packets.h
new file mode 100644 (file)
index 0000000..96cddc4
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef RAD_PACKETSH
+#define RAD_PACKETSH
+
+#define RAD_MAGIC_LEN        (5)
+#define RAD_PROTO_VER_LEN    (2)
+#define RAD_MAX_PACKET_LEN   (1024)
+#define RAD_LOGIN_LEN        (32)
+#define RAD_SERVICE_LEN        (16)
+#define RAD_PASSWORD_LEN        (32)
+#define RAD_SESSID_LEN        (32)
+
+// Request
+#define RAD_AUTZ_PACKET      (0)
+#define RAD_AUTH_PACKET      (1)
+#define RAD_POST_AUTH_PACKET (2)
+#define RAD_ACCT_START_PACKET (3)
+#define RAD_ACCT_STOP_PACKET (4)
+#define RAD_ACCT_UPDATE_PACKET (5)
+#define RAD_ACCT_OTHER_PACKET (6)
+// Responce
+#define RAD_ACCEPT_PACKET    (7)
+#define RAD_REJECT_PACKET    (8)
+
+#define RAD_ID "00100"
+
+#include "os_int.h"
+
+struct RAD_PACKET
+{
+uint8_t              magic[RAD_MAGIC_LEN];
+uint8_t              protoVer[RAD_PROTO_VER_LEN];
+uint8_t              packetType;
+uint8_t              login[RAD_LOGIN_LEN];
+uint32_t             ip;
+uint8_t              service[RAD_SERVICE_LEN];
+uint8_t              password[RAD_PASSWORD_LEN];
+uint8_t              sessid[RAD_SESSID_LEN];
+uint8_t              padding[4];
+};
+
+#endif
diff --git a/include/raw_ip_packet.h b/include/raw_ip_packet.h
new file mode 100644 (file)
index 0000000..af62d05
--- /dev/null
@@ -0,0 +1,214 @@
+#ifndef RAW_IP_PACKET_H
+#define RAW_IP_PACKET_H
+
+#include <netinet/in.h> // for htons
+#include <netinet/ip.h> // for struct ip
+
+#include <cstring>
+
+#include "stg_const.h"
+#include "common.h"
+
+#define IPv4 (2)
+
+enum { pcktSize = 68 }; //60(max) ip + 8 udp or tcp (part of tcp or udp header to ports)
+//-----------------------------------------------------------------------------
+struct RAW_PACKET
+{
+    RAW_PACKET()
+        : dataLen(-1)
+    {
+    memset(pckt, 0, pcktSize);
+    }
+
+    RAW_PACKET(const RAW_PACKET & rp)
+        : dataLen(rp.dataLen)
+    {
+    memcpy(pckt, rp.pckt, pcktSize);
+    }
+
+uint16_t    GetIPVersion() const;
+uint8_t     GetHeaderLen() const;
+uint8_t     GetProto() const;
+uint32_t    GetLen() const;
+uint32_t    GetSrcIP() const;
+uint32_t    GetDstIP() const;
+uint16_t    GetSrcPort() const;
+uint16_t    GetDstPort() const;
+
+bool        operator==(const RAW_PACKET & rvalue) const;
+bool        operator!=(const RAW_PACKET & rvalue) const { return !(*this == rvalue); };
+bool        operator<(const RAW_PACKET & rvalue) const;
+
+union
+    {
+    uint8_t     pckt[pcktSize];         // îÁÞÁÌÏ ÐÁËÅÔÁ ÚÁÈ×ÁÞÅÎÎÏÇÏ ÉÚ ÓÅÔÉ
+    struct
+        {
+        struct ip   ipHeader;
+        // Only for packets without options field
+        uint16_t    sPort;
+        uint16_t    dPort;
+        } __attribute__ ((packed));
+    };
+int32_t     dataLen;                // äÌÉÎÁ IP ÐÁËÅÔÁ. åÓÌÉ -1, ÔÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÄÌÉÎÕ ÉÚ ÚÁÇÏÌÏ×ËÁ ÓÁÍÏÇÏ ÐÁËÅÔÁ.
+};
+//-----------------------------------------------------------------------------
+inline uint16_t RAW_PACKET::GetIPVersion() const
+{
+return ipHeader.ip_v;
+}
+//-----------------------------------------------------------------------------
+inline uint8_t RAW_PACKET::GetHeaderLen() const
+{
+return ipHeader.ip_hl * 4;
+}
+//-----------------------------------------------------------------------------
+inline uint8_t RAW_PACKET::GetProto() const
+{
+return ipHeader.ip_p;
+}
+//-----------------------------------------------------------------------------
+inline uint32_t RAW_PACKET::GetLen() const
+{
+if (dataLen != -1)
+    return dataLen;
+return ntohs(ipHeader.ip_len);
+}
+//-----------------------------------------------------------------------------
+inline uint32_t RAW_PACKET::GetSrcIP() const
+{
+return ipHeader.ip_src.s_addr;
+}
+//-----------------------------------------------------------------------------
+inline uint32_t RAW_PACKET::GetDstIP() const
+{
+return ipHeader.ip_dst.s_addr;
+}
+//-----------------------------------------------------------------------------
+inline uint16_t RAW_PACKET::GetSrcPort() const
+{
+if (ipHeader.ip_p == 1) // for icmp proto return port 0
+    return 0;
+return ntohs(*((uint16_t*)(pckt + ipHeader.ip_hl * 4)));
+}
+//-----------------------------------------------------------------------------
+inline uint16_t RAW_PACKET::GetDstPort() const
+{
+if (ipHeader.ip_p == 1) // for icmp proto return port 0
+    return 0;
+return ntohs(*((uint16_t*)(pckt + ipHeader.ip_hl * 4 + 2)));
+}
+//-----------------------------------------------------------------------------
+inline bool RAW_PACKET::operator==(const RAW_PACKET & rvalue) const
+{
+if (ipHeader.ip_src.s_addr != rvalue.ipHeader.ip_src.s_addr)
+    return false;
+
+if (ipHeader.ip_dst.s_addr != rvalue.ipHeader.ip_dst.s_addr)
+    return false;
+
+if (ipHeader.ip_p != 1 && rvalue.ipHeader.ip_p != 1)
+    {
+    if (*((uint16_t *)(pckt + ipHeader.ip_hl * 4)) !=
+        *((uint16_t *)(rvalue.pckt + rvalue.ipHeader.ip_hl * 4)))
+        return false;
+
+    if (*((uint16_t *)(pckt + ipHeader.ip_hl * 4 + 2)) !=
+        *((uint16_t *)(rvalue.pckt + rvalue.ipHeader.ip_hl * 4 + 2)))
+        return false;
+    }
+
+if (ipHeader.ip_p != rvalue.ipHeader.ip_p)
+    return false;
+
+return true;
+}
+/*//-----------------------------------------------------------------------------
+inline bool operator==(const RAW_PACKET & lhs, const RAW_PACKET & rhs) 
+{
+if (lhs.GetSrcIP() != rhs.GetSrcIP())
+    return false;
+
+if (lhs.GetDstIP() != rhs.GetDstIP())
+    return false;
+
+if (lhs.GetSrcPort() != rhs.GetSrcPort())
+    return false;
+
+if (lhs.GetDstPort() != rhs.GetDstPort())
+    return false;
+
+if (lhs.GetProto() != rhs.GetProto())
+    return false;
+
+return true;
+}*/
+//-----------------------------------------------------------------------------
+inline bool RAW_PACKET::operator<(const RAW_PACKET & rvalue) const
+{
+if (ipHeader.ip_src.s_addr < rvalue.ipHeader.ip_src.s_addr) 
+    return true;
+if (ipHeader.ip_src.s_addr > rvalue.ipHeader.ip_src.s_addr) 
+    return false;
+
+if (ipHeader.ip_dst.s_addr < rvalue.ipHeader.ip_dst.s_addr) 
+    return true;
+if (ipHeader.ip_dst.s_addr > rvalue.ipHeader.ip_dst.s_addr) 
+    return false;
+
+if (ipHeader.ip_p != 1 && rvalue.ipHeader.ip_p != 1)
+    {
+    if (*((uint16_t *)(pckt + ipHeader.ip_hl * 4)) <
+        *((uint16_t *)(rvalue.pckt + rvalue.ipHeader.ip_hl * 4))) 
+        return true;
+    if (*((uint16_t *)(pckt + ipHeader.ip_hl * 4)) >
+        *((uint16_t *)(rvalue.pckt + rvalue.ipHeader.ip_hl * 4))) 
+        return false;
+
+    if (*((uint16_t *)(pckt + ipHeader.ip_hl * 4 + 2)) <
+        *((uint16_t *)(rvalue.pckt + rvalue.ipHeader.ip_hl * 4 + 2))) 
+        return true;
+    if (*((uint16_t *)(pckt + ipHeader.ip_hl * 4 + 2)) >
+        *((uint16_t *)(rvalue.pckt + rvalue.ipHeader.ip_hl * 4 + 2))) 
+        return false;
+    }
+
+if (ipHeader.ip_p < rvalue.ipHeader.ip_p) 
+    return true;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+/*inline bool operator<(const RAW_PACKET & lhs, const RAW_PACKET & rhs)
+{
+if (lhs.GetSrcIP() < rhs.GetSrcIP()) 
+    return true;
+if (lhs.GetSrcIP() > rhs.GetSrcIP()) 
+    return false;
+
+if (lhs.GetDstIP() < rhs.GetDstIP()) 
+    return true;
+if (lhs.GetDstIP() > rhs.GetDstIP()) 
+    return false;
+
+if (lhs.GetSrcPort() < rhs.GetSrcPort()) 
+    return true;
+if (lhs.GetSrcPort() > rhs.GetSrcPort()) 
+    return false;
+
+if (lhs.GetDstPort() < rhs.GetDstPort()) 
+    return true;
+if (lhs.GetDstPort() > rhs.GetDstPort()) 
+    return false;
+
+if (lhs.GetProto() < rhs.GetProto()) 
+    return true;
+
+return false;
+}*/
+//-----------------------------------------------------------------------------
+
+#endif
+
+
diff --git a/include/resetable.h b/include/resetable.h
new file mode 100644 (file)
index 0000000..d31bffd
--- /dev/null
@@ -0,0 +1,98 @@
+ /*
+ $Revision: 1.9 $
+ $Date: 2010/03/11 14:42:04 $
+ $Author: faust $
+ */
+
+/*
+ * Copyright (c) 2001 by Peter Simons <simons@cryp.to>.
+ * All rights reserved.
+ */
+
+#ifndef RESETABLE_VARIABLE_H
+#define RESETABLE_VARIABLE_H
+
+// This is a wrapper class about variables where you want to keep
+// track of whether it has been assigened yet or not.
+
+#include <iostream>
+
+template <typename varT>
+class RESETABLE
+{
+    template <typename varT1>
+    friend std::ostream & operator<<(std::ostream & o, RESETABLE<varT1> v);
+public:
+    typedef varT value_type;
+
+    //-------------------------------------------------------------------------
+    RESETABLE()
+        : value(),
+          is_set(false)
+    {
+    }
+    //-------------------------------------------------------------------------
+    RESETABLE<value_type>(const RESETABLE<value_type> & rvalue)
+        : value(rvalue.value),
+          is_set(rvalue.is_set)
+    {
+    }
+    //-------------------------------------------------------------------------
+    RESETABLE(const value_type& val)
+        : value(val),
+          is_set(true)
+    {
+    }
+    //-------------------------------------------------------------------------
+    RESETABLE<value_type> & operator=(const RESETABLE<value_type> & rvalue)
+    {
+        value = rvalue.value;
+        is_set = rvalue.is_set;
+        return *this;
+    }
+    //-------------------------------------------------------------------------
+    RESETABLE<value_type> & operator= (const value_type& rhs)
+    {
+        value = rhs;
+        is_set = true;
+        return *this;
+    }
+    //-------------------------------------------------------------------------
+    const value_type& const_data() const throw()
+    {
+        return value;
+    }
+    //-------------------------------------------------------------------------
+    value_type& data() throw()
+    {
+        return value;
+    }
+    //-------------------------------------------------------------------------
+    operator const value_type&() const throw()
+    {
+        return value;
+    }
+    //-------------------------------------------------------------------------
+    bool res_empty() const throw()
+    {
+        return !is_set;
+    }
+    //-------------------------------------------------------------------------
+    void reset() throw()
+    {
+        is_set = false;
+    }
+    //-------------------------------------------------------------------------
+protected:
+    value_type  value;
+    bool        is_set;
+};
+//-----------------------------------------------------------------------------
+template <typename varT>
+std::ostream & operator<<(std::ostream & o, RESETABLE<varT> v)
+{
+    return o << v.value;
+}
+//-------------------------------------------------------------------------
+#endif // RESETABLE_VARIABLE_H
+
diff --git a/include/rs_packets.h b/include/rs_packets.h
new file mode 100644 (file)
index 0000000..1a038be
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef RS_PACKETSH
+#define RS_PACKETSH
+
+#define RS_MAGIC_LEN        (6)
+#define RS_PROTO_VER_LEN    (2)
+#define RS_MAX_PACKET_LEN   (1048)
+#define RS_LOGIN_LEN        (32)
+#define RS_PARAMS_LEN       (979)
+
+#define RS_ALIVE_PACKET      (0)
+#define RS_CONNECT_PACKET    (1)
+#define RS_DISCONNECT_PACKET (2)
+
+#define RS_ID "RSP00"
+
+#include "os_int.h"
+
+struct RS_PACKET_HEADER
+{
+int8_t              magic[RS_MAGIC_LEN];
+int8_t              protoVer[RS_PROTO_VER_LEN];
+int8_t              packetType;
+uint32_t            ip;
+uint32_t            id;
+int8_t              login[RS_LOGIN_LEN];
+int8_t              padding[7];
+} __attribute__((__packed__)); // 48 bytes, 6 blocks
+
+struct RS_PACKET_TAIL
+{
+int8_t              magic[RS_MAGIC_LEN];
+int8_t              params[RS_PARAMS_LEN];
+int8_t              padding[7];
+} __attribute__((__packed__)); // 992 bytes, 124 blocks
+
+#endif
diff --git a/include/service_conf.h b/include/service_conf.h
new file mode 100644 (file)
index 0000000..6c958c4
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef SERVICE_CONF_H
+#define SERVICE_CONF_H
+
+struct SERVICE_CONF
+{
+string  name;
+string  comment;
+double  cost;
+int     payDay;
+};
+
+#endif //SERVICE_CONF_H
+
diff --git a/include/stdstring.h b/include/stdstring.h
new file mode 100644 (file)
index 0000000..dde89e9
--- /dev/null
@@ -0,0 +1,3737 @@
+// =============================================================================\r
+//  FILE:  StdString.h\r
+//  AUTHOR:    Joe O'Leary (with outside help noted in comments)\r
+//  REMARKS:\r
+//             This header file declares the CStdStr template.  This template derives\r
+//             the Standard C++ Library basic_string<> template and add to it the\r
+//             the following conveniences:\r
+//                     - The full MFC CString set of functions (including implicit cast)\r
+//                     - writing to/reading from COM IStream interfaces\r
+//                     - Functional objects for use in STL algorithms\r
+//\r
+//             From this template, we intstantiate two classes:  CStdStringA and\r
+//             CStdStringW.  The name "CStdString" is just a #define of one of these,\r
+//             based upone the _UNICODE macro setting\r
+//\r
+//             This header also declares our own version of the MFC/ATL UNICODE-MBCS\r
+//             conversion macros.  Our version looks exactly like the Microsoft's to\r
+//             facilitate portability.\r
+//\r
+//     NOTE:\r
+//             If you you use this in an MFC or ATL build, you should include either\r
+//             afx.h or atlbase.h first, as appropriate.\r
+//\r
+//     PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:\r
+//\r
+//             Several people have helped me iron out problems and othewise improve\r
+//             this class.  OK, this is a long list but in my own defense, this code\r
+//             has undergone two major rewrites.  Many of the improvements became\r
+//             necessary after I rewrote the code as a template.  Others helped me\r
+//             improve the CString facade.\r
+//\r
+//             Anyway, these people are (in chronological order):\r
+//\r
+//                     - Pete the Plumber (???)\r
+//                     - Julian Selman\r
+//                     - Chris (of Melbsys)\r
+//                     - Dave Plummer\r
+//                     - John C Sipos\r
+//                     - Chris Sells\r
+//                     - Nigel Nunn\r
+//                     - Fan Xia\r
+//                     - Matthew Williams\r
+//                     - Carl Engman\r
+//                     - Mark Zeren\r
+//                     - Craig Watson\r
+//                     - Rich Zuris\r
+//                     - Karim Ratib\r
+//                     - Chris Conti\r
+//                     - Baptiste Lepilleur\r
+//                     - Greg Pickles\r
+//                     - Jim Cline\r
+//                     - Jeff Kohn\r
+//                     - Todd Heckel\r
+//                     - Ullrich Pollähne\r
+//                     - Joe Vitaterna\r
+//                     - Joe Woodbury\r
+//                     - Aaron (no last name)\r
+//                     - Joldakowski (???)\r
+//                     - Scott Hathaway\r
+//                     - Eric Nitzche\r
+//                     - Pablo Presedo\r
+//                     - Farrokh Nejadlotfi\r
+//                     - Jason Mills\r
+//                     - Igor Kholodov\r
+//                     - Mike Crusader\r
+//                     - John James\r
+//                     - Wang Haifeng\r
+//                     - Tim Dowty\r
+//          - Arnt Witteveen\r
+//          - Glen Maynard\r
+//          - Paul DeMarco\r
+//          - Bagira (full name?)\r
+//          - Ronny Schulz\r
+//          - Jakko Van Hunen\r
+//                     - Charles G\r
+//\r
+//     REVISION HISTORY\r
+//    2003-JUL-10 - Thanks to Charles G for making me realize my 'FmtArg' fixes\r
+//                  had inadvertently broken the DLL-export code (which is\r
+//                  normally commented out.  I had to move it up higher.  Also\r
+//                                     this helped me catch a bug in ssicoll that would prevent\r
+//                  compilation, otherwise.\r
+//\r
+//    2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste\r
+//                  bug in one of the overloads of FmtArg.\r
+//\r
+//    2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes\r
+//                  to help CStdString build on SGI and for pointing out an\r
+//                  error in placement of my preprocessor macros for ssfmtmsg.\r
+//\r
+//    2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of\r
+//                  SpanExcluding was not properly handling the case in which\r
+//                  the string did NOT contain any of the given characters\r
+//\r
+//    2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me\r
+//                  get this code working with Borland's free compiler as well\r
+//                  as the Dev-C++ compiler (available free at SourceForge).\r
+//\r
+//    2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud\r
+//                  but harmless warnings that were showing up on g++.  Glen\r
+//                  also pointed out that some pre-declarations of FmtArg<>\r
+//                  specializations were unnecessary (and no good on G++)\r
+//\r
+//    2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using\r
+//                  static_cast<> in a place in which I should have been using\r
+//                  reinterpret_cast<> (the ctor for unsigned char strings).\r
+//                  That's what happens when I don't unit-test properly!\r
+//                  Arnt also noticed that CString was silently correcting the\r
+//                  'nCount' argument to Left() and Right() where CStdString was\r
+//                  not (and crashing if it was bad).  That is also now fixed!\r
+//\r
+//       2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix\r
+//                                     for) a conversion problem with non-ASCII MBCS characters.\r
+//                                     CStdString is now used in my favorite commercial MP3 player!\r
+//\r
+//       2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the\r
+//                                     assignment operators (for _bstr_t) that would cause compiler\r
+//                                     errors when refcounting protection was turned off.\r
+//\r
+//       2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators\r
+//                                     due to a conflict with the rel_ops operator!=.  Thanks to\r
+//                                     John James for pointing this out.\r
+//\r
+//    2001-OCT-29 - Added a minor range checking fix for the Mid function to\r
+//                                     make it as forgiving as CString's version is.  Thanks to\r
+//                                     Igor Kholodov for noticing this.  \r
+//                               - Added a specialization of std::swap for CStdString.  Thanks\r
+//                                     to Mike Crusader for suggesting this!  It's commented out\r
+//                                     because you're not supposed to inject your own code into the\r
+//                                     'std' namespace.  But if you don't care about that, it's\r
+//                                     there if you want it\r
+//                               - Thanks to Jason Mills for catching a case where CString was\r
+//                                     more forgiving in the Delete() function than I was.\r
+//\r
+//       2001-JUN-06 - I was violating the Standard name lookup rules stated\r
+//                                     in [14.6.2(3)].  None of the compilers I've tried so\r
+//                                     far apparently caught this but HP-UX aCC 3.30 did.  The\r
+//                                     fix was to add 'this->' prefixes in many places.\r
+//                                     Thanks to Farrokh Nejadlotfi for this!\r
+//\r
+//       2001-APR-27 - StreamLoad was calculating the number of BYTES in one\r
+//                                     case, not characters.  Thanks to Pablo Presedo for this.\r
+//\r
+//    2001-FEB-23 - Replace() had a bug which caused infinite loops if the\r
+//                                     source string was empty.  Fixed thanks to Eric Nitzsche.\r
+//\r
+//    2001-FEB-23 - Scott Hathaway was a huge help in providing me with the\r
+//                                     ability to build CStdString on Sun Unix systems.  He\r
+//                                     sent me detailed build reports about what works and what\r
+//                                     does not.  If CStdString compiles on your Unix box, you\r
+//                                     can thank Scott for it.\r
+//\r
+//       2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a\r
+//                                     range check as CString's does.  Now fixed -- thanks!\r
+//\r
+//       2000-NOV-07 - Aaron pointed out that I was calling static member\r
+//                                     functions of char_traits via a temporary.  This was not\r
+//                                     technically wrong, but it was unnecessary and caused\r
+//                                     problems for poor old buggy VC5.  Thanks Aaron!\r
+//\r
+//       2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match\r
+//                                     what the CString::Find code really ends up doing.   I was\r
+//                                     trying to match the docs.  Now I match the CString code\r
+//                               - Joe also caught me truncating strings for GetBuffer() calls\r
+//                                     when the supplied length was less than the current length.\r
+//\r
+//       2000-MAY-25 - Better support for STLPORT's Standard library distribution\r
+//                               - Got rid of the NSP macro - it interfered with Koenig lookup\r
+//                               - Thanks to Joe Woodbury for catching a TrimLeft() bug that\r
+//                                     I introduced in January.  Empty strings were not getting\r
+//                                     trimmed\r
+//\r
+//       2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind\r
+//                                     is supposed to be a const function.\r
+//\r
+//       2000-MAR-07 - Thanks to Ullrich Pollähne for catching a range bug in one\r
+//                                     of the overloads of assign.\r
+//\r
+//    2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!\r
+//                                     Thanks to Todd Heckel for helping out with this.\r
+//\r
+//       2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the\r
+//                                     Trim() function more efficient.\r
+//                               - Thanks to Jeff Kohn for prompting me to find and fix a typo\r
+//                                     in one of the addition operators that takes _bstr_t.\r
+//                               - Got rid of the .CPP file -  you only need StdString.h now!\r
+//\r
+//       1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem\r
+//                                     with my implementation of CStdString::FormatV in which\r
+//                                     resulting string might not be properly NULL terminated.\r
+//\r
+//       1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment\r
+//                                     bug that MS has not fixed.  CStdString did nothing to fix\r
+//                                     it either but it does now!  The bug was: create a string\r
+//                                     longer than 31 characters, get a pointer to it (via c_str())\r
+//                                     and then assign that pointer to the original string object.\r
+//                                     The resulting string would be empty.  Not with CStdString!\r
+//\r
+//       1999-OCT-06 - BufferSet was erasing the string even when it was merely\r
+//                                     supposed to shrink it.  Fixed.  Thanks to Chris Conti.\r
+//                               - Some of the Q172398 fixes were not checking for assignment-\r
+//                                     to-self.  Fixed.  Thanks to Baptiste Lepilleur.\r
+//\r
+//       1999-AUG-20 - Improved Load() function to be more efficient by using \r
+//                                     SizeOfResource().  Thanks to Rich Zuris for this.\r
+//                               - Corrected resource ID constructor, again thanks to Rich.\r
+//                               - Fixed a bug that occurred with UNICODE characters above\r
+//                                     the first 255 ANSI ones.  Thanks to Craig Watson. \r
+//                               - Added missing overloads of TrimLeft() and TrimRight().\r
+//                                     Thanks to Karim Ratib for pointing them out\r
+//\r
+//       1999-JUL-21 - Made all calls to GetBuf() with no args check length first.\r
+//\r
+//       1999-JUL-10 - Improved MFC/ATL independence of conversion macros\r
+//                               - Added SS_NO_REFCOUNT macro to allow you to disable any\r
+//                                     reference-counting your basic_string<> impl. may do.\r
+//                               - Improved ReleaseBuffer() to be as forgiving as CString.\r
+//                                     Thanks for Fan Xia for helping me find this and to\r
+//                                     Matthew Williams for pointing it out directly.\r
+//\r
+//       1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in\r
+//                                     ToLower/ToUpper.  They should call GetBuf() instead of\r
+//                                     data() in order to ensure the changed string buffer is not\r
+//                                     reference-counted (in those implementations that refcount).\r
+//\r
+//       1999-JUL-01 - Added a true CString facade.  Now you can use CStdString as\r
+//                                     a drop-in replacement for CString.  If you find this useful,\r
+//                                     you can thank Chris Sells for finally convincing me to give\r
+//                                     in and implement it.\r
+//                               - Changed operators << and >> (for MFC CArchive) to serialize\r
+//                                     EXACTLY as CString's do.  So now you can send a CString out\r
+//                                     to a CArchive and later read it in as a CStdString.   I have\r
+//                                     no idea why you would want to do this but you can. \r
+//\r
+//       1999-JUN-21 - Changed the CStdString class into the CStdStr template.\r
+//                               - Fixed FormatV() to correctly decrement the loop counter.\r
+//                                     This was harmless bug but a bug nevertheless.  Thanks to\r
+//                                     Chris (of Melbsys) for pointing it out\r
+//                               - Changed Format() to try a normal stack-based array before\r
+//                                     using to _alloca().\r
+//                               - Updated the text conversion macros to properly use code\r
+//                                     pages and to fit in better in MFC/ATL builds.  In other\r
+//                                     words, I copied Microsoft's conversion stuff again. \r
+//                               - Added equivalents of CString::GetBuffer, GetBufferSetLength\r
+//                               - new sscpy() replacement of CStdString::CopyString()\r
+//                               - a Trim() function that combines TrimRight() and TrimLeft().\r
+//\r
+//       1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()\r
+//                                     instead of _isspace()   Thanks to Dave Plummer for this.\r
+//\r
+//       1999-FEB-26 - Removed errant line (left over from testing) that #defined\r
+//                                     _MFC_VER.  Thanks to John C Sipos for noticing this.\r
+//\r
+//       1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that\r
+//                                     caused infinite recursion and stack overflow\r
+//                               - Added member functions to simplify the process of\r
+//                                     persisting CStdStrings to/from DCOM IStream interfaces \r
+//                               - Added functional objects (e.g. StdStringLessNoCase) that\r
+//                                     allow CStdStrings to be used as keys STL map objects with\r
+//                                     case-insensitive comparison \r
+//                               - Added array indexing operators (i.e. operator[]).  I\r
+//                                     originally assumed that these were unnecessary and would be\r
+//                                     inherited from basic_string.  However, without them, Visual\r
+//                                     C++ complains about ambiguous overloads when you try to use\r
+//                                     them.  Thanks to Julian Selman to pointing this out. \r
+//\r
+//       1998-FEB-?? - Added overloads of assign() function to completely account\r
+//                                     for Q172398 bug.  Thanks to "Pete the Plumber" for this\r
+//\r
+//       1998-FEB-?? - Initial submission\r
+//\r
+// COPYRIGHT:\r
+//             2002 Joseph M. O'Leary.  This code is 100% free.  Use it anywhere you\r
+//      want.  Rewrite it, restructure it, whatever.  If you can write software\r
+//      that makes money off of it, good for you.  I kinda like capitalism. \r
+//      Please don't blame me if it causes your $30 billion dollar satellite\r
+//      explode in orbit.  If you redistribute it in any form, I'd appreciate it\r
+//      if you would leave this notice here.\r
+//\r
+//             If you find any bugs, please let me know:\r
+//\r
+//                             jmoleary@earthlink.net\r
+//                             http://www.joeo.net\r
+//\r
+//      The latest version of this code should always be available at the\r
+//      following link:\r
+//\r
+//              http://www.joeo.net/code/StdString.zip\r
+// =============================================================================\r
+\r
+// Avoid multiple inclusion the VC++ way,\r
+// Turn off browser references\r
+// Turn off unavoidable compiler warnings\r
+\r
+#if defined(_MSC_VER) && (_MSC_VER > 1100)\r
+       #pragma once\r
+       #pragma component(browser, off, references, "CStdString")\r
+       #pragma warning (disable : 4290) // C++ Exception Specification ignored\r
+       #pragma warning (disable : 4127) // Conditional expression is constant\r
+       #pragma warning (disable : 4097) // typedef name used as synonym for class name\r
+#endif\r
+\r
+// Borland warnings to turn off\r
+#ifdef __BORLANDC__\r
+    #pragma option push -w-inl\r
+//     #pragma warn -inl   // Turn off inline function warnings\r
+#endif\r
+\r
+#ifndef STDSTRING_H\r
+#define STDSTRING_H\r
+\r
+// MACRO: SS_UNSIGNED\r
+// ------------------\r
+//      This macro causes the addition of a constructor and assignment operator\r
+//      which take unsigned characters.  CString has such functions and in order\r
+//      to provide maximum CString-compatability, this code needs them as well.\r
+//      In practice you will likely never need these functions...\r
+\r
+//#define SS_UNSIGNED\r
+\r
+#ifdef SS_ALLOW_UNSIGNED_CHARS\r
+       #define SS_UNSIGNED\r
+#endif\r
+\r
+// MACRO: SS_SAFE_FORMAT\r
+// ---------------------\r
+//      This macro provides limited compatability with a questionable CString\r
+//      "feature".  You can define it in order to avoid a common problem that\r
+//      people encounter when switching from CString to CStdString.\r
+//\r
+//      To illustrate the problem -- With CString, you can do this:\r
+//\r
+//          CString sName("Joe");\r
+//          CString sTmp;\r
+//          sTmp.Format("My name is %s", sName);                    // WORKS!\r
+//\r
+//      However if you were to try this with CStdString, your program would\r
+//      crash.\r
+//\r
+//          CStdString sName("Joe");\r
+//          CStdString sTmp;\r
+//          sTmp.Format("My name is %s", sName);                    // CRASHES!\r
+//\r
+//      You must explicitly call c_str() or cast the object to the proper type\r
+//\r
+//          sTmp.Format("My name is %s", sName.c_str());            // WORKS!\r
+//          sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!\r
+//          sTmp.Format("My name is %s", (PCSTR)sName);// WORKS!\r
+//\r
+//      This is because it is illegal to pass anything but a POD type as a\r
+//      variadic argument to a variadic function (i.e. as one of the "..."\r
+//      arguments).  The type const char* is a POD type.  The type CStdString\r
+//      is not.  Of course, neither is the type CString, but CString lets you do\r
+//      it anyway due to the way they laid out the class in binary.  I have no\r
+//      control over this in CStdString since I derive from whatever\r
+//      implementation of basic_string is available.\r
+//\r
+//      However if you have legacy code (which does this) that you want to take\r
+//      out of the MFC world and you don't want to rewrite all your calls to\r
+//      Format(), then you can define this flag and it will no longer crash.\r
+//\r
+//      Note however that this ONLY works for Format(), not sprintf, fprintf, \r
+//      etc.  If you pass a CStdString object to one of those functions, your\r
+//      program will crash.  Not much I can do to get around this, short of\r
+//      writing substitutes for those functions as well.\r
+\r
+#define SS_SAFE_FORMAT  // use new template style Format() function\r
+\r
+\r
+// MACRO: SS_NO_IMPLICIT_CAST\r
+// --------------------------\r
+//      Some people don't like the implicit cast to const char* (or rather to\r
+//      const CT*) that CStdString (and MFC's CString) provide.  That was the\r
+//      whole reason I created this class in the first place, but hey, whatever\r
+//      bakes your cake.  Just #define this macro to get rid of the the implicit\r
+//      cast.\r
+\r
+//#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()\r
+\r
+\r
+// MACRO: SS_NO_REFCOUNT\r
+// ---------------------\r
+//             turns off reference counting at the assignment level.  Only needed\r
+//             for the version of basic_string<> that comes with Visual C++ versions\r
+//             6.0 or earlier, and only then in some heavily multithreaded scenarios.\r
+//             Uncomment it if you feel you need it.\r
+\r
+//#define SS_NO_REFCOUNT\r
+\r
+// MACRO: SS_WIN32\r
+// ---------------\r
+//      When this flag is set, we are building code for the Win32 platform and\r
+//      may use Win32 specific functions (such as LoadString).  This gives us\r
+//      a couple of nice extras for the code.\r
+//\r
+//      Obviously, Microsoft's is not the only compiler available for Win32 out\r
+//      there.  So I can't just check to see if _MSC_VER is defined to detect\r
+//      if I'm building on Win32.  So for now, if you use MS Visual C++ or\r
+//      Borland's compiler, I turn this on.  Otherwise you may turn it on\r
+//      yourself, if you prefer\r
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)\r
+    #define SS_WIN32\r
+#endif\r
+\r
+// MACRO: SS_ANSI\r
+// --------------\r
+//      When this macro is defined, the code attempts only to use ANSI/ISO\r
+//      standard library functions to do it's work.  It will NOT attempt to use\r
+//      any Win32 of Visual C++ specific functions -- even if they are\r
+//      available.  You may define this flag yourself to prevent any Win32\r
+//      of VC++ specific functions from being called.\r
+\r
+// If we're not on Win32, we MUST use an ANSI build\r
+#ifndef SS_WIN32\r
+    #if !defined(SS_NO_ANSI)\r
+        #define SS_ANSI\r
+    #endif\r
+#endif\r
+\r
+// MACRO: SS_ALLOCA\r
+// ----------------\r
+//      Some implementations of the Standard C Library have a non-standard\r
+//      function known as alloca().  This functions allows one to allocate a\r
+//      variable amount of memory on the stack.  It comes in very useful for\r
+//      the ASCII/MBCS conversion macros.\r
+//\r
+//      Here we attempt to determine automatically if alloca() is available on\r
+//      this platform.  If so we define SS_ALLOCA to be the name of the alloca\r
+//      function.  If SS_ALLOCA is undefined later on, then the conversion\r
+//      macros will not be compiled.\r
+//\r
+//      You may prevent SS_ALLOCA\r
+\r
+\r
+\r
+// Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well\r
+\r
+#if defined (_UNICODE) && !defined (UNICODE)\r
+       #define UNICODE\r
+#endif\r
+#if defined (UNICODE) && !defined (_UNICODE)\r
+       #define _UNICODE\r
+#endif\r
+\r
+// -----------------------------------------------------------------------------\r
+// MIN and MAX.  The Standard C++ template versions go by so many names (at\r
+// at least in the MS implementation) that you never know what's available\r
+// -----------------------------------------------------------------------------\r
+template<class Type>\r
+inline const Type& SSMIN(const Type& arg1, const Type& arg2)\r
+{\r
+       return arg2 < arg1 ? arg2 : arg1;\r
+}\r
+template<class Type>\r
+inline const Type& SSMAX(const Type& arg1, const Type& arg2)\r
+{\r
+       return arg2 > arg1 ? arg2 : arg1;\r
+}\r
+\r
+// If they have not #included W32Base.h (part of my W32 utility library) then\r
+// we need to define some stuff.  Otherwise, this is all defined there.\r
+\r
+#if !defined(W32BASE_H)\r
+\r
+       // If they want us to use only standard C++ stuff (no Win32 stuff)\r
+\r
+       #ifdef SS_ANSI\r
+\r
+               // On Win32 we have TCHAR.H so just include it.  This is NOT violating\r
+        // the spirit of SS_ANSI as we are not calling any Win32 functions here.\r
+        \r
+               #ifdef SS_WIN32\r
+\r
+                       #include <TCHAR.H>\r
+                       #include <WTYPES.H>\r
+                       #ifndef STRICT\r
+                               #define STRICT\r
+                       #endif\r
+\r
+        // ... but on non-Win32 platforms, we must #define the types we need.\r
+\r
+               #else\r
+\r
+                       typedef const char*             PCSTR;\r
+                       typedef char*                   PSTR;\r
+                       typedef const wchar_t*  PCWSTR;\r
+                       typedef wchar_t*                PWSTR;\r
+                       #ifdef UNICODE\r
+                               typedef wchar_t         TCHAR;\r
+                       #else\r
+                               typedef char            TCHAR;\r
+                       #endif\r
+                       typedef wchar_t                 OLECHAR;\r
+\r
+               #endif  // #ifndef _WIN32\r
+\r
+\r
+               // Make sure ASSERT and verify are defined using only ANSI stuff\r
+\r
+               #ifndef ASSERT\r
+                       #include <assert.h>\r
+                       #define ASSERT(f) assert((f))\r
+               #endif\r
+               #ifndef VERIFY\r
+                       #ifdef _DEBUG\r
+                               #define VERIFY(x) ASSERT((x))\r
+                       #else\r
+                               #define VERIFY(x) x\r
+                       #endif\r
+               #endif\r
+\r
+       #else // ...else SS_ANSI is NOT defined\r
+\r
+               #include <TCHAR.H>\r
+               #include <WTYPES.H>\r
+               #ifndef STRICT\r
+                       #define STRICT\r
+               #endif\r
+\r
+               // Make sure ASSERT and verify are defined\r
+\r
+               #ifndef ASSERT\r
+                       #include <crtdbg.h>\r
+                       #define ASSERT(f) _ASSERTE((f))\r
+               #endif\r
+               #ifndef VERIFY\r
+                       #ifdef _DEBUG\r
+                               #define VERIFY(x) ASSERT((x))\r
+                       #else\r
+                               #define VERIFY(x) x\r
+                       #endif\r
+               #endif\r
+\r
+       #endif // #ifdef SS_ANSI\r
+\r
+       #ifndef UNUSED\r
+               #define UNUSED(x) x\r
+       #endif\r
+\r
+#endif // #ifndef W32BASE_H\r
+\r
+// Standard headers needed\r
+\r
+#include <string>                      // basic_string\r
+#include <algorithm>           // for_each, etc.\r
+#include <functional>          // for StdStringLessNoCase, et al\r
+#include <locale>              // for various facets\r
+\r
+// If this is a recent enough version of VC include comdef.h, so we can write\r
+// member functions to deal with COM types & compiler support classes e.g. _bstr_t\r
+\r
+#if defined (_MSC_VER) && (_MSC_VER >= 1100)\r
+       #include <comdef.h>\r
+       #define SS_INC_COMDEF           // signal that we #included MS comdef.h file\r
+       #define STDSTRING_INC_COMDEF\r
+       #define SS_NOTHROW __declspec(nothrow)\r
+#else\r
+       #define SS_NOTHROW\r
+#endif\r
+\r
+#ifndef TRACE\r
+       #define TRACE_DEFINED_HERE\r
+       #define TRACE\r
+#endif\r
+\r
+// Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the\r
+// versions with the "L" in front of them because that's a leftover from Win 16\r
+// days, even though it evaluates to the same thing.  Therefore, Define a PCSTR\r
+// as an LPCTSTR.\r
+\r
+#if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)\r
+       typedef const TCHAR*                    PCTSTR;\r
+       #define PCTSTR_DEFINED\r
+#endif\r
+\r
+#if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)\r
+       typedef const OLECHAR*                  PCOLESTR;\r
+       #define PCOLESTR_DEFINED\r
+#endif\r
+\r
+#if !defined(POLESTR) && !defined(POLESTR_DEFINED)\r
+       typedef OLECHAR*                                POLESTR;\r
+       #define POLESTR_DEFINED\r
+#endif\r
+\r
+#if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)\r
+       typedef const unsigned char*    PCUSTR;\r
+       typedef unsigned char*                  PUSTR;\r
+       #define PCUSTR_DEFINED\r
+#endif\r
+\r
+\r
+// SGI compiler 7.3 doesnt know these  types - oh and btw, remember to use\r
+// -LANG:std in the CXX Flags\r
+#if defined(__sgi)\r
+    typedef unsigned long           DWORD;\r
+    typedef void *                  LPCVOID;\r
+#endif\r
+\r
+\r
+// SS_USE_FACET macro and why we need it:\r
+//\r
+// Since I'm a good little Standard C++ programmer, I use locales.  Thus, I\r
+// need to make use of the use_facet<> template function here.   Unfortunately,\r
+// this need is complicated by the fact the MS' implementation of the Standard\r
+// C++ Library has a non-standard version of use_facet that takes more\r
+// arguments than the standard dictates.  Since I'm trying to write CStdString\r
+// to work with any version of the Standard library, this presents a problem.\r
+//\r
+// The upshot of this is that I can't do 'use_facet' directly.  The MS' docs\r
+// tell me that I have to use a macro, _USE() instead.  Since _USE obviously\r
+// won't be available in other implementations, this means that I have to write\r
+// my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the\r
+// standard, use_facet.\r
+//\r
+// If you are having trouble with the SS_USE_FACET macro, in your implementation\r
+// of the Standard C++ Library, you can define your own version of SS_USE_FACET.\r
+#ifndef schMSG\r
+       #define schSTR(x)          #x\r
+       #define schSTR2(x)      schSTR(x)\r
+       #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)\r
+#endif\r
+\r
+#ifndef SS_USE_FACET\r
+       // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for\r
+       // all MSVC builds, erroneously in my opinion.  It causes problems for\r
+       // my SS_ANSI builds.  In my code, I always comment out that line.  You'll\r
+       // find it in   \stlport\config\stl_msvc.h\r
+       #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )\r
+               #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)\r
+                       #ifdef SS_ANSI\r
+                               #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)\r
+                       #endif\r
+               #endif\r
+               #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)\r
+       #elif defined(_MSC_VER )\r
+       #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)\r
+\r
+       // ...and\r
+       #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)\r
+        #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)\r
+       #else\r
+               #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)\r
+       #endif\r
+#endif\r
+\r
+// =============================================================================\r
+// UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones.\r
+// =============================================================================\r
+\r
+#include <wchar.h>      // Added to Std Library with Amendment #1.\r
+\r
+// First define the conversion helper functions.  We define these regardless of\r
+// any preprocessor macro settings since their names won't collide. \r
+\r
+// Not sure if we need all these headers.   I believe ANSI says we do.\r
+\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include <wctype.h>\r
+#include <ctype.h>\r
+#include <stdlib.h>\r
+#ifndef va_start\r
+       #include <varargs.h>\r
+#endif\r
+\r
+// StdCodeCvt - made to look like Win32 functions WideCharToMultiByte\r
+//                             and MultiByteToWideChar but uses locales in SS_ANSI\r
+//                             builds\r
+//typedef int mbstate_t;\r
+#if defined (SS_ANSI) || !defined (SS_WIN32)\r
+\r
+    typedef std::codecvt<wchar_t, char, std::mbstate_t> SSCodeCvt;\r
+\r
+\r
+    inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,\r
+        const std::locale& loc=std::locale())\r
+    {\r
+        ASSERT(0 != pA);\r
+        ASSERT(0 != pW);\r
+        pW[0] = '\0';\r
+        PCSTR pBadA                            = 0;\r
+        PWSTR pBadW                            = 0;\r
+        SSCodeCvt::result res  = SSCodeCvt::ok;\r
+        const SSCodeCvt& conv  = SS_USE_FACET(loc, SSCodeCvt);\r
+        SSCodeCvt::state_type st= { 0 };\r
+        res                                            = conv.in(st,\r
+                                                                         pA, pA + nChars, pBadA,\r
+                                                                         pW, pW + nChars, pBadW);\r
+        ASSERT(SSCodeCvt::ok == res);\r
+        return pW;\r
+    }\r
+    inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,\r
+        const std::locale& loc=std::locale())\r
+    {\r
+        return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);\r
+    }\r
+\r
+    inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,\r
+        const std::locale& loc=std::locale())\r
+    {\r
+        ASSERT(0 != pA);\r
+        ASSERT(0 != pW);\r
+        pA[0] = '\0';\r
+        PSTR pBadA                             = 0;\r
+        PCWSTR pBadW                   = 0;\r
+        SSCodeCvt::result res  = SSCodeCvt::ok;\r
+        const SSCodeCvt& conv  = SS_USE_FACET(loc, SSCodeCvt);\r
+        SSCodeCvt::state_type st= { 0 };\r
+        res                                            = conv.out(st,\r
+                                                                          pW, pW + nChars, pBadW,\r
+                                                                          pA, pA + nChars, pBadA);\r
+        ASSERT(SSCodeCvt::ok == res);\r
+        return pA;\r
+    }\r
+    inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,\r
+        const std::locale& loc=std::locale())\r
+    {\r
+        return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);\r
+    }\r
+\r
+#else   // ...or are we doing things assuming win32 and Visual C++?\r
+\r
+       #include <malloc.h>     // needed for _alloca\r
+\r
+       inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)\r
+       {\r
+               ASSERT(0 != pA);\r
+               ASSERT(0 != pW);\r
+               pW[0] = '\0';\r
+               MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);\r
+               return pW;\r
+       }\r
+       inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)\r
+       {\r
+               return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);\r
+       }\r
+\r
+       inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)\r
+       {\r
+               ASSERT(0 != pA);\r
+               ASSERT(0 != pW);\r
+               pA[0] = '\0';\r
+               WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);\r
+               return pA;\r
+       }\r
+       inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)\r
+       {\r
+               return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);\r
+       }\r
+\r
+#endif\r
+// Unicode/MBCS conversion macros are only available on implementations of\r
+// the "C" library that have the non-standard _alloca function.  As far as I\r
+// know that's only Microsoft's though I've hear that the function exits\r
+// elsewhere.  \r
+    \r
+#if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION\r
+\r
+    #include <malloc.h>        // needed for _alloca\r
+\r
+\r
+    // Define our conversion macros to look exactly like Microsoft's to\r
+    // facilitate using this stuff both with and without MFC/ATL\r
+\r
+    #ifdef _CONVERSION_USES_THREAD_LOCALE\r
+           #ifndef _DEBUG\r
+                   #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \\r
+                           _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa\r
+           #else\r
+                   #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\\r
+                            _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa\r
+           #endif\r
+    #else\r
+           #ifndef _DEBUG\r
+                   #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\\r
+                            PCWSTR _pw; _pw; PCSTR _pa; _pa\r
+           #else\r
+                   #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \\r
+                           _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa\r
+           #endif\r
+    #endif\r
+\r
+    #ifdef _CONVERSION_USES_THREAD_LOCALE\r
+           #define SSA2W(pa) (\\r
+                   ((_pa = pa) == 0) ? 0 : (\\r
+                           _cvt = (sslen(_pa)+1),\\r
+                           StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))\r
+           #define SSW2A(pw) (\\r
+                   ((_pw = pw) == 0) ? 0 : (\\r
+                           _cvt = (sslen(_pw)+1)*2,\\r
+                           StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))\r
+    #else\r
+           #define SSA2W(pa) (\\r
+                   ((_pa = pa) == 0) ? 0 : (\\r
+                           _cvt = (sslen(_pa)+1),\\r
+                           StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))\r
+           #define SSW2A(pw) (\\r
+                   ((_pw = pw) == 0) ? 0 : (\\r
+                           _cvt = (sslen(_pw)+1)*2,\\r
+                           StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))\r
+    #endif\r
+\r
+    #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))\r
+    #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))\r
+\r
+    #ifdef UNICODE\r
+           #define SST2A       SSW2A\r
+           #define SSA2T       SSA2W\r
+           #define SST2CA      SSW2CA\r
+           #define SSA2CT      SSA2CW\r
+           inline PWSTR        SST2W(PTSTR p)                  { return p; }\r
+           inline PTSTR        SSW2T(PWSTR p)                  { return p; }\r
+           inline PCWSTR       SST2CW(PCTSTR p)                { return p; }\r
+           inline PCTSTR       SSW2CT(PCWSTR p)                { return p; }\r
+    #else\r
+           #define SST2W       SSA2W\r
+           #define SSW2T       SSW2A\r
+           #define SST2CW      SSA2CW\r
+           #define SSW2CT      SSW2CA\r
+           inline PSTR         SST2A(PTSTR p)                  { return p; }\r
+           inline PTSTR        SSA2T(PSTR p)                   { return p; }\r
+           inline PCSTR        SST2CA(PCTSTR p)                { return p; }\r
+           inline PCTSTR       SSA2CT(PCSTR p)                 { return p; }\r
+    #endif // #ifdef UNICODE\r
+\r
+    #if defined(UNICODE)\r
+    // in these cases the default (TCHAR) is the same as OLECHAR\r
+           inline PCOLESTR     SST2COLE(PCTSTR p)              { return p; }\r
+           inline PCTSTR       SSOLE2CT(PCOLESTR p)    { return p; }\r
+           inline POLESTR      SST2OLE(PTSTR p)                { return p; }\r
+           inline PTSTR        SSOLE2T(POLESTR p)              { return p; }\r
+    #elif defined(OLE2ANSI)\r
+    // in these cases the default (TCHAR) is the same as OLECHAR\r
+           inline PCOLESTR     SST2COLE(PCTSTR p)              { return p; }\r
+           inline PCTSTR       SSOLE2CT(PCOLESTR p)    { return p; }\r
+           inline POLESTR      SST2OLE(PTSTR p)                { return p; }\r
+           inline PTSTR        SSOLE2T(POLESTR p)              { return p; }\r
+    #else\r
+           //CharNextW doesn't work on Win95 so we use this\r
+           #define SST2COLE(pa)        SSA2CW((pa))\r
+           #define SST2OLE(pa)         SSA2W((pa))\r
+           #define SSOLE2CT(po)        SSW2CA((po))\r
+           #define SSOLE2T(po)         SSW2A((po))\r
+    #endif\r
+\r
+    #ifdef OLE2ANSI\r
+           #define SSW2OLE             SSW2A\r
+           #define SSOLE2W             SSA2W\r
+           #define SSW2COLE    SSW2CA\r
+           #define SSOLE2CW    SSA2CW\r
+           inline POLESTR              SSA2OLE(PSTR p)         { return p; }\r
+           inline PSTR                 SSOLE2A(POLESTR p)      { return p; }\r
+           inline PCOLESTR             SSA2COLE(PCSTR p)       { return p; }\r
+           inline PCSTR                SSOLE2CA(PCOLESTR p){ return p; }\r
+    #else\r
+           #define SSA2OLE             SSA2W\r
+           #define SSOLE2A             SSW2A\r
+           #define SSA2COLE    SSA2CW\r
+           #define SSOLE2CA    SSW2CA\r
+           inline POLESTR              SSW2OLE(PWSTR p)        { return p; }\r
+           inline PWSTR                SSOLE2W(POLESTR p)      { return p; }\r
+           inline PCOLESTR             SSW2COLE(PCWSTR p)      { return p; }\r
+           inline PCWSTR               SSOLE2CW(PCOLESTR p){ return p; }\r
+    #endif\r
+\r
+    // Above we've defined macros that look like MS' but all have\r
+    // an 'SS' prefix.  Now we need the real macros.  We'll either\r
+    // get them from the macros above or from MFC/ATL. \r
+\r
+       #if defined (USES_CONVERSION)\r
+\r
+               #define _NO_STDCONVERSION       // just to be consistent\r
+\r
+       #else\r
+\r
+               #ifdef _MFC_VER\r
+\r
+                       #include <afxconv.h>\r
+                       #define _NO_STDCONVERSION // just to be consistent\r
+\r
+               #else\r
+\r
+                       #define USES_CONVERSION SSCVT\r
+                       #define A2CW                    SSA2CW\r
+                       #define W2CA                    SSW2CA\r
+                       #define T2A                             SST2A\r
+                       #define A2T                             SSA2T\r
+                       #define T2W                             SST2W\r
+                       #define W2T                             SSW2T\r
+                       #define T2CA                    SST2CA\r
+                       #define A2CT                    SSA2CT\r
+                       #define T2CW                    SST2CW\r
+                       #define W2CT                    SSW2CT\r
+                       #define ocslen                  sslen\r
+                       #define ocscpy                  sscpy\r
+                       #define T2COLE                  SST2COLE\r
+                       #define OLE2CT                  SSOLE2CT\r
+                       #define T2OLE                   SST2COLE\r
+                       #define OLE2T                   SSOLE2CT\r
+                       #define A2OLE                   SSA2OLE\r
+                       #define OLE2A                   SSOLE2A\r
+                       #define W2OLE                   SSW2OLE\r
+                       #define OLE2W                   SSOLE2W\r
+                       #define A2COLE                  SSA2COLE\r
+                       #define OLE2CA                  SSOLE2CA\r
+                       #define W2COLE                  SSW2COLE\r
+                       #define OLE2CW                  SSOLE2CW\r
+       \r
+               #endif // #ifdef _MFC_VER\r
+       #endif // #ifndef USES_CONVERSION\r
+#endif // #ifndef SS_NO_CONVERSION\r
+\r
+// Define ostring - generic name for std::basic_string<OLECHAR>\r
+\r
+#if !defined(ostring) && !defined(OSTRING_DEFINED)\r
+       typedef std::basic_string<OLECHAR> ostring;\r
+       #define OSTRING_DEFINED\r
+#endif\r
+\r
+// StdCodeCvt when there's no conversion to be done\r
+inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)\r
+{\r
+       if ( nChars > 0 )\r
+       {\r
+               pDst[0]                         = '\0';\r
+               std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);\r
+//             std::char_traits<char>::copy(pDst, pSrc, nChars);\r
+               if ( nChars > 0 )\r
+                       pDst[nChars]    = '\0';\r
+       }\r
+\r
+       return pDst;\r
+}\r
+inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)\r
+{\r
+       return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);\r
+}\r
+inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)\r
+{\r
+       return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);\r
+}\r
+\r
+inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)\r
+{\r
+       if ( nChars > 0 )\r
+       {\r
+               pDst[0]                         = '\0';\r
+               std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);\r
+//             std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);\r
+               if ( nChars > 0 )\r
+                       pDst[nChars]    = '\0';\r
+       }\r
+\r
+       return pDst;\r
+}\r
+\r
+\r
+// Define tstring -- generic name for std::basic_string<TCHAR>\r
+\r
+#if !defined(tstring) && !defined(TSTRING_DEFINED)\r
+       typedef std::basic_string<TCHAR> tstring;\r
+       #define TSTRING_DEFINED\r
+#endif\r
+\r
+// a very shorthand way of applying the fix for KB problem Q172398\r
+// (basic_string assignment bug)\r
+\r
+#if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )\r
+       #define Q172398(x) (x).erase()\r
+#else\r
+       #define Q172398(x)\r
+#endif\r
+\r
+// =============================================================================\r
+// INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES\r
+//\r
+// Usually for generic text mapping, we rely on preprocessor macro definitions\r
+// to map to string functions.  However the CStdStr<> template cannot use\r
+// macro-based generic text mappings because its character types do not get\r
+// resolved until template processing which comes AFTER macro processing.  In\r
+// other words, UNICODE is of little help to us in the CStdStr template\r
+//\r
+// Therefore, to keep the CStdStr declaration simple, we have these inline\r
+// functions.  The template calls them often.  Since they are inline (and NOT\r
+// exported when this is built as a DLL), they will probably be resolved away\r
+// to nothing. \r
+//\r
+// Without these functions, the CStdStr<> template would probably have to broken\r
+// out into two, almost identical classes.  Either that or it would be a huge,\r
+// convoluted mess, with tons of "if" statements all over the place checking the\r
+// size of template parameter CT.\r
+// \r
+// In several cases, you will see two versions of each function.  One version is\r
+// the more portable, standard way of doing things, while the other is the\r
+// non-standard, but often significantly faster Visual C++ way.\r
+// =============================================================================\r
+\r
+// If they defined SS_NO_REFCOUNT, then we must convert all assignments\r
+\r
+#ifdef SS_NO_REFCOUNT\r
+       #define SSREF(x) (x).c_str()\r
+#else\r
+       #define SSREF(x) (x)\r
+#endif\r
+\r
+// -----------------------------------------------------------------------------\r
+// sslen: strlen/wcslen wrappers\r
+// -----------------------------------------------------------------------------\r
+template<typename CT> inline int sslen(const CT* pT)\r
+{\r
+       return 0 == pT ? 0 : std::basic_string<CT>::traits_type::length(pT);\r
+//     return 0 == pT ? 0 : std::char_traits<CT>::length(pT);\r
+}\r
+inline SS_NOTHROW int sslen(const std::string& s)\r
+{\r
+       return s.length();\r
+}\r
+inline SS_NOTHROW int sslen(const std::wstring& s)\r
+{\r
+       return s.length();\r
+}\r
+\r
+// -----------------------------------------------------------------------------\r
+// sstolower/sstoupper -- convert characters to upper/lower case\r
+// -----------------------------------------------------------------------------\r
+template<typename CT>\r
+inline CT sstolower(const CT& t, const std::locale& loc = std::locale())\r
+{\r
+       return std::tolower<CT>(t, loc);\r
+}\r
+template<typename CT>\r
+inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())\r
+{\r
+       return std::toupper<CT>(t, loc);\r
+}\r
+\r
+// -----------------------------------------------------------------------------\r
+// ssasn: assignment functions -- assign "sSrc" to "sDst"\r
+// -----------------------------------------------------------------------------\r
+typedef std::string::size_type         SS_SIZETYPE; // just for shorthand, really\r
+typedef std::string::pointer           SS_PTRTYPE;  \r
+typedef std::wstring::size_type                SW_SIZETYPE;\r
+typedef std::wstring::pointer          SW_PTRTYPE;  \r
+\r
+inline void    ssasn(std::string& sDst, const std::string& sSrc)\r
+{\r
+       if ( sDst.c_str() != sSrc.c_str() )\r
+       {\r
+               sDst.erase();\r
+               sDst.assign(SSREF(sSrc));\r
+       }\r
+}\r
+inline void    ssasn(std::string& sDst, PCSTR pA)\r
+{\r
+       // Watch out for NULLs, as always.\r
+\r
+       if ( 0 == pA )\r
+       {\r
+               sDst.erase();\r
+       }\r
+\r
+       // If pA actually points to part of sDst, we must NOT erase(), but\r
+       // rather take a substring\r
+\r
+       else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )\r
+       {\r
+               sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));\r
+       }\r
+\r
+       // Otherwise (most cases) apply the assignment bug fix, if applicable\r
+       // and do the assignment\r
+\r
+       else\r
+       {\r
+               Q172398(sDst);\r
+               sDst.assign(pA);\r
+       }\r
+}\r
+inline void    ssasn(std::string& sDst, const std::wstring& sSrc)\r
+{\r
+       int nLen        = sSrc.size();\r
+       sDst.resize(nLen * sizeof(wchar_t) + 1);\r
+       StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);\r
+       sDst.resize(nLen);\r
+       //sDst.resize(sslen(sDst.c_str()));\r
+}\r
+inline void    ssasn(std::string& sDst, PCWSTR pW)\r
+{\r
+       int nLen        = sslen(pW);\r
+       sDst.resize(nLen * sizeof(wchar_t) + 1);\r
+       StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);\r
+       sDst.resize(nLen);\r
+       //sDst.resize(sslen(sDst.c_str()));\r
+}\r
+inline void ssasn(std::string& sDst, const int nNull)\r
+{\r
+       UNUSED(nNull);\r
+       ASSERT(nNull==0);\r
+       sDst.assign("");\r
+}      \r
+inline void    ssasn(std::wstring& sDst, const std::wstring& sSrc)\r
+{\r
+       if ( sDst.c_str() != sSrc.c_str() )\r
+       {\r
+               sDst.erase();\r
+               sDst.assign(SSREF(sSrc));\r
+       }\r
+}\r
+inline void    ssasn(std::wstring& sDst, PCWSTR pW)\r
+{\r
+       // Watch out for NULLs, as always.\r
+\r
+       if ( 0 == pW )\r
+       {\r
+               sDst.erase();\r
+       }\r
+\r
+       // If pW actually points to part of sDst, we must NOT erase(), but\r
+       // rather take a substring\r
+\r
+       else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )\r
+       {\r
+               sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));\r
+       }\r
+\r
+       // Otherwise (most cases) apply the assignment bug fix, if applicable\r
+       // and do the assignment\r
+\r
+       else\r
+       {\r
+               Q172398(sDst);\r
+               sDst.assign(pW);\r
+       }\r
+}\r
+#undef StrSizeType\r
+inline void    ssasn(std::wstring& sDst, const std::string& sSrc)\r
+{\r
+       int nLen        = sSrc.size();\r
+       sDst.resize(nLen+1);\r
+       StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen+1);\r
+       sDst.resize(sslen(sDst.c_str()));\r
+}\r
+inline void    ssasn(std::wstring& sDst, PCSTR pA)\r
+{\r
+       int nLen        = sslen(pA);\r
+       sDst.resize(nLen+1);\r
+       StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen+1);\r
+       sDst.resize(sslen(sDst.c_str()));\r
+}\r
+inline void ssasn(std::wstring& sDst, const int nNull)\r
+{\r
+       UNUSED(nNull);\r
+       ASSERT(nNull==0);\r
+       sDst.assign(L"");\r
+}\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// ssadd: string object concatenation -- add second argument to first\r
+// -----------------------------------------------------------------------------\r
+inline void    ssadd(std::string& sDst, const std::wstring& sSrc)\r
+{\r
+       int nSrcLen     = sSrc.size();\r
+       int nDstLen     = sDst.size();\r
+       int nEndLen     = nSrcLen + nDstLen;\r
+       sDst.resize(nEndLen + 1);\r
+       StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen);\r
+       sDst.resize(nEndLen);\r
+}\r
+inline void    ssadd(std::string& sDst, const std::string& sSrc)\r
+{\r
+       if ( &sDst == &sSrc )\r
+               sDst.reserve(2*sDst.size());\r
+\r
+       sDst.append(sSrc.c_str());\r
+}\r
+inline void    ssadd(std::string& sDst, PCWSTR pW)\r
+{\r
+       int nSrcLen     = sslen(pW);\r
+       int nDstLen     = sDst.size();\r
+       int nEndLen     = nSrcLen + nDstLen;\r
+       sDst.resize(nEndLen + 1);\r
+       StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDstLen), pW, nSrcLen+1);\r
+       sDst.resize(nEndLen);\r
+}\r
+inline void    ssadd(std::string& sDst, PCSTR pA)\r
+{\r
+       if ( pA )\r
+       {\r
+               // If the string being added is our internal string or a part of our\r
+               // internal string, then we must NOT do any reallocation without\r
+               // first copying that string to another object (since we're using a\r
+               // direct pointer)\r
+\r
+               if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())\r
+               {\r
+                       if ( sDst.capacity() <= sDst.size()+sslen(pA) )\r
+                               sDst.append(std::string(pA));\r
+                       else\r
+                               sDst.append(pA);\r
+               }\r
+               else\r
+               {\r
+                       sDst.append(pA); \r
+               }\r
+       }\r
+}\r
+inline void    ssadd(std::wstring& sDst, const std::wstring& sSrc)\r
+{\r
+       if ( &sDst == &sSrc )\r
+               sDst.reserve(2*sDst.size());\r
+\r
+       sDst.append(sSrc.c_str());\r
+}\r
+inline void    ssadd(std::wstring& sDst, const std::string& sSrc)\r
+{\r
+       int nSrcLen     = sSrc.size();\r
+       int nDstLen     = sDst.size();\r
+       int nEndLen     = nSrcLen + nDstLen;\r
+       sDst.resize(nEndLen+1);\r
+       StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), sSrc.c_str(), nSrcLen+1);\r
+       sDst.resize(nEndLen);\r
+}\r
+inline void    ssadd(std::wstring& sDst, PCSTR pA)\r
+{\r
+       int nSrcLen     = sslen(pA);\r
+       int nDstLen     = sDst.size();\r
+       int nEndLen     = nSrcLen + nDstLen;\r
+       sDst.resize(nEndLen + 1);\r
+       StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDstLen), pA, nSrcLen+1);\r
+       sDst.resize(nEndLen);\r
+}\r
+inline void    ssadd(std::wstring& sDst, PCWSTR pW)\r
+{\r
+       if ( pW )\r
+       {\r
+               // If the string being added is our internal string or a part of our\r
+               // internal string, then we must NOT do any reallocation without\r
+               // first copying that string to another object (since we're using a\r
+               // direct pointer)\r
+\r
+               if ( pW >= sDst.c_str() && pW <= sDst.c_str()+sDst.length())\r
+               {\r
+                       if ( sDst.capacity() <= sDst.size()+sslen(pW) )\r
+                               sDst.append(std::wstring(pW));\r
+                       else\r
+                               sDst.append(pW);\r
+               }\r
+               else\r
+               {\r
+                       sDst.append(pW);\r
+               }\r
+       }\r
+}\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// ssicmp: comparison (case insensitive )\r
+// -----------------------------------------------------------------------------\r
+template<typename CT>\r
+inline int ssicmp(const CT* pA1, const CT* pA2)\r
+{\r
+    std::locale loc;\r
+    const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);\r
+    CT f;\r
+    CT l;\r
+\r
+    do \r
+    {\r
+           f = ct.tolower(*(pA1++));\r
+           l = ct.tolower(*(pA2++));\r
+    } while ( (f) && (f == l) );\r
+\r
+    return (int)(f - l);\r
+}\r
+\r
+// -----------------------------------------------------------------------------\r
+// ssupr/sslwr: Uppercase/Lowercase conversion functions\r
+// -----------------------------------------------------------------------------\r
+\r
+template<typename CT>\r
+inline void sslwr(CT* pT, size_t nLen)\r
+{\r
+       SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);\r
+}\r
+template<typename CT>\r
+inline void ssupr(CT* pT, size_t nLen)\r
+{\r
+       SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);\r
+}\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+//  vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard\r
+//  builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.\r
+// -----------------------------------------------------------------------------\r
+#if defined(SS_ANSI) || !defined(_MSC_VER)\r
+\r
+    // Borland's headers put some ANSI "C" functions in the 'std' namespace.\r
+    // Promote them to the global namespace so we can use them here.\r
+\r
+    #if defined(__BORLANDC__)\r
+        using std::vsprintf;\r
+        using std::vswprintf;\r
+    #endif\r
+       inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)\r
+       {\r
+               return vsprintf(pA, pFmtA, vl);\r
+       }\r
+       inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)\r
+       {\r
+               // JMO: Some distributions of the "C" have a version of vswprintf that\r
+        // takes 3 arguments (e.g. Microsoft, Borland, GNU).  Others have a \r
+        // version which takes 4 arguments (an extra "count" argument in the\r
+        // second position.  The best stab I can take at this so far is that if\r
+        // you are NOT running with MS, Borland, or GNU, then I'll assume you\r
+        // have the version that takes 4 arguments.\r
+        //\r
+        // I'm sure that these checks don't catch every platform correctly so if\r
+        // you get compiler errors on one of the lines immediately below, it's\r
+        // probably because your implemntation takes a different number of\r
+        // arguments.  You can comment out the offending line (and use the\r
+        // alternate version) or you can figure out what compiler flag to check\r
+        // and add that preprocessor check in.  Regardless, if you get an error\r
+        // on these lines, I'd sure like to hear from you about it.\r
+        //\r
+        // Thanks to Ronny Schulz for the SGI-specific checks here.\r
+\r
+//     #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)\r
+    #if    !defined(_MSC_VER) \\r
+        && !defined (__BORLANDC__) \\r
+        && !defined(__GNUC__) \\r
+        && !defined(__sgi)\r
+\r
+        return vswprintf(pW, nCount, pFmtW, vl);\r
+\r
+    // suddenly with the current SGI 7.3 compiler there is no such function as\r
+    // vswprintf and the substitute needs explicit casts to compile\r
+\r
+    #elif defined(__sgi)\r
+\r
+        nCount;\r
+        return vsprintf( (char *)pW, (char *)pFmtW, vl);\r
+\r
+    #else\r
+\r
+        nCount;\r
+        return vswprintf(pW, pFmtW, vl);\r
+\r
+    #endif\r
+\r
+       }\r
+#else\r
+       inline int      ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)\r
+       {\r
+               return _vsnprintf(pA, nCount, pFmtA, vl);\r
+       }\r
+       inline int      ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)\r
+       {\r
+               return _vsnwprintf(pW, nCount, pFmtW, vl);\r
+       }\r
+#endif\r
+\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// ssload: Type safe, overloaded ::LoadString wrappers\r
+// There is no equivalent of these in non-Win32-specific builds.  However, I'm\r
+// thinking that with the message facet, there might eventually be one\r
+// -----------------------------------------------------------------------------\r
+#if defined (SS_WIN32) && !defined(SS_ANSI)\r
+       inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)\r
+       {\r
+               return ::LoadStringA(hInst, uId, pBuf, nMax);\r
+       }\r
+       inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)\r
+       {\r
+               return ::LoadStringW(hInst, uId, pBuf, nMax);\r
+       }\r
+#endif\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// sscoll/ssicoll: Collation wrappers\r
+//             Note -- with MSVC I have reversed the arguments order here because the\r
+//             functions appear to return the opposite of what they should\r
+// -----------------------------------------------------------------------------\r
+template <typename CT>\r
+inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)\r
+{\r
+       const std::collate<CT>& coll =\r
+               SS_USE_FACET(std::locale(), std::collate<CT>);\r
+\r
+       return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);\r
+}\r
+template <typename CT>\r
+inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)\r
+{\r
+       const std::locale loc;\r
+       const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);\r
+\r
+       // Some implementations seem to have trouble using the collate<>\r
+       // facet typedefs so we'll just default to basic_string and hope\r
+       // that's what the collate facet uses (which it generally should)\r
+\r
+//     std::collate<CT>::string_type s1(sz1);\r
+//     std::collate<CT>::string_type s2(sz2);\r
+       const std::basic_string<CT> sEmpty;\r
+    std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());\r
+    std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());\r
+\r
+       sslwr(const_cast<CT*>(s1.c_str()), nLen1);\r
+       sslwr(const_cast<CT*>(s2.c_str()), nLen2);\r
+       return coll.compare(s2.c_str(), s2.c_str()+nLen2,\r
+                                               s1.c_str(), s1.c_str()+nLen1);\r
+}\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade\r
+// Again -- no equivalent of these on non-Win32 builds but their might one day\r
+// be one if the message facet gets implemented\r
+// -----------------------------------------------------------------------------\r
+#if defined (SS_WIN32) && !defined(SS_ANSI)\r
+       inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,\r
+                                                 DWORD dwLangId, PSTR pBuf, DWORD nSize,\r
+                                                 va_list* vlArgs)\r
+       { \r
+               return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,\r
+                                                         pBuf, nSize,vlArgs);\r
+       }\r
+       inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,\r
+                                                 DWORD dwLangId, PWSTR pBuf, DWORD nSize,\r
+                                                 va_list* vlArgs)\r
+       {\r
+               return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,\r
+                                                         pBuf, nSize,vlArgs);\r
+       }\r
+#else\r
+#endif\r
\r
+\r
+\r
+// FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.\r
+// -----------------------------------------------------------------------------\r
+// FUNCTION:  sscpy\r
+//             inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);\r
+//             inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)\r
+//             inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);\r
+//             inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);\r
+//             inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);\r
+//\r
+// DESCRIPTION:\r
+//             This function is very much (but not exactly) like strcpy.  These\r
+//             overloads simplify copying one C-style string into another by allowing\r
+//             the caller to specify two different types of strings if necessary.\r
+//\r
+//             The strings must NOT overlap\r
+//\r
+//             "Character" is expressed in terms of the destination string, not\r
+//             the source.  If no 'nMax' argument is supplied, then the number of\r
+//             characters copied will be sslen(pSrc).  A NULL terminator will\r
+//             also be added so pDst must actually be big enough to hold nMax+1\r
+//             characters.  The return value is the number of characters copied,\r
+//             not including the NULL terminator.\r
+//\r
+// PARAMETERS: \r
+//             pSrc - the string to be copied FROM.  May be a char based string, an\r
+//                        MBCS string (in Win32 builds) or a wide string (wchar_t).\r
+//             pSrc - the string to be copied TO.  Also may be either MBCS or wide\r
+//             nMax - the maximum number of characters to be copied into szDest.  Note\r
+//                        that this is expressed in whatever a "character" means to pDst.\r
+//                        If pDst is a wchar_t type string than this will be the maximum\r
+//                        number of wchar_ts that my be copied.  The pDst string must be\r
+//                        large enough to hold least nMaxChars+1 characters.\r
+//                        If the caller supplies no argument for nMax this is a signal to\r
+//                        the routine to copy all the characters in pSrc, regardless of\r
+//                        how long it is.\r
+//\r
+// RETURN VALUE: none\r
+// -----------------------------------------------------------------------------\r
+template<typename CT1, typename CT2>\r
+inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)\r
+{\r
+       StdCodeCvt(pDst, pSrc, nChars);\r
+       pDst[SSMAX(nChars, 0)]  = '\0';\r
+       return nChars;\r
+}\r
+\r
+template<typename CT1, typename CT2>\r
+inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)\r
+{\r
+       return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));\r
+}\r
+template<typename CT1, typename CT2>\r
+inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)\r
+{\r
+       return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));\r
+}\r
+template<typename CT1, typename CT2>\r
+inline int sscpy(CT1* pDst, const CT2* pSrc)\r
+{\r
+       return sscpycvt(pDst, pSrc, sslen(pSrc));\r
+}\r
+template<typename CT1, typename CT2>\r
+inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)\r
+{\r
+       return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));\r
+}\r
+template<typename CT1, typename CT2>\r
+inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)\r
+{\r
+       return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());\r
+}\r
+\r
+#ifdef SS_INC_COMDEF\r
+       template<typename CT1>\r
+       inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)\r
+       {\r
+               return sscpycvt(pDst, static_cast<PCOLESTR>(bs),\r
+            SSMIN(nMax, static_cast<int>(bs.length())));\r
+       }\r
+       template<typename CT1>\r
+       inline int sscpy(CT1* pDst, const _bstr_t& bs)\r
+       {\r
+               return sscpy(pDst, bs, static_cast<int>(bs.length()));\r
+       }\r
+#endif\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// Functional objects for changing case.  They also let you pass locales\r
+// -----------------------------------------------------------------------------\r
+\r
+#ifdef SS_ANSI\r
+    template<typename CT>\r
+    struct SSToUpper : public std::binary_function<CT, std::locale, CT>\r
+    {\r
+           inline CT operator()(const CT& t, const std::locale& loc) const\r
+           {\r
+                   return sstoupper<CT>(t, loc);\r
+           }\r
+    };\r
+    template<typename CT>\r
+    struct SSToLower : public std::binary_function<CT, std::locale, CT>\r
+    {\r
+           inline CT operator()(const CT& t, const std::locale& loc) const\r
+           {\r
+                   return sstolower<CT>(t, loc);\r
+           }\r
+    };\r
+#endif\r
+\r
+// This struct is used for TrimRight() and TrimLeft() function implementations.\r
+//template<typename CT>\r
+//struct NotSpace : public std::unary_function<CT, bool>\r
+//{\r
+//     const std::locale& loc;\r
+//     inline NotSpace(const std::locale& locArg) : loc(locArg) {}\r
+//     inline bool operator() (CT t) { return !std::isspace(t, loc); }\r
+//};\r
+template<typename CT>\r
+struct NotSpace : public std::unary_function<CT, bool>\r
+{\r
+\r
+       // DINKUMWARE BUG:\r
+       // Note -- using std::isspace in a COM DLL gives us access violations\r
+       // because it causes the dynamic addition of a function to be called\r
+       // when the library shuts down.  Unfortunately the list is maintained\r
+       // in DLL memory but the function is in static memory.  So the COM DLL\r
+       // goes away along with the function that was supposed to be called,\r
+       // and then later when the DLL CRT shuts down it unloads the list and\r
+       // tries to call the long-gone function.\r
+       // This is DinkumWare's implementation problem.  Until then, we will\r
+       // use good old isspace and iswspace from the CRT unless they\r
+       // specify SS_ANSI\r
+    \r
+       const std::locale loc;\r
+       NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}\r
+       bool operator() (CT t) const { return !std::isspace(t, loc); }\r
+};\r
+\r
+\r
+\r
+\r
+//                     Now we can define the template (finally!)\r
+// =============================================================================\r
+// TEMPLATE: CStdStr\r
+//             template<typename CT> class CStdStr : public std::basic_string<CT>\r
+//\r
+// REMARKS:\r
+//             This template derives from basic_string<CT> and adds some MFC CString-\r
+//             like functionality\r
+//\r
+//             Basically, this is my attempt to make Standard C++ library strings as\r
+//             easy to use as the MFC CString class.\r
+//\r
+//             Note that although this is a template, it makes the assumption that the\r
+//             template argument (CT, the character type) is either char or wchar_t.  \r
+// =============================================================================\r
+\r
+//#define CStdStr _SS  // avoid compiler warning 4786\r
+\r
+//    template<typename ARG> ARG& FmtArg(ARG& arg)  { return arg; }\r
+//    PCSTR  FmtArg(const std::string& arg)  { return arg.c_str(); }\r
+//    PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }\r
+\r
+template<typename ARG>\r
+struct FmtArg\r
+{\r
+    explicit FmtArg(const ARG& arg) : a_(arg) {}\r
+    const ARG& Val() const { return a_; }\r
+    const ARG& a_;\r
+private:\r
+    FmtArg& operator=(const FmtArg&) { return *this; }\r
+};\r
+\r
+template<typename CT>\r
+class CStdStr : public std::basic_string<CT>\r
+{\r
+       // Typedefs for shorter names.  Using these names also appears to help\r
+       // us avoid some ambiguities that otherwise arise on some platforms\r
+\r
+       typedef typename std::basic_string<CT>          MYBASE;  // my base class\r
+       typedef CStdStr<CT>                                                     MYTYPE;  // myself\r
+       typedef typename MYBASE::const_pointer          PCMYSTR; // PCSTR or PCWSTR \r
+       typedef typename MYBASE::pointer                        PMYSTR;  // PSTR or PWSTR\r
+       typedef typename MYBASE::iterator                       MYITER;  // my iterator type\r
+       typedef typename MYBASE::const_iterator         MYCITER; // you get the idea...\r
+       typedef typename MYBASE::reverse_iterator       MYRITER;\r
+       typedef typename MYBASE::size_type                      MYSIZE;   \r
+       typedef typename MYBASE::value_type                     MYVAL; \r
+       typedef typename MYBASE::allocator_type         MYALLOC;\r
+       \r
+public:\r
+\r
+       // shorthand conversion from PCTSTR to string resource ID\r
+       #define _TRES(pctstr) (LOWORD((DWORD)(pctstr))) \r
+\r
+       // CStdStr inline constructors\r
+       CStdStr()\r
+       {\r
+       }\r
+\r
+       CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))\r
+       {\r
+       }\r
+\r
+       CStdStr(const std::string& str)\r
+       {\r
+               ssasn(*this, SSREF(str));\r
+       }\r
+\r
+       CStdStr(const std::wstring& str)\r
+       {\r
+               ssasn(*this, SSREF(str));\r
+       }\r
+\r
+       CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)\r
+       {\r
+       }\r
+\r
+#ifdef SS_UNSIGNED\r
+       CStdStr(PCUSTR pU)\r
+       {\r
+               *this = reinterpret_cast<PCSTR>(pU);\r
+       }\r
+#endif\r
+\r
+       CStdStr(PCSTR pA)\r
+       {\r
+       #ifdef SS_ANSI\r
+               *this = pA;\r
+       #else\r
+               if ( 0 != HIWORD(pA) )\r
+                       *this = pA;\r
+               else if ( 0 != pA && !Load(_TRES(pA)) )\r
+                       TRACE(_T("Can't load string %u\n"), _TRES(pA));\r
+       #endif\r
+       }\r
+\r
+       CStdStr(PCWSTR pW)\r
+       {\r
+       #ifdef SS_ANSI\r
+               *this = pW;\r
+       #else\r
+               if ( 0 != HIWORD(pW) )\r
+                       *this = pW;\r
+               else if ( 0 != pW && !Load(_TRES(pW)) )\r
+                       TRACE(_T("Can't load string %u\n"), _TRES(pW));\r
+       #endif\r
+       }\r
+\r
+       CStdStr(MYCITER first, MYCITER last)\r
+               : MYBASE(first, last)\r
+       {\r
+       }\r
+\r
+       CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())\r
+               : MYBASE(nSize, ch, al)\r
+       {\r
+       }\r
+\r
+       #ifdef SS_INC_COMDEF\r
+               CStdStr(const _bstr_t& bstr)\r
+               {\r
+                       if ( bstr.length() > 0 )\r
+                               this->append(static_cast<PCMYSTR>(bstr), bstr.length());\r
+               }\r
+       #endif\r
+\r
+       // CStdStr inline assignment operators -- the ssasn function now takes care\r
+       // of fixing  the MSVC assignment bug (see knowledge base article Q172398).\r
+       MYTYPE& operator=(const MYTYPE& str)\r
+       { \r
+               ssasn(*this, str); \r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator=(const std::string& str)\r
+       {\r
+               ssasn(*this, str);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator=(const std::wstring& str)\r
+       {\r
+               ssasn(*this, str);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator=(PCSTR pA)\r
+       {\r
+               ssasn(*this, pA);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator=(PCWSTR pW)\r
+       {\r
+               ssasn(*this, pW);\r
+               return *this;\r
+       }\r
+\r
+#ifdef SS_UNSIGNED\r
+       MYTYPE& operator=(PCUSTR pU)\r
+       {\r
+               ssasn(*this, reinterpret_cast<PCSTR>(pU)):\r
+               return *this;\r
+       }\r
+#endif\r
+\r
+       MYTYPE& operator=(CT t)\r
+       {\r
+               Q172398(*this);\r
+               this->assign(1, t);\r
+               return *this;\r
+       }\r
+\r
+       #ifdef SS_INC_COMDEF\r
+               MYTYPE& operator=(const _bstr_t& bstr)\r
+               {\r
+                       if ( bstr.length() > 0 )\r
+                       {\r
+                               this->assign(static_cast<PCMYSTR>(bstr), bstr.length());\r
+                               return *this;\r
+                       }\r
+                       else\r
+                       {\r
+                               this->erase();\r
+                               return *this;\r
+                       }\r
+               }\r
+       #endif\r
+\r
+\r
+       // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)\r
+       //  *** Thanks to Pete The Plumber for catching this one ***\r
+       // They also are compiled if you have explicitly turned off refcounting\r
+       #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT) \r
+\r
+               MYTYPE& assign(const MYTYPE& str)\r
+               {\r
+                       ssasn(*this, str);\r
+                       return *this;\r
+               }\r
+\r
+               MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)\r
+               {\r
+                       // This overload of basic_string::assign is supposed to assign up to\r
+                       // <nChars> or the NULL terminator, whichever comes first.  Since we\r
+                       // are about to call a less forgiving overload (in which <nChars>\r
+                       // must be a valid length), we must adjust the length here to a safe\r
+                       // value.  Thanks to Ullrich Pollähne for catching this bug\r
+\r
+                       nChars          = SSMIN(nChars, str.length() - nStart);\r
+\r
+                       // Watch out for assignment to self\r
+\r
+                       if ( this == &str )\r
+                       {\r
+                               MYTYPE strTemp(str.c_str()+nStart, nChars);\r
+                               MYBASE::assign(strTemp);\r
+                       }\r
+                       else\r
+                       {\r
+                               Q172398(*this);\r
+                               MYBASE::assign(str.c_str()+nStart, nChars);\r
+                       }\r
+                       return *this;\r
+               }\r
+\r
+               MYTYPE& assign(const MYBASE& str)\r
+               {\r
+                       ssasn(*this, str);\r
+                       return *this;\r
+               }\r
+\r
+               MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)\r
+               {\r
+                       // This overload of basic_string::assign is supposed to assign up to\r
+                       // <nChars> or the NULL terminator, whichever comes first.  Since we\r
+                       // are about to call a less forgiving overload (in which <nChars>\r
+                       // must be a valid length), we must adjust the length here to a safe\r
+                       // value. Thanks to Ullrich Pollähne for catching this bug\r
+\r
+                       nChars          = SSMIN(nChars, str.length() - nStart);\r
+\r
+                       // Watch out for assignment to self\r
+\r
+                       if ( this == &str )     // watch out for assignment to self\r
+                       {\r
+                               MYTYPE strTemp(str.c_str() + nStart, nChars);\r
+                               MYBASE::assign(strTemp);\r
+                       }\r
+                       else\r
+                       {\r
+                               Q172398(*this);\r
+                               MYBASE::assign(str.c_str()+nStart, nChars);\r
+                       }\r
+                       return *this;\r
+               }\r
+\r
+               MYTYPE& assign(const CT* pC, MYSIZE nChars)\r
+               {\r
+                       // Q172398 only fix -- erase before assigning, but not if we're\r
+                       // assigning from our own buffer\r
+\r
+       #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )\r
+                       if ( !this->empty() &&\r
+                               ( pC < this->data() || pC > this->data() + this->capacity() ) )\r
+                       {\r
+                               this->erase();\r
+                       }\r
+       #endif\r
+                       Q172398(*this);\r
+                       MYBASE::assign(pC, nChars);\r
+                       return *this;\r
+               }\r
+\r
+               MYTYPE& assign(MYSIZE nChars, MYVAL val)\r
+               {\r
+                       Q172398(*this);\r
+                       MYBASE::assign(nChars, val);\r
+                       return *this;\r
+               }\r
+\r
+               MYTYPE& assign(const CT* pT)\r
+               {\r
+                       return this->assign(pT, MYBASE::traits_type::length(pT));\r
+               }\r
+\r
+               MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)\r
+               {\r
+       #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) \r
+                       // Q172398 fix.  don't call erase() if we're assigning from ourself\r
+                       if ( iterFirst < this->begin() ||\r
+                 iterFirst > this->begin() + this->size() )\r
+            {\r
+                               this->erase()\r
+            }\r
+       #endif\r
+                       this->replace(this->begin(), this->end(), iterFirst, iterLast);\r
+                       return *this;\r
+               }\r
+       #endif\r
+\r
+\r
+       // -------------------------------------------------------------------------\r
+       // CStdStr inline concatenation.\r
+       // -------------------------------------------------------------------------\r
+       MYTYPE& operator+=(const MYTYPE& str)\r
+       {\r
+               ssadd(*this, str);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator+=(const std::string& str)\r
+       {\r
+               ssadd(*this, str);\r
+               return *this; \r
+       }\r
+\r
+       MYTYPE& operator+=(const std::wstring& str)\r
+       {\r
+               ssadd(*this, str);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator+=(PCSTR pA)\r
+       {\r
+               ssadd(*this, pA);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator+=(PCWSTR pW)\r
+       {\r
+               ssadd(*this, pW);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& operator+=(CT t)\r
+       {\r
+               this->append(1, t);\r
+               return *this;\r
+       }\r
+       #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.\r
+               MYTYPE& operator+=(const _bstr_t& bstr)\r
+               {\r
+                       return this->operator+=(static_cast<PCMYSTR>(bstr));\r
+               }\r
+       #endif\r
+\r
+\r
+       // -------------------------------------------------------------------------\r
+       // Case changing functions\r
+       // -------------------------------------------------------------------------\r
+\r
+    MYTYPE& ToUpper()\r
+       {\r
+               //  Strictly speaking, this would be about the most portable way\r
+\r
+               //      std::transform(begin(),\r
+               //                                 end(),\r
+               //                                 begin(),\r
+               //                                 std::bind2nd(SSToUpper<CT>(), std::locale()));\r
+\r
+               // But practically speaking, this works faster\r
+\r
+               if ( !empty() )\r
+                       ssupr(GetBuf(), this->size());\r
+\r
+               return *this;\r
+       }\r
+\r
+\r
+\r
+       MYTYPE& ToLower()\r
+       {\r
+               //  Strictly speaking, this would be about the most portable way\r
+\r
+               //      std::transform(begin(),\r
+               //                                 end(),\r
+               //                                 begin(),\r
+               //                                 std::bind2nd(SSToLower<CT>(), std::locale()));\r
+\r
+               // But practically speaking, this works faster\r
+\r
+               if ( !empty() )\r
+                       sslwr(GetBuf(), this->size());\r
+\r
+               return *this;\r
+       }\r
+\r
+\r
+\r
+       MYTYPE& Normalize()\r
+       {\r
+               return Trim().ToLower();\r
+       }\r
+\r
+\r
+       // -------------------------------------------------------------------------\r
+       // CStdStr -- Direct access to character buffer.  In the MS' implementation,\r
+       // the at() function that we use here also calls _Freeze() providing us some\r
+       // protection from multithreading problems associated with ref-counting.\r
+    // In VC 7 and later, of course, the ref-counting stuff is gone.\r
+       // -------------------------------------------------------------------------\r
+\r
+       CT* GetBuf(int nMinLen=-1)\r
+       {\r
+               if ( static_cast<int>(size()) < nMinLen )\r
+                       this->resize(static_cast<MYSIZE>(nMinLen));\r
+\r
+               return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));\r
+       }\r
+\r
+       CT* SetBuf(int nLen)\r
+       {\r
+               nLen = ( nLen > 0 ? nLen : 0 );\r
+               if ( this->capacity() < 1 && nLen == 0 )\r
+                       this->resize(1);\r
+\r
+               this->resize(static_cast<MYSIZE>(nLen));\r
+               return const_cast<CT*>(this->data());\r
+       }\r
+       void RelBuf(int nNewLen=-1)\r
+       {\r
+               this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :\r
+                                                        sslen(this->c_str())));\r
+       }\r
+\r
+       void BufferRel()                 { RelBuf(); }                  // backwards compatability\r
+       CT*  Buffer()                    { return GetBuf(); }   // backwards compatability\r
+       CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability\r
+\r
+       bool Equals(const CT* pT, bool bUseCase=false) const\r
+       {       // get copy, THEN compare (thread safe)\r
+               return  bUseCase ? this->compare(pT) == 0 :\r
+                           ssicmp(MYTYPE(*this).c_str(), pT) == 0;\r
+       } \r
+\r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION:  CStdStr::Load\r
+       // REMARKS:\r
+       //              Loads string from resource specified by nID\r
+       //\r
+       // PARAMETERS:\r
+       //              nID - resource Identifier.  Purely a Win32 thing in this case\r
+       //\r
+       // RETURN VALUE:\r
+       //              true if successful, false otherwise\r
+       // -------------------------------------------------------------------------\r
+\r
+#ifndef SS_ANSI\r
+\r
+       bool Load(UINT nId, HMODULE hModule=NULL)\r
+       {\r
+               bool bLoaded            = false;        // set to true of we succeed.\r
+\r
+       #ifdef _MFC_VER         // When in Rome (or MFC land)...\r
+\r
+               CString strRes;\r
+               bLoaded                         = FALSE != strRes.LoadString(nId);\r
+               if ( bLoaded )\r
+                       *this                   = strRes;\r
+\r
+       #else // otherwise make our own hackneyed version of CString's Load\r
+               \r
+               // Get the resource name and module handle\r
+\r
+               if ( NULL == hModule )\r
+                       hModule                 = GetResourceHandle();\r
+\r
+               PCTSTR szName           = MAKEINTRESOURCE((nId>>4)+1); // lifted \r
+               DWORD dwSize            = 0;\r
+\r
+               // No sense continuing if we can't find the resource\r
+\r
+               HRSRC hrsrc                     = ::FindResource(hModule, szName, RT_STRING);\r
+\r
+               if ( NULL == hrsrc )\r
+               {\r
+                       TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());\r
+               }\r
+               else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))\r
+               {\r
+                       TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());\r
+               }\r
+               else\r
+               {\r
+                       bLoaded                 = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);\r
+                       ReleaseBuffer();\r
+               }\r
+\r
+       #endif  // #ifdef _MFC_VER\r
+\r
+               if ( !bLoaded )\r
+                       TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());\r
+\r
+               return bLoaded;\r
+       }\r
+\r
+#endif  // #ifdef SS_ANSI\r
+       \r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION:  CStdStr::Format\r
+       //              void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)\r
+       //              void _cdecl Format(PCSTR szFormat);\r
+       //           \r
+       // DESCRIPTION:\r
+       //              This function does sprintf/wsprintf style formatting on CStdStringA\r
+       //              objects.  It looks a lot like MFC's CString::Format.  Some people\r
+       //              might even call this identical.  Fortunately, these people are now\r
+       //              dead... heh heh.\r
+       //\r
+       // PARAMETERS: \r
+       //              nId - ID of string resource holding the format string\r
+       //              szFormat - a PCSTR holding the format specifiers\r
+       //              argList - a va_list holding the arguments for the format specifiers.\r
+       //\r
+       // RETURN VALUE:  None.\r
+       // -------------------------------------------------------------------------\r
+       // formatting (using wsprintf style formatting)\r
+\r
+    // If they want a Format() function that safely handles string objects\r
+    // without casting\r
\r
+#ifdef SS_SAFE_FORMAT       \r
+    \r
+    // Question:  Joe, you wacky coder you, why do you have so many overloads\r
+    //      of the Format() function\r
+    // Answer:  One reason only - CString compatability.  In short, by making\r
+    //      the Format() function a template this way, I can do strong typing\r
+    //      and allow people to pass CStdString arguments as fillers for\r
+    //      "%s" format specifiers without crashing their program!  The downside\r
+    //      is that I need to overload on the number of arguments.   If you are\r
+    //      passing more arguments than I have listed below in any of my\r
+    //      overloads, just add another one.\r
+    //\r
+    //      Yes, yes, this is really ugly.  In essence what I am doing here is\r
+    //      protecting people from a bad (and incorrect) programming practice\r
+    //      that they should not be doing anyway.  I am protecting them from\r
+    //      themselves.  Why am I doing this?  Well, if you had any idea the\r
+    //      number of times I've been emailed by people about this\r
+    //      "incompatability" in my code, you wouldn't ask.\r
+\r
+       void Fmt(const CT* szFmt, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, szFmt);\r
+               FormatV(szFmt, argList);\r
+               va_end(argList);\r
+       }\r
+\r
+#ifndef SS_ANSI\r
+\r
+    void Format(UINT nId)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) ) \r
+            this->swap(strFmt);\r
+    }\r
+    template<class A1>\r
+    void Format(UINT nId, const A1& v)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+            Fmt(strFmt, FmtArg<A1>(v).Val());\r
+    }\r
+    template<class A1, class A2>\r
+    void Format(UINT nId, const A1& v1, const A2& v2)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+           Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val());\r
+    }\r
+    template<class A1, class A2, class A3>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(),FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(),FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+           Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(),FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+                FmtArg<A12>(v12).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+                FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+                FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14, class A15>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14, const A15& v15)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+                FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),\r
+                FmtArg<A15>(v15).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14, class A15, class A16>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14, const A15& v15,\r
+                const A16& v16)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+                FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),\r
+                FmtArg<A15>(v15).Val(), FmtArg<A16>(v16).Val());\r
+        }\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14, class A15, class A16, class A17>\r
+    void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14, const A15& v15,\r
+                const A16& v16, const A17& v17)\r
+    {\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+        {\r
+            Fmt(strFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+                FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+                FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+                FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+                FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),\r
+                FmtArg<A15>(v15).Val(),FmtArg<A16>(v16).Val(),FmtArg<A17>(v17).Val());\r
+        }\r
+    }\r
+    \r
+#endif // #ifndef SS_ANSI\r
+\r
+    // ...now the other overload of Format: the one that takes a string literal\r
+\r
+    void Format(const CT* szFmt)\r
+    {\r
+        *this = szFmt;\r
+    }\r
+    template<class A1>\r
+    void Format(const CT* szFmt, A1 v)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v).Val());\r
+    }\r
+    template<class A1, class A2>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val());\r
+    }\r
+    template<class A1, class A2, class A3>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(),FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+            FmtArg<A12>(v12).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+            FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+            FmtArg<A12>(v12).Val(), FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14, class A15>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14, const A15& v15)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+            FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),\r
+            FmtArg<A15>(v15).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14, class A15, class A16>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14, const A15& v15,\r
+                const A16& v16)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+            FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),\r
+            FmtArg<A15>(v15).Val(), FmtArg<A16>(v16).Val());\r
+    }\r
+    template<class A1, class A2, class A3, class A4, class A5, class A6,\r
+        class A7, class A8, class A9, class A10, class A11, class A12,\r
+        class A13, class A14, class A15, class A16, class A17>\r
+    void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,\r
+                const A4& v4, const A5& v5, const A6& v6, const A7& v7,\r
+                const A8& v8, const A9& v9, const A10& v10, const A11& v11,\r
+                const A12& v12, const A13& v13, const A14& v14, const A15& v15,\r
+                const A16& v16, const A17& v17)\r
+    {\r
+        Fmt(szFmt, FmtArg<A1>(v1).Val(), FmtArg<A2>(v2).Val(),\r
+            FmtArg<A3>(v3).Val(), FmtArg<A4>(v4).Val(), FmtArg<A5>(v5).Val(),\r
+            FmtArg<A6>(v6).Val(), FmtArg<A7>(v7).Val(), FmtArg<A8>(v8).Val(),\r
+            FmtArg<A9>(v9).Val(), FmtArg<A10>(v10).Val(),FmtArg<A11>(v11).Val(),\r
+            FmtArg<A12>(v12).Val(),FmtArg<A13>(v13).Val(),FmtArg<A14>(v14).Val(),\r
+            FmtArg<A15>(v15).Val(),FmtArg<A16>(v16).Val(),FmtArg<A17>(v17).Val());\r
+    }\r
+\r
+#else  // #ifdef SS_SAFE_FORMAT\r
+\r
+\r
+#ifndef SS_ANSI\r
+\r
+       void Format(UINT nId, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, nId);\r
+               va_start(argList, nId);\r
+\r
+               MYTYPE strFmt;\r
+               if ( strFmt.Load(nId) )\r
+                       FormatV(strFmt, argList);\r
+\r
+               va_end(argList);\r
+       }\r
+    \r
+#endif  // #ifdef SS_ANSI\r
+\r
+       void Format(const CT* szFmt, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, szFmt);\r
+               FormatV(szFmt, argList);\r
+               va_end(argList);\r
+       }\r
+\r
+#endif // #ifdef SS_SAFE_FORMAT\r
+\r
+       void AppendFormat(const CT* szFmt, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, szFmt);\r
+               AppendFormatV(szFmt, argList);\r
+               va_end(argList);\r
+       }\r
+\r
+       #define MAX_FMT_TRIES           5        // #of times we try \r
+       #define FMT_BLOCK_SIZE          2048 // # of bytes to increment per try\r
+       #define BUFSIZE_1ST     256\r
+       #define BUFSIZE_2ND 512\r
+       #define STD_BUF_SIZE            1024\r
+\r
+       // an efficient way to add formatted characters to the string.  You may only\r
+       // add up to STD_BUF_SIZE characters at a time, though\r
+       void AppendFormatV(const CT* szFmt, va_list argList)\r
+       {\r
+               CT szBuf[STD_BUF_SIZE];\r
+       #if defined(SS_ANSI) || !defined(_MSC_VER)\r
+               int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);\r
+       #else\r
+               int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);\r
+       #endif\r
+               if ( 0 < nLen )\r
+                       this->append(szBuf, nLen);\r
+       }\r
+\r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION:  FormatV\r
+       //              void FormatV(PCSTR szFormat, va_list, argList);\r
+       //           \r
+       // DESCRIPTION:\r
+       //              This function formats the string with sprintf style format-specs. \r
+       //              It makes a general guess at required buffer size and then tries\r
+       //              successively larger buffers until it finds one big enough or a\r
+       //              threshold (MAX_FMT_TRIES) is exceeded.\r
+       //\r
+       // PARAMETERS:\r
+       //              szFormat - a PCSTR holding the format of the output\r
+       //              argList - a Microsoft specific va_list for variable argument lists\r
+       //\r
+       // RETURN VALUE:\r
+       // -------------------------------------------------------------------------\r
+\r
+       void FormatV(const CT* szFormat, va_list argList)\r
+       {\r
+       #if defined(SS_ANSI) || !defined(_MSC_VER)\r
+               int nLen        = sslen(szFormat) + STD_BUF_SIZE;\r
+               ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);\r
+               ReleaseBuffer();\r
+\r
+       #else\r
+\r
+               CT* pBuf                        = NULL;\r
+               int nChars                      = 1;\r
+               int nUsed                       = 0;\r
+               size_type nActual       = 0;\r
+               int nTry                        = 0;\r
+\r
+               do\r
+               {\r
+                       // Grow more than linearly (e.g. 512, 1536, 3072, etc)\r
+\r
+                       nChars                  += ((nTry+1) * FMT_BLOCK_SIZE);\r
+                       pBuf                    = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));\r
+                       nUsed                   = ssnprintf(pBuf, nChars-1, szFormat, argList);\r
+\r
+                       // Ensure proper NULL termination.\r
+\r
+                       nActual                 = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);\r
+                       pBuf[nActual+1]= '\0';\r
+\r
+\r
+               } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );\r
+\r
+               // assign whatever we managed to format\r
+\r
+               this->assign(pBuf, nActual);\r
+\r
+       #endif\r
+       }\r
+       \r
+\r
+       // -------------------------------------------------------------------------\r
+       // CString Facade Functions:\r
+       //\r
+       // The following methods are intended to allow you to use this class as a\r
+       // drop-in replacement for CString.\r
+       // -------------------------------------------------------------------------\r
+       #ifdef SS_WIN32\r
+               BSTR AllocSysString() const\r
+               {\r
+                       ostring os;\r
+                       ssasn(os, *this);\r
+                       return ::SysAllocString(os.c_str());\r
+               }\r
+       #endif\r
+\r
+       int Collate(PCMYSTR szThat) const\r
+       {\r
+               return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));\r
+       }\r
+\r
+       int CollateNoCase(PCMYSTR szThat) const\r
+       {\r
+               return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));\r
+       }\r
+\r
+       int Compare(PCMYSTR szThat) const\r
+       {\r
+               return this->compare(szThat);   \r
+       }\r
+\r
+       int CompareNoCase(PCMYSTR szThat)       const\r
+       {\r
+               return ssicmp(this->c_str(), szThat);\r
+       }\r
+\r
+       int Delete(int nIdx, int nCount=1)\r
+       {\r
+        if ( nIdx < 0 )\r
+                       nIdx = 0;\r
+\r
+               if ( nIdx < GetLength() )\r
+                       this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));\r
+\r
+               return GetLength();\r
+       }\r
+\r
+       void Empty()\r
+       {\r
+               this->erase();\r
+       }\r
+\r
+       int Find(CT ch) const\r
+       {\r
+               MYSIZE nIdx     = this->find_first_of(ch);\r
+               return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);\r
+       }\r
+\r
+       int Find(PCMYSTR szSub) const\r
+       {\r
+               MYSIZE nIdx     = this->find(szSub);\r
+               return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);\r
+       }\r
+\r
+       int Find(CT ch, int nStart) const\r
+       {\r
+               // CString::Find docs say add 1 to nStart when it's not zero\r
+               // CString::Find code doesn't do that however.  We'll stick\r
+               // with what the code does\r
+\r
+               MYSIZE nIdx     = this->find_first_of(ch, static_cast<MYSIZE>(nStart));\r
+               return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);\r
+       }\r
+\r
+       int Find(PCMYSTR szSub, int nStart) const\r
+       {\r
+               // CString::Find docs say add 1 to nStart when it's not zero\r
+               // CString::Find code doesn't do that however.  We'll stick\r
+               // with what the code does\r
+\r
+               MYSIZE nIdx     = this->find(szSub, static_cast<MYSIZE>(nStart));\r
+               return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);\r
+       }\r
+\r
+       int FindOneOf(PCMYSTR szCharSet) const\r
+       {\r
+               MYSIZE nIdx = this->find_first_of(szCharSet);\r
+               return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);\r
+       }\r
+\r
+#ifndef SS_ANSI\r
+       void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, szFormat);\r
+               PMYSTR szTemp;\r
+               if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,\r
+                                          szFormat, 0, 0,\r
+                                          reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||\r
+                        szTemp == 0 )\r
+               {\r
+                       throw std::runtime_error("out of memory");\r
+               }\r
+               *this = szTemp;\r
+               LocalFree(szTemp);\r
+               va_end(argList);\r
+       }\r
+\r
+       void FormatMessage(UINT nFormatId, ...) throw(std::exception)\r
+       {\r
+               MYTYPE sFormat;\r
+               VERIFY(sFormat.LoadString(nFormatId) != 0);\r
+               va_list argList;\r
+               va_start(argList, nFormatId);\r
+               PMYSTR szTemp;\r
+               if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,\r
+                                          sFormat, 0, 0,\r
+                                          reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||\r
+                       szTemp == 0)\r
+               {\r
+                       throw std::runtime_error("out of memory");\r
+               }\r
+               *this = szTemp;\r
+               LocalFree(szTemp);\r
+               va_end(argList);\r
+       }\r
+#endif\r
+\r
+\r
+       // -------------------------------------------------------------------------\r
+       // GetXXXX -- Direct access to character buffer\r
+       // -------------------------------------------------------------------------\r
+       CT GetAt(int nIdx) const\r
+       {\r
+               return this->at(static_cast<MYSIZE>(nIdx));\r
+       }\r
+\r
+       CT* GetBuffer(int nMinLen=-1)\r
+       {\r
+               return GetBuf(nMinLen);\r
+       }\r
+\r
+       CT* GetBufferSetLength(int nLen)\r
+       {\r
+               return BufferSet(nLen);\r
+       }\r
+\r
+       // GetLength() -- MFC docs say this is the # of BYTES but\r
+       // in truth it is the number of CHARACTERs (chars or wchar_ts)\r
+       int GetLength() const\r
+       {\r
+               return static_cast<int>(this->length());\r
+       }\r
+\r
+       \r
+       int Insert(int nIdx, CT ch)\r
+       {\r
+               if ( static_cast<MYSIZE>(nIdx) > this->size() -1 )\r
+                       this->append(1, ch);\r
+               else\r
+                       this->insert(static_cast<MYSIZE>(nIdx), 1, ch);\r
+\r
+               return GetLength();\r
+       }\r
+       int Insert(int nIdx, PCMYSTR sz)\r
+       {\r
+               if ( nIdx >= this->size() )\r
+                       this->append(sz, sslen(sz));\r
+               else\r
+                       this->insert(static_cast<MYSIZE>(nIdx), sz);\r
+\r
+               return GetLength();\r
+       }\r
+\r
+       bool IsEmpty() const\r
+       {\r
+               return this->empty();\r
+       }\r
+\r
+       MYTYPE Left(int nCount) const\r
+       {\r
+        // Range check the count.\r
+\r
+               nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));\r
+               return this->substr(0, static_cast<MYSIZE>(nCount)); \r
+       }\r
+\r
+#ifndef SS_ANSI\r
+       bool LoadString(UINT nId)\r
+       {\r
+               return this->Load(nId);\r
+       }\r
+#endif\r
+\r
+       void MakeLower()\r
+       {\r
+               ToLower();\r
+       }\r
+\r
+       void MakeReverse()\r
+       {\r
+               std::reverse(this->begin(), this->end());\r
+       }\r
+\r
+       void MakeUpper()\r
+       { \r
+               ToUpper();\r
+       }\r
+\r
+       MYTYPE Mid(int nFirst ) const\r
+       {\r
+               return Mid(nFirst, size()-nFirst);\r
+       }\r
+\r
+       MYTYPE Mid(int nFirst, int nCount) const\r
+       {\r
+               // CString does range checking here.  Since we're trying to emulate it,\r
+               // we must check too.\r
+\r
+               if ( nFirst < 0 )\r
+                       nFirst = 0;\r
+               if ( nCount < 0 )\r
+                       nCount = 0;\r
+\r
+               if ( nFirst + nCount > size() )\r
+                       nCount = size() - nFirst;\r
+\r
+               if ( nFirst > size() )\r
+                       return MYTYPE();\r
+\r
+               ASSERT(nFirst >= 0);\r
+               ASSERT(nFirst + nCount <= size());\r
+\r
+               return this->substr(static_cast<MYSIZE>(nFirst),\r
+                                                       static_cast<MYSIZE>(nCount));\r
+       }\r
+\r
+       void ReleaseBuffer(int nNewLen=-1)\r
+       {\r
+               RelBuf(nNewLen);\r
+       }\r
+\r
+       int Remove(CT ch)\r
+       {\r
+               MYSIZE nIdx             = 0;\r
+               int nRemoved    = 0;\r
+               while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )\r
+               {\r
+                       this->erase(nIdx, 1);\r
+                       nRemoved++;\r
+               }\r
+               return nRemoved;\r
+       }\r
+\r
+       int Replace(CT chOld, CT chNew)\r
+       {\r
+               int nReplaced   = 0;\r
+               for ( MYITER iter=this->begin(); iter != this->end(); iter++ )\r
+               {\r
+                       if ( *iter == chOld )\r
+                       {\r
+                               *iter = chNew;\r
+                               nReplaced++;\r
+                       }\r
+               }\r
+               return nReplaced;\r
+       }\r
+\r
+       int Replace(PCMYSTR szOld, PCMYSTR szNew)\r
+       {\r
+               int nReplaced           = 0;\r
+               MYSIZE nIdx                     = 0;\r
+               MYSIZE nOldLen          = sslen(szOld);\r
+               if ( 0 == nOldLen )\r
+                       return 0;\r
+\r
+               static const CT ch      = CT(0);\r
+               MYSIZE nNewLen          = sslen(szNew);\r
+               PCMYSTR szRealNew       = szNew == 0 ? &ch : szNew;\r
+\r
+               while ( (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )\r
+               {\r
+                       replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen, szRealNew);\r
+                       nReplaced++;\r
+                       nIdx += nNewLen;\r
+               }\r
+               return nReplaced;\r
+       }\r
+\r
+       int ReverseFind(CT ch) const\r
+       {\r
+               MYSIZE nIdx     = this->find_last_of(ch);\r
+               return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);\r
+       }\r
+\r
+       // ReverseFind overload that's not in CString but might be useful\r
+       int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const\r
+       {\r
+               MYSIZE nIdx     = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);\r
+               return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);\r
+       }\r
+\r
+       MYTYPE Right(int nCount) const\r
+       {\r
+        // Range check the count.\r
+\r
+               nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));\r
+               return this->substr(this->size()-static_cast<MYSIZE>(nCount));\r
+       }\r
+\r
+       void SetAt(int nIndex, CT ch)\r
+       {\r
+               ASSERT(this->size() > static_cast<MYSIZE>(nIndex));\r
+               this->at(static_cast<MYSIZE>(nIndex))           = ch;\r
+       }\r
+\r
+#ifndef SS_ANSI\r
+       BSTR SetSysString(BSTR* pbstr) const\r
+       {\r
+               ostring os;\r
+               ssasn(os, *this);\r
+               if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )\r
+                       throw std::runtime_error("out of memory");\r
+\r
+               ASSERT(*pbstr != 0);\r
+               return *pbstr;\r
+       }\r
+#endif\r
+\r
+       MYTYPE SpanExcluding(PCMYSTR szCharSet) const\r
+       {\r
+        MYSIZE pos = this->find_first_of(szCharSet);\r
+        return pos == MYBASE::npos ? *this : Left(pos);\r
+       }\r
+\r
+       MYTYPE SpanIncluding(PCMYSTR szCharSet) const\r
+       {\r
+        MYSIZE pos = this->find_first_not_of(szCharSet);\r
+        return pos == MYBASE::npos ? *this : Left(pos);\r
+       }\r
+\r
+#if !defined(UNICODE) && !defined(SS_ANSI)\r
+\r
+       // CString's OemToAnsi and AnsiToOem functions are available only in\r
+       // Unicode builds.  However since we're a template we also need a\r
+       // runtime check of CT and a reinterpret_cast to account for the fact\r
+       // that CStdStringW gets instantiated even in non-Unicode builds.\r
+\r
+       void AnsiToOem()\r
+       {\r
+               if ( sizeof(CT) == sizeof(char) && !empty() )\r
+               {\r
+                       ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),\r
+                                               reinterpret_cast<PSTR>(GetBuf()));\r
+               }\r
+               else\r
+               {\r
+                       ASSERT(false);\r
+               }\r
+       }\r
+\r
+       void OemToAnsi()\r
+       {\r
+               if ( sizeof(CT) == sizeof(char) && !empty() )\r
+               {\r
+                       ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),\r
+                                               reinterpret_cast<PSTR>(GetBuf()));\r
+               }\r
+               else\r
+               {\r
+                       ASSERT(false);\r
+               }\r
+       }\r
+\r
+#endif\r
+       \r
+\r
+       // -------------------------------------------------------------------------\r
+       // Trim and its variants\r
+       // -------------------------------------------------------------------------\r
+       MYTYPE& Trim()\r
+       {\r
+               return TrimLeft().TrimRight();\r
+       }\r
+\r
+       MYTYPE& TrimLeft()\r
+       {\r
+               this->erase(this->begin(),\r
+                       std::find_if(this->begin(), this->end(), NotSpace<CT>()));\r
+\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE&  TrimLeft(CT tTrim)\r
+       {\r
+               this->erase(0, this->find_first_not_of(tTrim));\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE&  TrimLeft(PCMYSTR szTrimChars)\r
+       {\r
+               this->erase(0, this->find_first_not_of(szTrimChars));\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE& TrimRight()\r
+       {\r
+               // NOTE:  When comparing reverse_iterators here (MYRITER), I avoid using\r
+               // operator!=.  This is because namespace rel_ops also has a template\r
+               // operator!= which conflicts with the global operator!= already defined\r
+               // for reverse_iterator in the header <utility>.\r
+               // Thanks to John James for alerting me to this.\r
+\r
+               MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());\r
+               if ( !(this->rend() == it) )\r
+                       this->erase(this->rend() - it);\r
+\r
+               this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE&  TrimRight(CT tTrim)\r
+       {\r
+               MYSIZE nIdx     = this->find_last_not_of(tTrim);\r
+               this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);\r
+               return *this;\r
+       }\r
+\r
+       MYTYPE&  TrimRight(PCMYSTR szTrimChars)\r
+       {\r
+               MYSIZE nIdx     = this->find_last_not_of(szTrimChars);\r
+               this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);\r
+               return *this;\r
+       }\r
+\r
+       void                    FreeExtra()\r
+       {\r
+               MYTYPE mt;\r
+               this->swap(mt);\r
+               if ( !mt.empty() )\r
+                       this->assign(mt.c_str(), mt.size());\r
+       }\r
+\r
+       // I have intentionally not implemented the following CString\r
+       // functions.   You cannot make them work without taking advantage\r
+       // of implementation specific behavior.  However if you absolutely\r
+       // MUST have them, uncomment out these lines for "sort-of-like"\r
+       // their behavior.  You're on your own.\r
+\r
+//     CT*                             LockBuffer()    { return GetBuf(); }// won't really lock\r
+//     void                    UnlockBuffer(); { }     // why have UnlockBuffer w/o LockBuffer?\r
+\r
+       // Array-indexing operators.  Required because we defined an implicit cast\r
+       // to operator const CT* (Thanks to Julian Selman for pointing this out)\r
+       CT& operator[](int nIdx)\r
+       {\r
+               return MYBASE::operator[](static_cast<MYSIZE>(nIdx));\r
+       }\r
+\r
+       const CT& operator[](int nIdx) const\r
+       {\r
+               return MYBASE::operator[](static_cast<MYSIZE>(nIdx));\r
+       }\r
+\r
+       CT& operator[](unsigned int nIdx)\r
+       {\r
+               return MYBASE::operator[](static_cast<MYSIZE>(nIdx));\r
+       }\r
+\r
+       const CT& operator[](unsigned int nIdx) const\r
+       {\r
+               return MYBASE::operator[](static_cast<MYSIZE>(nIdx));\r
+       }\r
+\r
+#ifndef SS_NO_IMPLICIT_CAST\r
+       operator const CT*() const\r
+       {\r
+               return this->c_str();\r
+       }\r
+#endif\r
+\r
+       // IStream related functions.  Useful in IPersistStream implementations\r
+\r
+#ifdef SS_INC_COMDEF\r
+\r
+       // struct SSSHDR - useful for non Std C++ persistence schemes.\r
+       typedef struct SSSHDR\r
+       {\r
+               BYTE    byCtrl;\r
+               ULONG   nChars;\r
+       } SSSHDR;       // as in "Standard String Stream Header"\r
+\r
+       #define SSSO_UNICODE    0x01    // the string is a wide string\r
+       #define SSSO_COMPRESS   0x02    // the string is compressed\r
+\r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION: StreamSize\r
+       // REMARKS:\r
+       //              Returns how many bytes it will take to StreamSave() this CStdString\r
+       //              object to an IStream.\r
+       // -------------------------------------------------------------------------\r
+       ULONG StreamSize() const\r
+       {\r
+               // Control header plus string\r
+               ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));\r
+               return (this->size() * sizeof(CT)) + sizeof(SSSHDR);\r
+       }\r
+\r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION: StreamSave\r
+       // REMARKS:\r
+       //              Saves this CStdString object to a COM IStream.\r
+       // -------------------------------------------------------------------------\r
+       HRESULT StreamSave(IStream* pStream) const\r
+       {\r
+               ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));\r
+               HRESULT hr              = E_FAIL;\r
+               ASSERT(pStream != 0);\r
+               SSSHDR hdr;\r
+               hdr.byCtrl              = sizeof(CT) == 2 ? SSSO_UNICODE : 0;\r
+               hdr.nChars              = this->size();\r
+\r
+\r
+               if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )\r
+                       TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);\r
+               else if ( empty() )\r
+                       ;               // nothing to write\r
+               else if ( FAILED(hr=pStream->Write(this->c_str(), this->size()*sizeof(CT), 0)) )\r
+                       TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);\r
+\r
+               return hr;\r
+       }\r
+\r
+\r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION: StreamLoad\r
+       // REMARKS:\r
+       //              This method loads the object from an IStream.\r
+       // -------------------------------------------------------------------------\r
+       HRESULT StreamLoad(IStream* pStream)\r
+       {\r
+               ASSERT(pStream != 0);\r
+               SSSHDR hdr;\r
+               HRESULT hr                      = E_FAIL;\r
+\r
+               if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )\r
+               {\r
+                       TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);\r
+               }\r
+               else if ( hdr.nChars > 0 )\r
+               {\r
+                       ULONG nRead             = 0;\r
+                       PMYSTR pMyBuf   = BufferSet(hdr.nChars);\r
+\r
+                       // If our character size matches the character size of the string\r
+                       // we're trying to read, then we can read it directly into our\r
+                       // buffer. Otherwise, we have to read into an intermediate buffer\r
+                       // and convert.\r
+                       \r
+                       if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )\r
+                       {\r
+                               ULONG nBytes    = hdr.nChars * sizeof(wchar_t);\r
+                               if ( sizeof(CT) == sizeof(wchar_t) )\r
+                               {\r
+                                       if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )\r
+                                               TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);\r
+                               }\r
+                               else\r
+                               {       \r
+                                       PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));\r
+                                       if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )\r
+                                               TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);\r
+                                       else\r
+                                               sscpy(pMyBuf, pBufW, hdr.nChars);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               ULONG nBytes    = hdr.nChars * sizeof(char);\r
+                               if ( sizeof(CT) == sizeof(char) )\r
+                               {\r
+                                       if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )\r
+                                               TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);\r
+                               }\r
+                               else\r
+                               {\r
+                                       PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));\r
+                                       if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )\r
+                                               TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);\r
+                                       else\r
+                                               sscpy(pMyBuf, pBufA, hdr.nChars);\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       this->erase();\r
+               }\r
+               return hr;\r
+       }\r
+#endif // #ifdef SS_INC_COMDEF\r
+\r
+#ifndef SS_ANSI\r
+\r
+       // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly\r
+       // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they\r
+       // point to a single static HINST so that those who call the member\r
+       // functions that take resource IDs can provide an alternate HINST of a DLL\r
+       // to search.  This is not exactly the list of HMODULES that MFC provides\r
+       // but it's better than nothing.\r
+\r
+#ifdef _MFC_VER\r
+       static void SetResourceHandle(HMODULE hNew)\r
+       {\r
+               AfxSetResourceHandle(hNew);\r
+       }\r
+       static HMODULE GetResourceHandle()\r
+       {\r
+               return AfxGetResourceHandle();\r
+       }\r
+#else\r
+       static void SetResourceHandle(HMODULE hNew)\r
+       {\r
+               SSResourceHandle() = hNew;\r
+       }\r
+       static HMODULE GetResourceHandle()\r
+       {\r
+               return SSResourceHandle();\r
+       }\r
+#endif\r
+\r
+\r
+    template<typename CT2>\r
+    MYTYPE operator+(const CStdStr<CT2>& s2)\r
+    {\r
+           MYTYPE strRet(SSREF(*this));\r
+        strRet += s2.c_str();\r
+           return strRet;\r
+    }\r
+\r
+\r
+#endif\r
+};\r
+\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// CStdStr friend addition functions defined as inline\r
+// -----------------------------------------------------------------------------\r
+template<typename CT>\r
+inline\r
+CStdStr<CT> operator+(const  CStdStr<CT>& str1, const CStdStr<CT>& str2)\r
+{\r
+       CStdStr<CT> strRet(SSREF(str1));\r
+       strRet.append(str2);\r
+       return strRet;\r
+}\r
+\r
+template<typename CT>  \r
+inline\r
+CStdStr<CT> operator+(const  CStdStr<CT>& str, CT t)\r
+{\r
+       // this particular overload is needed for disabling reference counting\r
+       // though it's only an issue from line 1 to line 2\r
+\r
+       CStdStr<CT> strRet(SSREF(str)); // 1\r
+       strRet.append(1, t);                            // 2\r
+       return strRet;\r
+}\r
+\r
+template<typename CT>\r
+inline\r
+CStdStr<CT> operator+(const  CStdStr<CT>& str, PCSTR pA)\r
+{\r
+       return CStdStr<CT>(str) + CStdStr<CT>(pA);\r
+}\r
+\r
+template<typename CT>\r
+inline\r
+CStdStr<CT> operator+(PCSTR pA, const CStdStr<CT>& str)\r
+{\r
+       CStdStr<CT> strRet(pA);\r
+       strRet.append(str);\r
+       return strRet;\r
+}\r
+\r
+template<typename CT>\r
+inline\r
+CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)\r
+{ \r
+       return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);\r
+}\r
+\r
+template<typename CT>\r
+inline\r
+CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)\r
+{\r
+       CStdStr<CT> strRet(pW);\r
+       strRet.append(str);\r
+       return strRet;\r
+}\r
+\r
+#ifdef SS_INC_COMDEF\r
+       template<typename CT>\r
+       inline\r
+       CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)\r
+       {\r
+               return static_cast<const CT*>(bstr) + str;\r
+       }\r
+\r
+       template<typename CT>\r
+       inline\r
+       CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)\r
+       {\r
+               return str + static_cast<const CT*>(bstr);\r
+       }\r
+#endif\r
+\r
+// -----------------------------------------------------------------------------\r
+// HOW TO EXPORT CSTDSTRING FROM A DLL\r
+//\r
+// If you want to export CStdStringA and CStdStringW from a DLL, then all you\r
+// need to\r
+//             1.      make sure that all components link to the same DLL version\r
+//                     of the CRT (not the static one).\r
+//             2.      Uncomment the 3 lines of code below\r
+//             3.      #define 2 macros per the instructions in MS KnowledgeBase\r
+//                     article Q168958.  The macros are:\r
+//\r
+//             MACRO           DEFINTION WHEN EXPORTING                DEFINITION WHEN IMPORTING\r
+//             -----           ------------------------                -------------------------\r
+//             SSDLLEXP        (nothing, just #define it)              extern\r
+//             SSDLLSPEC       __declspec(dllexport)                   __declspec(dllimport)\r
+//\r
+//             Note that these macros must be available to ALL clients who want to \r
+//             link to the DLL and use the class.  If they \r
+// -----------------------------------------------------------------------------\r
+//#pragma warning(disable:4231) // non-standard extension ("extern template")\r
+//     SSDLLEXP template class SSDLLSPEC CStdStr<char>;\r
+//     SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;\r
+\r
+// =============================================================================\r
+//                                             END OF CStdStr INLINE FUNCTION DEFINITIONS\r
+// =============================================================================\r
+\r
+//     Now typedef our class names based upon this humongous template\r
+\r
+typedef CStdStr<char>          CStdStringA;    // a better std::string\r
+typedef CStdStr<wchar_t>       CStdStringW;    // a better std::wstring\r
+typedef CStdStr<OLECHAR>       CStdStringO;    // almost always CStdStringW\r
+\r
+\r
+// New-style format function is a template\r
+\r
+#ifdef SS_SAFE_FORMAT\r
+\r
+template<>\r
+struct FmtArg<CStdStringA>\r
+{\r
+    explicit FmtArg(const CStdStringA& arg) : a_(arg) {}\r
+    PCSTR Val() const { return a_.c_str(); }\r
+    const CStdStringA& a_;\r
+private:\r
+    FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }\r
+};\r
+template<>\r
+struct FmtArg<CStdStringW>\r
+{\r
+    explicit FmtArg(const CStdStringW& arg) : a_(arg) {}\r
+    PCWSTR Val() const { return a_.c_str(); }\r
+    const CStdStringW& a_;\r
+private:\r
+    FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }\r
+};\r
+\r
+template<>\r
+struct FmtArg<std::string>\r
+{\r
+    explicit FmtArg(const std::string& arg) : a_(arg) {}\r
+    PCSTR Val() const { return a_.c_str(); }\r
+    const std::string& a_;\r
+private:\r
+    FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }\r
+};\r
+template<>\r
+struct FmtArg<std::wstring>\r
+{\r
+    explicit FmtArg(const std::wstring& arg) : a_(arg) {}\r
+    PCWSTR Val() const { return a_.c_str(); }\r
+    const std::wstring& a_;\r
+private:\r
+    FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}\r
+};\r
+#endif // #ifdef SS_SAFEFORMAT\r
+\r
+#ifndef SS_ANSI\r
+       // SSResourceHandle: our MFC-like resource handle\r
+       inline HMODULE& SSResourceHandle()\r
+       {\r
+               static HMODULE hModuleSS        = GetModuleHandle(0);\r
+               return hModuleSS;\r
+       }\r
+#endif\r
+\r
+\r
+\r
+\r
+// In MFC builds, define some global serialization operators\r
+// Special operators that allow us to serialize CStdStrings to CArchives.\r
+// Note that we use an intermediate CString object in order to ensure that\r
+// we use the exact same format.\r
+\r
+#ifdef _MFC_VER\r
+       inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)\r
+       {\r
+               CString strTemp = strA;\r
+               return ar << strTemp;\r
+       }\r
+       inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)\r
+       {\r
+               CString strTemp = strW;\r
+               return ar << strTemp;\r
+       }\r
+\r
+       inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)\r
+       {\r
+               CString strTemp;\r
+               ar >> strTemp;\r
+               strA = strTemp;\r
+               return ar;\r
+       }\r
+       inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)\r
+       {\r
+               CString strTemp;\r
+               ar >> strTemp;\r
+               strW = strTemp;\r
+               return ar;\r
+       }\r
+#endif // #ifdef _MFC_VER -- (i.e. is this MFC?)\r
+\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// GLOBAL FUNCTION:  WUFormat\r
+//             CStdStringA WUFormat(UINT nId, ...);\r
+//             CStdStringA WUFormat(PCSTR szFormat, ...);\r
+//\r
+// REMARKS:\r
+//             This function allows the caller for format and return a CStdStringA\r
+//             object with a single line of code.\r
+// -----------------------------------------------------------------------------\r
+#ifdef SS_ANSI\r
+#else\r
+\r
+       inline CStdStringA WUFormatA(UINT nId, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, nId);\r
+\r
+               CStdStringA strFmt;\r
+               CStdStringA strOut;\r
+               if ( strFmt.Load(nId) )\r
+                       strOut.FormatV(strFmt, argList);\r
+\r
+               va_end(argList);\r
+               return strOut;\r
+       }\r
+       inline CStdStringA WUFormatA(PCSTR szFormat, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, szFormat);\r
+               CStdStringA strOut;\r
+               strOut.FormatV(szFormat, argList);\r
+               va_end(argList);\r
+               return strOut;\r
+       }\r
+\r
+       inline CStdStringW WUFormatW(UINT nId, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, nId);\r
+\r
+               CStdStringW strFmt;\r
+               CStdStringW strOut;\r
+               if ( strFmt.Load(nId) )\r
+                       strOut.FormatV(strFmt, argList);\r
+\r
+               va_end(argList);\r
+               return strOut;\r
+       }\r
+       inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)\r
+       {\r
+               va_list argList;\r
+               va_start(argList, szwFormat);\r
+               CStdStringW strOut;\r
+               strOut.FormatV(szwFormat, argList);\r
+               va_end(argList);\r
+               return strOut;\r
+       }\r
+#endif // #ifdef SS_ANSI\r
+\r
+#ifdef SS_WIN32\r
+       // -------------------------------------------------------------------------\r
+       // FUNCTION: WUSysMessage\r
+       //       CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);\r
+       //       CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);\r
+       //           \r
+       // DESCRIPTION:\r
+       //       This function simplifies the process of obtaining a string equivalent\r
+       //       of a system error code returned from GetLastError().  You simply\r
+       //       supply the value returned by GetLastError() to this function and the\r
+       //       corresponding system string is returned in the form of a CStdStringA.\r
+       //\r
+       // PARAMETERS: \r
+       //       dwError - a DWORD value representing the error code to be translated\r
+       //       dwLangId - the language id to use.  defaults to english.\r
+       //\r
+       // RETURN VALUE: \r
+       //       a CStdStringA equivalent of the error code.  Currently, this function\r
+       //       only returns either English of the system default language strings.  \r
+       // -------------------------------------------------------------------------\r
+       #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)\r
+       inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)\r
+       {\r
+               CHAR szBuf[512];\r
+\r
+               if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,\r
+                                                                  dwLangId, szBuf, 511, NULL) )\r
+                       return WUFormatA("%s (0x%X)", szBuf, dwError);\r
+               else\r
+                       return WUFormatA("Unknown error (0x%X)", dwError);\r
+       }\r
+       inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)\r
+       {\r
+               WCHAR szBuf[512];\r
+\r
+               if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,\r
+                                                                  dwLangId, szBuf, 511, NULL) )\r
+                       return WUFormatW(L"%s (0x%X)", szBuf, dwError);\r
+               else\r
+                       return WUFormatW(L"Unknown error (0x%X)", dwError);\r
+       }\r
+#endif\r
+\r
+// Define TCHAR based friendly names for some of these functions\r
+\r
+#ifdef UNICODE\r
+       #define CStdString                              CStdStringW\r
+       #define WUSysMessage                    WUSysMessageW\r
+       #define WUFormat                                WUFormatW\r
+#else\r
+       #define CStdString                              CStdStringA\r
+       #define WUSysMessage                    WUSysMessageA\r
+       #define WUFormat                                WUFormatA\r
+#endif\r
+\r
+// ...and some shorter names for the space-efficient\r
+\r
+#define WUSysMsg                                       WUSysMessage\r
+#define WUSysMsgA                                      WUSysMessageA\r
+#define WUSysMsgW                                      WUSysMessageW\r
+#define WUFmtA                                         WUFormatA\r
+#define        WUFmtW                                          WUFormatW\r
+#define WUFmt                                          WUFormat\r
+#define WULastErrMsg()                         WUSysMessage(::GetLastError())\r
+#define WULastErrMsgA()                                WUSysMessageA(::GetLastError())\r
+#define WULastErrMsgW()                                WUSysMessageW(::GetLastError())\r
+\r
+\r
+// -----------------------------------------------------------------------------\r
+// FUNCTIONAL COMPARATORS:\r
+// REMARKS:\r
+//             These structs are derived from the std::binary_function template.  They\r
+//             give us functional classes (which may be used in Standard C++ Library\r
+//             collections and algorithms) that perform case-insensitive comparisons of\r
+//             CStdString objects.  This is useful for maps in which the key may be the\r
+//              proper string but in the wrong case.\r
+// -----------------------------------------------------------------------------\r
+#define StdStringLessNoCaseW           SSLNCW  // avoid VC compiler warning 4786\r
+#define StdStringEqualsNoCaseW         SSENCW          \r
+#define StdStringLessNoCaseA           SSLNCA          \r
+#define StdStringEqualsNoCaseA         SSENCA          \r
+\r
+#ifdef UNICODE\r
+       #define StdStringLessNoCase             SSLNCW          \r
+       #define StdStringEqualsNoCase   SSENCW          \r
+#else\r
+       #define StdStringLessNoCase             SSLNCA          \r
+       #define StdStringEqualsNoCase   SSENCA          \r
+#endif\r
+\r
+struct StdStringLessNoCaseW\r
+       : std::binary_function<CStdStringW, CStdStringW, bool>\r
+{\r
+       inline\r
+       bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const\r
+       { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }\r
+};\r
+struct StdStringEqualsNoCaseW\r
+       : std::binary_function<CStdStringW, CStdStringW, bool>\r
+{\r
+       inline\r
+       bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const\r
+       { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }\r
+};\r
+struct StdStringLessNoCaseA\r
+       : std::binary_function<CStdStringA, CStdStringA, bool>\r
+{\r
+       inline\r
+       bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const\r
+       { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }\r
+};\r
+struct StdStringEqualsNoCaseA\r
+       : std::binary_function<CStdStringA, CStdStringA, bool>\r
+{\r
+       inline\r
+       bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const\r
+       { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }\r
+};\r
+\r
+// If we had to define our own version of TRACE above, get rid of it now\r
+\r
+#ifdef TRACE_DEFINED_HERE\r
+       #undef TRACE\r
+       #undef TRACE_DEFINED_HERE\r
+#endif\r
+\r
+\r
+// These std::swap specializations come courtesy of Mike Crusader. \r
+\r
+//namespace std\r
+//{\r
+//     inline void swap(CStdStringA& s1, CStdStringA& s2) throw()\r
+//     {\r
+//             s1.swap(s2);\r
+//     }\r
+//     template<>\r
+//     inline void swap(CStdStringW& s1, CStdStringW& s2) throw()\r
+//     {\r
+//             s1.swap(s2);\r
+//     }\r
+//}\r
+\r
+// Turn back on any Borland warnings we turned off.\r
+\r
+#ifdef __BORLANDC__\r
+    #pragma option pop  // Turn back on inline function warnings\r
+//     #pragma warn +inl   // Turn back on inline function warnings\r
+#endif\r
+\r
+#endif // #ifndef STDSTRING_H
\ No newline at end of file
diff --git a/include/stg_common.h b/include/stg_common.h
new file mode 100644 (file)
index 0000000..e49f999
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *****************************************************************************
+ *
+ * File:        stg_common.h
+ *
+ * Description: çÌÏÂÁÌØÎÏÅ ÄÌÑ ×ÓÅÇÏ ÐÒÏÅËÔÁ STG
+ *
+ * $Id: stg_common.h,v 1.1.1.1 2005/10/09 11:00:45 nobunaga Exp $
+ *
+ *****************************************************************************
+ */
+
+#ifndef _STG_COMMON_H_
+#define _STG_COMMON_H_
+
+
+#define LOGIN_LEN       (32)
+#define PASSWD_LEN      (32)
+
+#endif  /* _STG_COMMON_H_ */
+
+/* EOF */
+
diff --git a/include/stg_comp_stat.h b/include/stg_comp_stat.h
new file mode 100644 (file)
index 0000000..3bab9a7
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef STG_COMP_STAT_H
+#define STG_COMP_STAT_H
+
+#ifdef LINUX
+#include <stdint.h>
+#endif
+
+#ifdef FREE_BSD5
+#include <inttypes.h>
+#endif
+
+#ifdef FREE_BSD
+#include <sys/inttypes.h>
+#endif
+
+#include "stg_const.h"
+//-----------------------------------------------------------------------------
+struct DAY_STAT
+{
+    DAY_STAT()
+    {
+        lastUpdate = 0;
+        memset(upload,      0, sizeof(uint64_t) * DIR_NUM);
+        memset(download,    0, sizeof(uint64_t) * DIR_NUM);
+        memset(cash,        0, sizeof(double) * DIR_NUM);
+    }
+
+    time_t      lastUpdate;
+    uint64_t    upload[DIR_NUM];
+    uint64_t    download[DIR_NUM];
+    double      cash[DIR_NUM];
+};
+//-----------------------------------------------------------------------------
+struct MONTH_STAT
+{
+    DAY_STAT    dayStat[31];
+    char        notUsed;
+};
+//-----------------------------------------------------------------------------
+
+#endif //STG_COMP_STAT_H
diff --git a/include/stg_const.h b/include/stg_const.h
new file mode 100644 (file)
index 0000000..e882200
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *    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@ua.fm>
+ */
+
+ /*
+ $Author: nobunaga $
+ $Revision: 1.10 $
+ $Date: 2008/01/11 17:33:50 $
+ */
+
+
+#ifndef STG_CONST_H
+#define STG_CONST_H
+
+#define DIR_NUM         (10)
+#define SYS_IFACE_LEN   (9)
+#define IFACE_LEN       (255)
+#define MAX_IP          (5)
+#define USERDATA_NUM    (10)
+
+#define LOGIN_LEN       (32)
+#define PASSWD_LEN      (32)
+#define ADDR_LEN        (255)
+#define NOTE_LEN        (255)
+#define REALNM_LEN      (255)
+#define GROUP_LEN       (255)
+#define PHONE_LEN       (255)
+#define EMAIL_LEN       (255)
+#define USR_IFACE_LEN   (255)
+#define USER_DATA_LEN   (255)
+#define IP_STRING_LEN   (255)
+
+#define ADM_LOGIN_LEN   (32)
+#define ADM_PASSWD_LEN  (32)
+#define TARIFF_NAME_LEN (32)
+#define SERVER_NAME_LEN (255)
+
+#define DIR_NAME_LEN    (16)
+
+#define MAX_MSG_LEN     (235)
+#define MAX_MSG_LEN_8   (1030)
+
+#define LOGCASH         (1)
+#define NOLOGCASH       (0)
+
+#define USERNOCASH      (0)
+#define USERDISCONNECT  (1)
+
+#define LOGEVENT_CONNECT            (0)
+#define LOGEVENT_DISCONNECT         (1)
+#define LOGEVENT_NEW_MONTH          (2)
+#define LOGEVENT_NO_CASH            (3)
+#define LOGEVENT_CONNECT_NO_CASH    (4)
+#define LOGEVENT_USER_DOWN          (5)
+#define LOGEVENT_DELETED            (6)
+
+#define SET_TARIFF_NOW     (0)
+#define SET_TARIFF_DELAYED (1)
+#define SET_TARIFF_RECALC  (2)
+
+#define CASH_SET    (0)
+#define CASH_ADD    (1)
+
+#define NO_TARIFF_NAME  "*_NO_TARIFF_*"
+#define NO_CORP_NAME    "*_NO_CORP_*"
+
+#define mega (1024 * 1024)
+
+#define MONITOR_TIME_DELAY_SEC  (60)
+
+#endif
diff --git a/include/stg_int.h b/include/stg_int.h
new file mode 100644 (file)
index 0000000..30de8f5
--- /dev/null
@@ -0,0 +1,11 @@
+#ifdef LINUX
+#include <stdint.h>
+#endif
+
+#ifdef FREE_BSD5
+#include <inttypes.h>
+#endif
+
+#ifdef FREE_BSD
+#include <sys/inttypes.h>
+#endif
diff --git a/include/stg_message.h b/include/stg_message.h
new file mode 100644 (file)
index 0000000..156e173
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef STG_MESSAGES_H
+#define STG_MESSAGES_H
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.3 $
+ $Date: 2010/03/04 11:49:52 $
+ */
+
+#include <time.h>
+#include <string>
+
+using namespace std;
+//-----------------------------------------------------------------------------
+struct STG_MSG_HDR
+{
+STG_MSG_HDR()
+    : id(0),
+      ver(0),
+      type(0),
+      lastSendTime(0),
+      creationTime(0),
+      showTime(0),
+      repeat(0),
+      repeatPeriod(0)
+{};
+
+uint64_t    id;
+unsigned    ver;
+unsigned    type;
+unsigned    lastSendTime;
+unsigned    creationTime;
+unsigned    showTime;
+int         repeat;
+unsigned    repeatPeriod;
+};
+//-----------------------------------------------------------------------------
+struct STG_MSG
+{
+STG_MSG()
+    : header(),
+      text()
+{};
+
+STG_MSG_HDR header;
+string      text;
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
diff --git a/include/tariff_conf.h b/include/tariff_conf.h
new file mode 100644 (file)
index 0000000..30f1981
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.9 $
+ $Date: 2010/10/05 20:41:11 $
+ $Author: faust $
+ */
+
+#ifndef TARIFF_CONF_H
+#define TARIFF_CONF_H
+
+#include <string>
+#include <vector>
+
+#include "resetable.h"
+#include "stg_const.h"
+
+//-----------------------------------------------------------------------------
+enum
+{
+    TRAFF_UP = 0,
+    TRAFF_DOWN,
+    TRAFF_UP_DOWN,
+    TRAFF_MAX
+};
+//-----------------------------------------------------------------------------
+struct DIRPRICE_DATA
+{
+    DIRPRICE_DATA()
+        : hDay(0),
+          mDay(0),
+          hNight(0),
+          mNight(0),
+          priceDayA(0),
+          priceNightA(0),
+          priceDayB(0),
+          priceNightB(0),
+          threshold(0),
+          singlePrice(0),
+          noDiscount(0)
+        {}
+    int     hDay;
+    int     mDay;
+    int     hNight;
+    int     mNight;
+    double  priceDayA;
+    double  priceNightA;
+    double  priceDayB;
+    double  priceNightB;
+    int     threshold;
+    int     singlePrice; // Do not use day/night division
+    int     noDiscount; // Do not use threshold
+};
+//-----------------------------------------------------------------------------
+struct DIRPRICE_DATA_RES
+{
+    DIRPRICE_DATA_RES & operator= (const DIRPRICE_DATA & dpd)
+        {
+        hDay        = dpd.hDay;
+        mDay        = dpd.mDay;
+        hNight      = dpd.hNight;
+        mNight      = dpd.mNight;
+        priceDayA   = dpd.priceDayA;
+        priceNightA = dpd.priceNightA;
+        priceDayB   = dpd.priceDayB;
+        priceNightB = dpd.priceNightB;
+        threshold   = dpd.threshold;
+        singlePrice = dpd.singlePrice;
+        noDiscount  = dpd.noDiscount;
+        return *this;
+        };
+
+    DIRPRICE_DATA GetData()
+        {
+        DIRPRICE_DATA dd;
+        dd.hDay        = hDay;
+        dd.hNight      = hNight;
+        dd.mDay        = mDay;
+        dd.mNight      = mNight;
+        dd.noDiscount  = noDiscount;
+        dd.priceDayA   = priceDayA;
+        dd.priceDayB   = priceDayB;
+
+        dd.priceNightA = priceNightA;
+        dd.priceNightB = priceNightB;
+        dd.singlePrice = singlePrice;
+        dd.threshold   = threshold;
+        return dd;
+        }
+
+    RESETABLE<int>     hDay;
+    RESETABLE<int>     mDay;
+    RESETABLE<int>     hNight;
+    RESETABLE<int>     mNight;
+    RESETABLE<double>  priceDayA;
+    RESETABLE<double>  priceNightA;
+    RESETABLE<double>  priceDayB;
+    RESETABLE<double>  priceNightB;
+    RESETABLE<int>     threshold;
+    RESETABLE<int>     singlePrice;
+    RESETABLE<int>     noDiscount;
+};
+//-----------------------------------------------------------------------------
+struct TARIFF_CONF
+{
+    double      fee;                 // ÷ÅÌÉÞÉÎÁ ÁÂÏÎÐÌÁÔÙ
+    double      free;                // îÁ ËÁËÕÀ ÓÕÍÍÕ ÄÅÎÅÇ ÀÚÅÒ ËÁÞÁÅÔ ÂÅÓÐÌÁÔÎÏ
+    int         traffType;           // UP, DOWN, UP+DOWN, MAX
+    double      passiveCost;         // óÔÏÉÍÏÓÔØ ÚÁÍÏÒÏÚËÉ
+    std::string name;
+
+    TARIFF_CONF()
+        : fee(0),
+          free(0),
+          traffType(TRAFF_UP_DOWN),              // UP-DOWN
+          passiveCost(0),
+          name()
+        {};
+
+    TARIFF_CONF(const std::string & n)
+        : fee(0),
+          free(0),
+          traffType(TRAFF_UP_DOWN),              // UP-DOWN
+          passiveCost(0),
+          name(n)
+        {};
+};
+//-----------------------------------------------------------------------------
+struct TARIFF_CONF_RES
+{
+    TARIFF_CONF_RES & operator=(const TARIFF_CONF & tc)
+        {
+        fee         = tc.fee;
+        free        = tc.free;
+        traffType   = tc.traffType;
+        passiveCost = tc.passiveCost;
+        name        = tc.name;
+        return *this;
+        };
+
+    TARIFF_CONF GetData()
+        {
+        TARIFF_CONF tc;
+        tc.fee         = fee;
+        tc.free        = free;
+        tc.name        = name;
+        tc.passiveCost = passiveCost;
+        tc.traffType   = traffType;
+        return tc;
+        }
+
+    RESETABLE<double>       fee;
+    RESETABLE<double>       free;
+    RESETABLE<int>          traffType;
+    RESETABLE<double>       passiveCost;
+    RESETABLE<std::string>  name;
+};
+//-----------------------------------------------------------------------------
+struct TARIFF_DATA
+{
+    TARIFF_CONF                 tariffConf;
+    std::vector<DIRPRICE_DATA>  dirPrice;
+
+    TARIFF_DATA()
+        : tariffConf(),
+          dirPrice(DIR_NUM)
+        {}
+
+    TARIFF_DATA(const std::string & name)
+        : tariffConf(name),
+          dirPrice(DIR_NUM)
+        {}
+
+    TARIFF_DATA(const TARIFF_DATA & td)
+        : tariffConf(td.tariffConf),
+          dirPrice(td.dirPrice)
+        {}
+
+    TARIFF_DATA & operator=(const TARIFF_DATA & td)
+        {
+        tariffConf = td.tariffConf;
+        dirPrice = td.dirPrice;
+        return *this;
+        };
+};
+//-----------------------------------------------------------------------------
+struct TARIFF_DATA_RES
+{
+    TARIFF_CONF_RES     tariffConf;
+    std::vector<DIRPRICE_DATA_RES> dirPrice;
+
+    TARIFF_DATA_RES()
+        : tariffConf(),
+          dirPrice(DIR_NUM)
+        {}
+
+    TARIFF_DATA GetData()
+        {
+        TARIFF_DATA td;
+        td.tariffConf = tariffConf.GetData();
+        for (int i = 0; i < DIR_NUM; i++)
+            td.dirPrice[i] = dirPrice[i].GetData();
+        return td;
+        }
+};
+//-----------------------------------------------------------------------------
+#endif
diff --git a/include/user_conf.h b/include/user_conf.h
new file mode 100644 (file)
index 0000000..9a6efb2
--- /dev/null
@@ -0,0 +1,158 @@
+ /*
+ $Revision: 1.12 $
+ $Date: 2010/03/11 14:42:05 $
+ $Author: faust $
+ */
+
+#ifndef USER_CONF_H
+#define USER_CONF_H
+
+#include <string>
+#include <vector>
+#include "stg_const.h"
+#include "user_ips.h"
+#include "resetable.h"
+#include "os_int.h"
+
+//-----------------------------------------------------------------------------
+struct USER_CONF
+{
+    USER_CONF()
+        : password(),
+          passive(0),
+          disabled(0),
+          disabledDetailStat(0),
+          alwaysOnline(0),
+          tariffName(),
+          address(),
+          phone(),
+          email(),
+          note(),
+          realName(),
+          corp(),
+          service(),
+          group(),
+          credit(0),
+          nextTariff(),
+          userdata(USERDATA_NUM),
+          creditExpire(0),
+          ips()
+    {};
+
+    std::string              password;
+    int                      passive;
+    int                      disabled;
+    int                      disabledDetailStat;
+    int                      alwaysOnline;
+    std::string              tariffName;
+    std::string              address;
+    std::string              phone;
+    std::string              email;
+    std::string              note;
+    std::string              realName;
+    std::string              corp;
+    std::vector<std::string> service;
+    std::string              group;
+    double                   credit;
+    std::string              nextTariff;
+    std::vector<std::string> userdata;
+    time_t                   creditExpire;
+    USER_IPS                 ips;
+};
+//-----------------------------------------------------------------------------
+struct USER_CONF_RES
+{
+    USER_CONF_RES()
+        : password(),
+          passive(),
+          disabled(),
+          disabledDetailStat(),
+          alwaysOnline(),
+          tariffName(),
+          address(),
+          phone(),
+          email(),
+          note(),
+          realName(),
+          group(),
+          credit(),
+          nextTariff(),
+          userdata(USERDATA_NUM, RESETABLE<std::string>()),
+          creditExpire(),
+          ips()
+    {
+    };
+
+    USER_CONF_RES & operator=(const USER_CONF & uc)
+    {
+        userdata.resize(USERDATA_NUM);
+        password     = uc.password;
+        passive      = uc.passive;
+        disabled     = uc.disabled;
+        disabledDetailStat = uc.disabledDetailStat;
+        alwaysOnline = uc.alwaysOnline;
+        tariffName   = uc.tariffName;
+        address      = uc.address;
+        phone        = uc.phone;
+        email        = uc.email;
+        note         = uc.note;
+        realName     = uc.realName;
+        group        = uc.group;
+        credit       = uc.credit;
+        nextTariff   = uc.nextTariff;
+        for (int i = 0; i < USERDATA_NUM; i++)
+            {
+            userdata[i]  = uc.userdata[i];
+            }
+        creditExpire = uc.creditExpire;
+        ips          = uc.ips;
+        return *this;
+    };
+    operator USER_CONF() const
+    {
+        USER_CONF uc;
+        uc.password     = password;
+        uc.passive      = passive;
+        uc.disabled     = disabled;
+        uc.disabledDetailStat = disabledDetailStat;
+        uc.alwaysOnline = alwaysOnline;
+        uc.tariffName   = tariffName;
+        uc.address      = address;
+        uc.phone        = phone;
+        uc.email        = email;
+        uc.note         = note;
+        uc.realName     = realName;
+        uc.group        = group;
+        uc.credit       = credit;
+        uc.nextTariff   = nextTariff;
+        for (int i = 0; i < USERDATA_NUM; i++)
+            {
+            uc.userdata[i]  = userdata[i];
+            }
+        uc.creditExpire = creditExpire;
+        uc.ips          = ips;
+        return uc;
+    }
+    //-------------------------------------------------------------------------
+
+    RESETABLE<std::string>               password;
+    RESETABLE<int>                       passive;
+    RESETABLE<int>                       disabled;
+    RESETABLE<int>                       disabledDetailStat;
+    RESETABLE<int>                       alwaysOnline;
+    RESETABLE<std::string>               tariffName;
+    RESETABLE<std::string>               address;
+    RESETABLE<std::string>               phone;
+    RESETABLE<std::string>               email;
+    RESETABLE<std::string>               note;
+    RESETABLE<std::string>               realName;
+    RESETABLE<std::string>               group;
+    RESETABLE<double>                    credit;
+    RESETABLE<std::string>               nextTariff;
+    std::vector<RESETABLE<std::string> > userdata;
+    RESETABLE<time_t>                    creditExpire;
+    RESETABLE<USER_IPS>                  ips;
+};
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/include/user_ips.h b/include/user_ips.h
new file mode 100644 (file)
index 0000000..d3e640c
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.22 $
+ $Date: 2010/03/04 11:49:53 $
+ $Author: faust $
+ */
+
+#ifndef USER_IPS_H
+#define USER_IPS_H
+
+#include <vector>
+//#include <algorithm>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <cstring>
+/////////////////////////
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "common.h"
+#include "os_int.h"
+
+using namespace std;
+
+//-------------------------------------------------------------------------
+struct IP_MASK
+{
+IP_MASK() : ip(0), mask(0) {}
+IP_MASK(const IP_MASK & ipm) : ip(ipm.ip), mask(ipm.mask)  {}
+uint32_t ip;
+uint32_t mask;
+};
+//-------------------------------------------------------------------------
+class USER_IPS
+{
+    friend std::ostream & operator<< (ostream & o, const USER_IPS & i);
+    //friend stringstream & operator<< (stringstream & s, const USER_IPS & i);
+    friend const USER_IPS StrToIPS(const string & ipsStr) throw(string);
+
+public:
+    USER_IPS();
+    USER_IPS(const USER_IPS &);
+    USER_IPS & operator=(const USER_IPS &);
+    const IP_MASK & operator[](int idx) const;
+    std::string GetIpStr() const;
+    bool IsIPInIPS(uint32_t ip) const;
+    bool OnlyOneIP() const;
+    int  Count() const;
+    void Add(const IP_MASK &im);
+    void Erase();
+
+private:
+    uint32_t CalcMask(unsigned int msk) const;
+    std::vector<IP_MASK> ips;
+};
+//-------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+inline
+USER_IPS::USER_IPS()
+    : ips()
+{}
+//-----------------------------------------------------------------------------
+inline
+USER_IPS::USER_IPS(const USER_IPS & i)
+    : ips(i.ips)
+{}
+//-----------------------------------------------------------------------------
+inline
+USER_IPS & USER_IPS::operator=(const USER_IPS & i)
+{
+ips = i.ips;
+return *this;
+}
+//-----------------------------------------------------------------------------
+inline
+const IP_MASK & USER_IPS::operator[](int idx) const
+{
+return ips[idx];
+}
+//-----------------------------------------------------------------------------
+inline
+std::string USER_IPS::GetIpStr() const
+{
+if (ips.empty())
+    {
+    return "";
+    }
+
+if (ips[0].ip == 0)
+    {
+    return "*";
+    }
+
+std::vector<IP_MASK>::const_iterator it(ips.begin());
+std::stringstream s;
+s << inet_ntostring(it->ip);
+++it;
+for (; it != ips.end(); ++it)
+    {
+    s << "," << inet_ntostring(it->ip);
+    }
+return s.str();
+}
+//-----------------------------------------------------------------------------
+inline
+int USER_IPS::Count() const
+{
+return ips.size();
+}
+//-----------------------------------------------------------------------------
+inline
+bool USER_IPS::IsIPInIPS(uint32_t ip) const
+{
+if (ips.empty())
+    {
+    return false;
+    }
+
+if (ips.front().ip == 0)
+    return true;
+
+for (std::vector<IP_MASK>::const_iterator it(ips.begin()); it != ips.end(); ++it)
+    {
+    uint32_t mask(CalcMask(it->mask));
+    if ((ip & mask) == (it->ip & mask))
+        return true;
+    }
+return false;
+}
+//-----------------------------------------------------------------------------
+inline
+bool USER_IPS::OnlyOneIP() const
+{
+if (ips.size() == 1 && ips.front().mask == 32)
+    return true;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+inline
+uint32_t USER_IPS::CalcMask(unsigned int msk) const
+{
+if (msk > 32)
+    return 0;
+return htonl(0xFFffFFff << (32 - msk));
+}
+//-----------------------------------------------------------------------------
+inline
+void USER_IPS::Add(const IP_MASK &im)
+{
+ips.push_back(im);
+}
+//-----------------------------------------------------------------------------
+inline
+void USER_IPS::Erase()
+{
+ips.erase(ips.begin(), ips.end());
+}
+//-----------------------------------------------------------------------------
+inline
+std::ostream & operator<<(std::ostream & o, const USER_IPS & i)
+{
+return o << i.GetIpStr();
+}
+//-----------------------------------------------------------------------------
+/*inline
+stringstream & operator<<(std::stringstream & s, const USER_IPS & i)
+{
+s << i.GetIpStr();
+return s;
+}*/
+//-----------------------------------------------------------------------------
+inline
+const USER_IPS StrToIPS(const std::string & ipsStr) throw(std::string)
+{
+USER_IPS ips;
+char * paddr;
+IP_MASK im;
+std::vector<std::string> ipMask;
+std::string err;
+if (ipsStr.empty())
+    {
+    err = "Incorrect IP address.";
+    throw(err);
+    }
+
+if (ipsStr[0] == '*' && ipsStr.size() == 1)
+    {
+    im.ip = 0;
+    im.mask = 0;
+    ips.ips.push_back(im);
+    return ips;
+    }
+
+char * str = new char[ipsStr.size() + 1];
+strcpy(str, ipsStr.c_str());
+char * pstr = str;
+while ((paddr = strtok(pstr, ",")))
+    {
+    pstr = NULL;
+    ipMask.push_back(paddr);
+    }
+
+delete[] str;
+
+for (unsigned int i = 0; i < ipMask.size(); i++)
+    {
+    char str[128];
+    char * strIp;
+    char * strMask;
+    strcpy(str, ipMask[i].c_str());
+    strIp = strtok(str, "/");
+    if (strIp == NULL)
+        {
+        err = "Incorrect IP address " + ipsStr;
+        throw(err);
+        }
+    strMask = strtok(NULL, "/");
+
+    im.ip = inet_addr(strIp);
+    if (im.ip == INADDR_NONE)
+        {
+        err = "Incorrect IP address: " + std::string(strIp);
+        throw(err);
+        }
+
+    im.mask = 32;
+    if (strMask != NULL)
+        {
+        int m = 0;
+        if (str2x(strMask, m) != 0)
+            {
+            err = "Incorrect mask: " + std::string(strMask);
+            throw(err);
+            }
+        im.mask = m;
+
+        if (im.mask > 32)
+            {
+            err = "Incorrect mask: " + std::string(strMask);
+            throw(err);
+            }
+
+        if ((im.ip & ips.CalcMask(im.mask)) != im.ip)
+            {
+            err = "Address does'n match mask: " + std::string(strIp) + "/" + std::string(strMask);
+            throw(err);
+            }
+        }
+    ips.ips.push_back(im);
+    }
+
+return ips;
+}
+//-------------------------------------------------------------------------
+#endif //USER_IPS_H
+
+
diff --git a/include/user_stat.h b/include/user_stat.h
new file mode 100644 (file)
index 0000000..eeb73df
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.15 $
+ $Date: 2010/03/11 14:42:05 $
+ $Author: faust $
+ */
+
+#ifndef USER_STAT_H
+#define USER_STAT_H
+
+#include <ctime>
+
+#include "os_int.h"
+#include "resetable.h"
+#include "user_traff.h"
+//-----------------------------------------------------------------------------
+struct IP_DIR_PAIR
+{
+    #ifdef TRAFF_STAT_WITH_PORTS
+    IP_DIR_PAIR(uint32_t _ip,
+                int _dir,
+                uint16_t _port)
+        : ip(_ip),
+          dir(_dir),
+          port(_port)
+    {}
+    #else
+    IP_DIR_PAIR(uint32_t _ip,
+                int _dir)
+        : ip(_ip),
+          dir(_dir)
+    {}
+    #endif
+    //------------------------
+    bool operator<(const IP_DIR_PAIR & idp) const
+        {
+        if (ip < idp.ip)
+            return true;
+
+        if (ip > idp.ip)
+            return false;
+
+        #ifdef TRAFF_STAT_WITH_PORTS
+        if (port < idp.port)
+            return true;
+
+        if (port > idp.port)
+            return false;
+        #endif
+
+        if (dir < idp.dir)
+            return true;
+
+        return false;
+        }
+    //------------------------
+    uint32_t        ip;
+    int             dir;
+    #ifdef TRAFF_STAT_WITH_PORTS
+    uint16_t        port;
+    #endif
+};
+//-----------------------------------------------------------------------------
+struct STAT_NODE
+{
+    STAT_NODE(uint64_t _up,
+              uint64_t _down,
+              double   _cash)
+        : up(_up),
+          down(_down),
+          cash(_cash)
+    {}
+    uint64_t        up;
+    uint64_t        down;
+    double          cash;
+};
+//-----------------------------------------------------------------------------
+struct USER_STAT
+{
+    //USER_STAT & operator= (const USER_STAT_RES & usr);
+    USER_STAT()
+        : up(),
+          down(),
+          cash(0),
+          freeMb(0),
+          lastCashAdd(0),
+          lastCashAddTime(0),
+          passiveTime(0),
+          lastActivityTime(0)
+    {};
+
+    DIR_TRAFF   up;
+    DIR_TRAFF   down;
+    double      cash;
+    double      freeMb;
+    double      lastCashAdd;
+    time_t      lastCashAddTime;
+    time_t      passiveTime;
+    time_t      lastActivityTime;
+};
+//-----------------------------------------------------------------------------
+struct USER_STAT_RES
+{
+    USER_STAT_RES()
+        : cash(),
+          freeMb(),
+          lastCashAdd(),
+          lastCashAddTime(),
+          passiveTime(),
+          lastActivityTime(),
+          up(),
+          down()
+    {}
+
+    USER_STAT_RES & operator= (const USER_STAT & us)
+    {
+        cash             = us.cash;
+        freeMb           = us.freeMb;
+        lastCashAdd      = us.lastCashAdd;
+        lastCashAddTime  = us.lastCashAddTime;
+        passiveTime      = us.passiveTime;
+        lastActivityTime = us.lastActivityTime;
+        up = us.up;
+        down = us.down;
+        return * this;
+    };
+    operator USER_STAT()
+    {
+        USER_STAT us;
+        us.cash             = cash;
+        us.freeMb           = freeMb;
+        us.lastCashAdd      = lastCashAdd;
+        us.lastCashAddTime  = lastCashAddTime;
+        us.passiveTime      = passiveTime;
+        us.lastActivityTime = lastActivityTime;
+        us.up               = up;
+        us.down             = down;
+        return us;
+    };
+
+    RESETABLE<double>      cash;
+    RESETABLE<double>      freeMb;
+    RESETABLE<double>      lastCashAdd;
+    RESETABLE<time_t>      lastCashAddTime;
+    RESETABLE<time_t>      passiveTime;
+    RESETABLE<time_t>      lastActivityTime;
+    RESETABLE<DIR_TRAFF>   up;
+    RESETABLE<DIR_TRAFF>   down;
+};
+//-----------------------------------------------------------------------------
+#endif
+
+
+
diff --git a/include/user_traff.h b/include/user_traff.h
new file mode 100644 (file)
index 0000000..fdefee0
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.7 $
+ $Date: 2010/10/07 19:48:52 $
+ $Author: faust $
+ */
+
+#ifndef USER_TRAFF_H
+#define USER_TRAFF_H
+
+#include <iostream>
+#include <vector>
+
+#include "stg_const.h"
+#include "os_int.h"
+
+enum TRAFF_DIRECTION {TRAFF_UPLOAD, TRAFF_DOWNLOAD};
+
+class DIR_TRAFF
+{
+    friend std::ostream & operator<< (std::ostream & o, const DIR_TRAFF & traff);
+
+public:
+    //-------------------------------------------------------------------------
+    DIR_TRAFF();
+    DIR_TRAFF(const DIR_TRAFF & ts);
+    DIR_TRAFF & operator=(const DIR_TRAFF & ts);
+    ~DIR_TRAFF();
+    uint64_t operator[](int idx) const;
+    uint64_t & operator[](int idx);
+    DIR_TRAFF operator+(const DIR_TRAFF & ts);
+
+private:
+    std::vector<uint64_t> traff;
+};
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+inline DIR_TRAFF::DIR_TRAFF()
+    : traff(DIR_NUM, 0)
+{
+}
+//-----------------------------------------------------------------------------
+inline DIR_TRAFF::DIR_TRAFF(const DIR_TRAFF & ts)
+    : traff(ts.traff)
+{
+}
+//-----------------------------------------------------------------------------
+inline DIR_TRAFF::~DIR_TRAFF()
+{
+}
+//-----------------------------------------------------------------------------
+inline DIR_TRAFF & DIR_TRAFF::operator=(const DIR_TRAFF & ts)
+{
+traff = ts.traff;
+return *this;
+};
+//-----------------------------------------------------------------------------
+inline uint64_t & DIR_TRAFF::operator[](int idx)
+{
+return traff[idx];
+};
+//-----------------------------------------------------------------------------
+inline uint64_t DIR_TRAFF::operator[](int idx) const
+{
+return traff[idx];
+};
+//-----------------------------------------------------------------------------
+inline DIR_TRAFF DIR_TRAFF::operator+(const DIR_TRAFF & ts)
+{
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    traff[i] = traff[i] + ts.traff[i];
+    }
+return *this;
+};
+//-----------------------------------------------------------------------------
+inline std::ostream & operator<<(std::ostream & o, const DIR_TRAFF & traff)
+{
+bool first = true;
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    if (first)
+        first = false;
+    else
+        o << ",";
+    o << traff[i];
+    }
+return o;
+}
+//-----------------------------------------------------------------------------
+#endif
diff --git a/include/utime.h b/include/utime.h
new file mode 100644 (file)
index 0000000..4342edc
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef UTIME_H
+#define UTIME_H
+
+/*
+ *    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: 22.12.2007
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.6 $
+ $Date: 2009/08/05 11:40:30 $
+ $Author: faust $
+ */
+
+#include <sys/time.h>
+#include <time.h>
+
+#ifdef FREE_BSD
+typedef long suseconds_t;
+#endif
+
+struct UTIME: public timeval
+{
+    UTIME()
+    {
+    tv_sec = 0;
+    tv_usec = 0;
+    }
+
+    UTIME(time_t t)
+    {
+    tv_sec = t;
+    tv_usec = 0;
+    }
+
+    UTIME(long long a, long long b)
+    {
+    tv_sec = a;
+    tv_usec = b;
+    }
+
+    bool operator<(const UTIME & rhs) const
+    {
+    if (tv_sec < rhs.tv_sec)
+        return true;
+    else if (tv_sec > rhs.tv_sec)
+        return false;
+    else if (tv_usec < rhs.tv_usec)
+        return true;
+    return false;
+    }
+
+    bool operator<=(const UTIME & rhs) const
+    {
+    if (tv_sec < rhs.tv_sec)
+        return true;
+    else if (tv_sec > rhs.tv_sec)
+        return false;
+    else if (tv_usec < rhs.tv_usec)
+        return true;
+    else if (tv_usec > rhs.tv_usec)
+        return false;
+    return true;
+    }
+
+    bool operator>(const UTIME & rhs) const
+    {
+    if (tv_sec > rhs.tv_sec)
+        return true;
+    else if (tv_sec < rhs.tv_sec)
+        return false;
+    else if (tv_usec > rhs.tv_usec)
+        return true;
+    return false;
+    }
+
+    bool operator>=(const UTIME & rhs) const
+    {
+    if (tv_sec > rhs.tv_sec)
+        return true;
+    else if (tv_sec < rhs.tv_sec)
+        return false;
+    else if (tv_usec > rhs.tv_usec)
+        return true;
+    else if (tv_usec < rhs.tv_usec)
+        return false;
+    return true;
+    }
+
+    bool operator==(const UTIME & rhs) const
+    {
+    //cout << tv_sec << "." << tv_usec << "  " << rhs.tv_sec << "." <<  rhs.tv_usec << endl;
+    //cout << (tv_sec == rhs.tv_sec) << " " << (tv_usec == rhs.tv_usec) << endl;
+    return (tv_sec == rhs.tv_sec) && (tv_usec == rhs.tv_usec);
+    }
+
+    UTIME operator+(const UTIME & rhs)
+    {
+    // TODO optimize
+    long long a, b;
+    /*a = tv_sec * 1000000 + tv_usec;
+    b = rhs.tv_sec * 1000000 + rhs.tv_usec;
+    return UTIME((a + b) / 1000000, (a + b) % 1000000);*/
+    a = tv_sec + rhs.tv_sec;
+    b = tv_usec + rhs.tv_usec;
+    if (b > 1000000)
+        {
+        ++a;
+        b -= 1000000;
+        }
+    return UTIME(a, b);
+    }
+
+    UTIME operator-(const UTIME & rhs)
+    {
+    // TODO optimize
+    long long a, b;
+    /*a = tv_sec * 1000000 + tv_usec;
+    b = rhs.tv_sec * 1000000 + rhs.tv_usec;
+    return UTIME((a - b) / 1000000, (a - b) % 1000000);*/
+    a = tv_sec - rhs.tv_sec;
+    b = tv_usec - rhs.tv_usec;
+    if (a >= 0)
+        {
+        if (b >= 0)
+            {
+            return UTIME(a, b);
+            }
+        else
+            {
+            return UTIME(--a, b + 1000000);
+            }
+        }
+    else
+        {
+        if (b >= 0)
+            {
+            return UTIME(++a, 1000000 - b);
+            }
+        else
+            {
+            return UTIME(a, b);
+            }
+        }
+    }
+
+    time_t GetSec() const
+    {
+    return tv_sec;
+    }
+
+    suseconds_t GetUSec() const
+    {
+    return tv_usec;
+    }
+};
+
+
+#endif //UTIME_H
+
diff --git a/include/version.h b/include/version.h
new file mode 100644 (file)
index 0000000..0808547
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *    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 Mamontiv <faust@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.5 $
+ $Date: 2009/08/05 09:24:01 $
+ */
+
+#define SERVER_VERSION "2.406" 
diff --git a/include/vpn_stg_packets.h b/include/vpn_stg_packets.h
new file mode 100644 (file)
index 0000000..e1f0b0b
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef vpn_stg_packets_h\r
+#define vpn_stg_packets_h\r
+\r
+#define VS_MAGIC "VS01"\r
+\r
+enum \r
+{\r
+GET_LOGIN,\r
+GET_LOGIN_ANS,\r
+VS_ALIVE,\r
+VS_ALIVE_ANS,\r
+VS_DISCONNECT\r
+}\r
+\r
+\r
+struct VS_GET_LOGIN\r
+{\r
+char magic[4];\r
+STG_PACKET_TYPES type;\r
+char login[32];\r
+//char password[32];\r
+};\r
+\r
+struct VS_CHECK_LOGIN_ANS\r
+{\r
+char magic[4];\r
+STG_PACKET_TYPES type;\r
+char login[32];\r
+char password[32];\r
+uint32_t ip;\r
+};\r
+\r
+struct VS_ALIVE\r
+{\r
+char magic[4];\r
+STG_PACKET_TYPES type;\r
+char login[32];\r
+uint32_t ip;\r
+};\r
+\r
+struct VS_ALIVE_ANS\r
+{\r
+char magic[4];\r
+STG_PACKET_TYPES type;\r
+char login[32];\r
+uint32_t ip;\r
+};\r
+\r
+struct VS_DISCONNECT\r
+{\r
+char magic[4];\r
+STG_PACKET_TYPES type;\r
+char login[32];\r
+uint32_t ip;\r
+};\r
+\r
+\r
+#endif\r
diff --git a/projects/convertor/Makefile b/projects/convertor/Makefile
new file mode 100644 (file)
index 0000000..c07f698
--- /dev/null
@@ -0,0 +1,74 @@
+###############################################################################
+# $Id: Makefile,v 1.12 2009/03/03 15:49:34 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = convertor
+
+SRCS = ./main.cpp \
+       ./settings.cpp
+
+STGLIBS =  -lstg_logger \
+           -lstg_common \
+           -ldotconfpp \
+          -lstg_crypto
+
+LIBS += $(LIB_THREAD)
+
+ifeq ($(OS),linux)
+LIBS += -ldl
+else
+LIBS += -lc
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS += -Wall
+LDFLAGS += -Wl,-E -L$(DIR_LIB) -Wl,-rpath,$(DIR_LIB)
+
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs plugins install uninstall
+all: libs plugins $(PROG) ../../Makefile.conf
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+plugins: libs 
+       $(MAKE) -C $(DIR_PLUGINS)
+
+$(PROG): $(OBJS) $(STGLIBS) 
+       $(CC) $^ $(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*
+       $(MAKE) -C $(DIR_LIBSRC) clean
+       $(MAKE) -C $(DIR_PLUGINS) clean
+
+distclean: clean
+       rm -f ../../Makefile.conf
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/convertor/build b/projects/convertor/build
new file mode 100755 (executable)
index 0000000..491cf81
--- /dev/null
@@ -0,0 +1,259 @@
+#!/bin/sh
+
+#   $Revision: 1.20 $
+#   $Author: faust $
+#   $Date: 2010/04/14 08:58:43 $
+######################################################
+
+OS=unknown
+sys=`uname -s`
+release=`uname -r | cut -b1`
+BUILD_DIR=`pwd`
+CONFFILE="../../Makefile.conf"
+PREFIX="/"
+BIN_MODE=0755
+DATA_MODE=0644
+OWNER=root
+VAR_DIR="./inst/var/stargazer"
+DEFS="-DDEBUG"
+MAKEOPTS="-j1"
+CXXFLAGS="$CXXFLAGS -g3 -W -Wall -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+
+if [ "$sys" = "Linux" ]
+then
+    OS=linux
+    release=""
+    MAKE="make"
+fi
+
+if [ "$sys" = "FreeBSD" ]
+then
+    case $release in
+        4) OS=bsd;;
+        5) OS=bsd5;;
+        6) OS=bsd5;;
+        7) OS=bsd7;;
+        8) OS=bsd7;;
+        *) OS=unknown;;
+    esac
+    MAKE="gmake"
+fi
+
+if [ "$OS" = "unknown" ]
+then 
+    echo "#############################################################################"
+    echo "# Sorry, but convertor currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #"
+    echo "#############################################################################"
+    exit 1
+fi
+
+echo "#############################################################################"
+echo "       Building convertor for $sys $release"
+echo "#############################################################################"
+
+STG_LIBS="stg_logger.lib 
+          stg_locker.lib
+         crypto.lib 
+         common.lib 
+         conffiles.lib
+         dotconfpp.lib"
+
+PLUGINS="store/files"
+
+if [ "$OS" = "linux" ]
+then
+    DEFS="$DEFS -DLINUX"
+    SHELL="/bin/bash"
+    LIB_THREAD=-lpthread
+else
+    if [ "$OS" = "bsd" ]
+    then
+        DEFS="$DEFS -DFREE_BSD"
+        LIB_THREAD=-lc_r
+    else
+        DEFS="$DEFS -DFREE_BSD5"
+        if [ "$OS" = "bsd7" ]
+        then
+            LIB_THREAD=-lpthread
+        else
+            LIB_THREAD=-lc_r
+        fi
+    fi
+    SHELL="/usr/local/bin/bash"
+fi
+
+echo -n "Checking endianess... "
+echo "int main() { int probe = 0x00000001; return *(char *)&probe; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS -L/usr/lib/mysql -L/usr/local/lib/mysql build_check.c -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    echo "FAIL!"
+    echo "Endianess checking failed"
+    exit;
+else
+    ./fake
+    if [ $? = 1 ]
+    then
+        ARCH=le
+        CXXFLAGS="$CXXFLAGS -DARCH_LE"
+        echo "Little Endian"
+    else
+        ARCH=be
+        CXXFLAGS="$CXXFLAGS -DARCH_BE"
+        echo "Big Endian"
+    fi
+fi
+rm -f fake
+
+echo -n "Checking for -lfbclient... "
+gcc $CXXFLAGS $LDFLAGS build_check.c -lfbclient $LIB_THREAD -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_FBCLIENT=no
+    echo "no"
+else
+    CHECK_FBCLIENT=yes
+    echo "yes"
+fi
+rm -f fake
+
+echo -n "Checking for mysql_config... "
+MYSQL_VERSION=`mysql_config --version 2> /dev/null`
+if [ $? != 0 ]
+then
+    echo "no";
+    echo -n "Checking for -lmysqlclient... "
+    gcc $CXXFLAGS $LDFLAGS build_check.c -lmysqlclient_r $LIB_THREAD -o fake > /dev/null 2> /dev/null
+    if [ $? != 0 ]
+    then
+        CHECK_MYSQLCLIENT=no
+        echo "no"
+    else
+        CHECK_MYSQLCLIENT=yes
+        echo "yes"
+    fi
+    rm -f fake
+else
+    echo "yes"
+    echo -n "Checking for mysql_config --cflags... "
+    MYSQL_CFLAGS=`mysql_config --cflags 2> /dev/null`
+    if [ $? != 0 ]
+    then
+        CHECK_MYSQLCLIENT=no
+        echo "no"
+    else
+        #CXXFLAGS="$CXXFLAGS $MYSQL_CFLAGS"
+        echo "[$MYSQL_CFLAGS]"
+        echo -n "Checking for mysql_config --libs_r... "
+        MYSQL_LDFLAGS=`mysql_config --libs_r 2> /dev/null`
+        if [ $? != 0 ]
+        then
+            CHECK_MYSQLCLIENT=no
+            echo "no"
+        else
+            CHECK_MYSQLCLIENT=yes
+            #LDFLAGS="$LDFLAGS $MYSQL_LDFLAGS"
+            echo "[$MYSQL_LDFLAGS]"
+        fi
+    fi
+fi
+
+echo -n "Checking for pg_config... "
+PG_VERSION=`pg_config --version 2> /dev/null`
+if [ $? != 0 ]
+then
+    echo "no";
+    echo -n "Checking for -lpq... "
+    gcc $CXXFLAGS $LDFLAGS build_check.c -lpq $LIB_THREAD -o fake > /dev/null 2> /dev/null
+    if [ $? != 0 ]
+    then
+        CHECK_PQ=no
+        echo "no"
+    else
+        CHECK_PQ=yes
+        echo "yes"
+    fi
+    rm -f fake
+else
+    echo "yes";
+    echo -n "Checking for pg_config --includedir... "
+    PG_CFLAGS=`pg_config --includedir 2> /dev/null`
+    if [ $? != 0 ]
+    then
+        CHECK_PQ=no
+        echo "no"
+    else
+        echo "[$PG_CFLAGS]"
+        echo -n "Checking for pg_config --libdir... "
+        PG_LDFLAGS=`pg_config --libdir 2> /dev/null`
+        if [ $? != 0 ]
+        then
+            CHECK_PQ=no
+            echo "no"
+        else
+            CHECK_PQ=yes
+            echo "[$PG_LDFLAGS]"
+        fi
+    fi
+fi
+
+rm -f build_check.c
+
+if [ "$CHECK_FBCLIENT" = "yes" ]
+then
+    STG_LIBS="$STG_LIBS
+          ibpp.lib"
+    PLUGINS="$PLUGINS
+         store/firebird"
+fi
+
+if [ "$CHECK_PQ" = "yes" ]
+then
+    PLUGINS="$PLUGINS
+             store/postgresql"
+fi
+
+if [ "$CHECK_MYSQLCLIENT" = "yes" ]
+then
+    PLUGINS="$PLUGINS
+         store/mysql"
+fi
+
+echo "OS=$OS" > $CONFFILE
+echo "STG_TIME=yes" >> $CONFFILE
+echo "DIR_BUILD=$BUILD_DIR" >> $CONFFILE
+echo "DIR_LIB=\$(DIR_BUILD)/../../lib" >> $CONFFILE
+echo "DIR_LIBSRC=\$(DIR_BUILD)/../../stglibs" >> $CONFFILE
+echo "DIR_INCLUDE=\$(DIR_BUILD)/../../include" >> $CONFFILE
+echo "DIR_MOD=\$(DIR_BUILD)/../stargazer/modules" >> $CONFFILE
+echo "DIR_PLUGINS=\$(DIR_BUILD)/../stargazer/plugins" >> $CONFFILE
+echo "ARCH=$ARCH" >> $CONFFILE
+echo "CHECK_FBCLIENT=$CHECK_FBCLIENT" >> $CONFFILE
+echo "DEFS=$DEFS" >> $CONFFILE
+echo -n "STG_LIBS=" >> $CONFFILE
+for lib in $STG_LIBS
+do
+    echo -n "$lib " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo -n "PLUGINS=" >> $CONFFILE
+for plugin in $PLUGINS
+do
+    echo -n "$plugin " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo "SHELL=$SHELL" >> $CONFFILE
+echo "CXXFLAGS=$CXXFLAGS" >> $CONFFILE
+echo "LDFLAGS=$LDFLAGS" >> $CONFFILE
+echo "LIB_THREAD=$LIB_THREAD" >> $CONFFILE
+echo "PREFIX=$PREFIX" >> $CONFFILE
+echo "BIN_MODE=$BIN_MODE" >> $CONFFILE
+echo "DATA_MODE=$DATA_MODE" >> $CONFFILE
+echo "OWNER=$OWNER" >> $CONFFILE
+echo "VAR_DIR=$VAR_DIR" >> $CONFFILE
+
+mkdir -p ../stargazer/modules
+
+$MAKE $MAKEOPTS
+
diff --git a/projects/convertor/convertor.conf b/projects/convertor/convertor.conf
new file mode 100644 (file)
index 0000000..d2405ad
--- /dev/null
@@ -0,0 +1,66 @@
+################################################################################
+#                        æÁÊÌ ÎÁÓÔÒÏÅË ËÏÎ×ÅÒÔÏÒÁ stargazer                    #
+################################################################################
+
+# ðÕÔØ Ë ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÎÁÈÏÄÑÔÓÑ ÍÏÄÕÌÉ ÓÅÒ×ÅÒÁ
+ModulesPath = ../stargazer/modules
+
+################################################################################
+# Store module
+# îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ ÒÁÂÏÔÁÀÝÅÇÏ Ó âä ÓÅÒ×ÅÒÁ
+
+# ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+# ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_store_files.so
+<SourceStoreModule store_files>
+
+    # òÁÂÏÞÁÑ ÄÉÒÅËÔÏÒÉÑ ÓÅÒ×ÅÒÁ, ÔÕÔ ÓÏÄÅÒÖÁÔÓÑ ÄÁÎÎÙÅ Ï ÔÁÒÉÆÁÈ, ÐÏÌØÚÏ×ÁÔÅÌÑÈ,
+    # ÁÄÍÉÎÉÓÔÒÁÔÏÒÁÈ É Ô.Ä.
+    WorkDir = /var/stargazer
+
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÆÁÊÌÙ ÓÔÁÔÉÓÔÉËÉ (stat) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    ConfOwner = root
+    ConfGroup = wheel
+    ConfMode = 600
+
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÆÁÊÌÙ ËÏÎÆÉÇÕÒÁÃÉÉ (conf) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    StatOwner = root
+    StatGroup = wheel
+    StatMode = 640
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÌÏÇ-ÆÁÊÌÙ (log) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    UserLogOwner = root
+    UserLogGroup = wheel
+    UserLogMode = 640
+
+</SourceStoreModule>
+
+#<DestStoreModule store_firebird>
+#    server = localhost
+#    database = /var/stargazer/stargazer.fdb
+#    user = stg
+#    password = 123456
+#</DestStoreModule>
+
+<DestStoreModule store_postgresql>
+    server = localhost
+    database = stargazer
+    user = stg
+    password = 123456
+</DestStoreModule>
+
+#<DestStoreModule store_mysql>
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    dbuser = stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    rootdbpass = 123456
+#
+#    # éÍÑ âä ÎÁ ÓÅÒ×ÅÒÅ
+#    dbname = stg
+#
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    dbhost = localhost
+#</DestStoreModule>
+
diff --git a/projects/convertor/main.cpp b/projects/convertor/main.cpp
new file mode 100644 (file)
index 0000000..58ff7fb
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.11 $
+ $Date: 2010/03/25 12:32:30 $
+ $Author: faust $
+ */
+
+#include <dlfcn.h>
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <ctime>
+#include <algorithm>
+
+#include "common.h"
+#include "base_store.h"
+#include "settings.h"
+#include "conffiles.h"
+
+#include "user_stat.h"
+#include "user_conf.h"
+#include "corp_conf.h"
+#include "service_conf.h"
+#include "admin_conf.h"
+#include "tariff_conf.h"
+#include "base_settings.h"
+#include "stg_message.h"
+
+using namespace std;
+
+volatile time_t stgTime = time(NULL);
+
+int main(int argc, char **argv)
+{
+printfd(__FILE__, "Start\n");
+
+BASE_STORE * fromStore = NULL;
+BASE_STORE * toStore = NULL;
+
+SETTINGS * settings = NULL;
+
+string modulePath;
+
+MODULE_SETTINGS fromStoreSettings;
+MODULE_SETTINGS toStoreSettings;
+
+ADMIN_CONF ac;
+USER_CONF uc;
+USER_STAT us;
+STG_MSG msg;
+TARIFF_DATA td;
+CORP_CONF cc;
+SERVICE_CONF sc;
+vector<STG_MSG_HDR> hdrs;
+vector<STG_MSG_HDR>::iterator mit;
+
+void * src_lh;
+void * dst_lh;
+
+if (argc == 2)
+    settings = new SETTINGS(argv[1]);
+else
+    settings = new SETTINGS();
+
+if (settings->ReadSettings())
+{
+    printfd(__FILE__, "Error reading settings\n");
+    delete settings;
+    return -1;
+}
+
+fromStoreSettings = settings->GetSourceStoreModuleSettings();
+toStoreSettings = settings->GetDestStoreModuleSettings();
+modulePath = settings->GetModulesPath();
+
+string sourcePlugin(modulePath + "/mod_" + fromStoreSettings.moduleName + ".so");
+string destPlugin(modulePath + "/mod_" + toStoreSettings.moduleName + ".so");
+
+src_lh = dlopen(sourcePlugin.c_str(), RTLD_NOW);
+if (!src_lh)
+    {
+    printfd(__FILE__, "Source storage plugin loading failed: %s\n", dlerror());
+    delete settings;
+    return -1;
+    }
+
+dst_lh = dlopen(destPlugin.c_str(), RTLD_NOW);
+if (!dst_lh)
+    {
+    printfd(__FILE__, "Destination storage plugin loading failed: %s\n", dlerror());
+    delete settings;
+    return -1;
+    }
+
+BASE_STORE * (*GetSourceStore)();
+BASE_STORE * (*GetDestStore)();
+GetSourceStore = (BASE_STORE * (*)())dlsym(src_lh, "GetStore");
+if (!GetSourceStore)
+    {
+    printfd(__FILE__, "Source storage plugin loading failed. GetStore not found: %s\n", dlerror());
+    delete settings;
+    return -1;
+    }
+GetDestStore = (BASE_STORE * (*)())dlsym(dst_lh, "GetStore");
+if (!GetDestStore)
+    {
+    printfd(__FILE__, "Storage plugin (firebird) loading failed. GetStore not found: %s\n", dlerror());
+    delete settings;
+    return -1;
+    }
+
+fromStore = GetSourceStore();
+toStore = GetDestStore();
+
+vector<string> entities;
+vector<string> ready;
+vector<string>::const_iterator it;
+fromStore->SetSettings(fromStoreSettings);
+fromStore->ParseSettings();
+toStore->SetSettings(toStoreSettings);
+toStore->ParseSettings();
+
+printfd(__FILE__, "Importing admins:\n");
+entities.erase(entities.begin(), entities.end());
+ready.erase(ready.begin(), ready.end());
+if (fromStore->GetAdminsList(&entities))
+    {
+    printfd(__FILE__, "Error getting admins list: %s\n", fromStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+if (toStore->GetAdminsList(&ready))
+    {
+    printfd(__FILE__, "Error getting admins list: %s\n", toStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+for (it = entities.begin(); it != entities.end(); ++it)
+    {
+    printfd(__FILE__, "\t - %s\n", it->c_str());
+    if (find(ready.begin(), ready.end(), *it) == ready.end())
+        if (toStore->AddAdmin(*it))
+            {
+            printfd(__FILE__, "Error adding admin: %s\n", toStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+    if (fromStore->RestoreAdmin(&ac, *it))
+        {
+        printfd(__FILE__, "Error getting admin's confi: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    ac.login = *it;
+    if (toStore->SaveAdmin(ac))
+        {
+        printfd(__FILE__, "Error saving admin's conf: %s\n", toStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    }
+
+printfd(__FILE__, "Importing tariffs:\n");
+entities.erase(entities.begin(), entities.end());
+ready.erase(ready.begin(), ready.end());
+if (fromStore->GetTariffsList(&entities))
+    {
+    printfd(__FILE__, "Error getting tariffs list: %s\n", fromStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+if (toStore->GetTariffsList(&ready))
+    {
+    printfd(__FILE__, "Error getting tariffs list: %s\n", toStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+for (it = entities.begin(); it != entities.end(); ++it)
+    {
+    printfd(__FILE__, "\t - %s\n", it->c_str());
+    if (find(ready.begin(), ready.end(), *it) == ready.end())
+        if (toStore->AddTariff(*it))
+            {
+            printfd(__FILE__, "Error adding tariff: %s\n", toStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+    if (fromStore->RestoreTariff(&td, *it))
+        {
+        printfd(__FILE__, "Error getting tariff's data: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    if (toStore->SaveTariff(td, *it))
+        {
+        printfd(__FILE__, "Error saving tariff's data: %s\n", toStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    }
+
+printfd(__FILE__, "Importing services:\n");
+entities.erase(entities.begin(), entities.end());
+ready.erase(ready.begin(), ready.end());
+if (fromStore->GetServicesList(&entities))
+    {
+    printfd(__FILE__, "Error getting service list: %s\n", fromStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+if (toStore->GetServicesList(&ready))
+    {
+    printfd(__FILE__, "Error getting service list: %s\n", toStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+for (it = entities.begin(); it != entities.end(); ++it)
+    {
+    printfd(__FILE__, "\t - %s\n", it->c_str());
+    if (find(ready.begin(), ready.end(), *it) == ready.end())
+        if (toStore->AddService(*it))
+            {
+            printfd(__FILE__, "Error adding service: %s\n", toStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+    if (fromStore->RestoreService(&sc, *it))
+        {
+        printfd(__FILE__, "Error getting service's data: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    if (toStore->SaveService(sc))
+        {
+        printfd(__FILE__, "Error saving service's data: %s\n", toStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    }
+
+printfd(__FILE__, "Importing corporations:\n");
+entities.erase(entities.begin(), entities.end());
+ready.erase(ready.begin(), ready.end());
+if (fromStore->GetCorpsList(&entities))
+    {
+    printfd(__FILE__, "Error getting corporations list: %s\n", fromStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+if (toStore->GetCorpsList(&ready))
+    {
+    printfd(__FILE__, "Error getting corporations list: %s\n", toStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+for (it = entities.begin(); it != entities.end(); ++it)
+    {
+    printfd(__FILE__, "\t - %s\n", it->c_str());
+    if (find(ready.begin(), ready.end(), *it) == ready.end())
+        if (toStore->AddCorp(*it))
+            {
+            printfd(__FILE__, "Error adding corporation: %s\n", toStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+    if (fromStore->RestoreCorp(&cc, *it))
+        {
+        printfd(__FILE__, "Error getting corporation's data: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    if (toStore->SaveCorp(cc))
+        {
+        printfd(__FILE__, "Error saving corporation's data: %s\n", toStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    }
+
+printfd(__FILE__, "Importing users:\n");
+entities.erase(entities.begin(), entities.end());
+ready.erase(ready.begin(), ready.end());
+if (fromStore->GetUsersList(&entities))
+    {
+    printfd(__FILE__, "Error getting users list: %s\n", fromStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+if (toStore->GetUsersList(&ready))
+    {
+    printfd(__FILE__, "Error getting users list: %s\n", toStore->GetStrError().c_str());
+    dlclose(src_lh);
+    dlclose(dst_lh);
+    delete settings;
+    return -1;
+    }
+sort(ready.begin(), ready.end());
+for (it = entities.begin(); it != entities.end(); ++it)
+    {
+    printfd(__FILE__, "\t - %s\n", it->c_str());
+    if (!binary_search(ready.begin(), ready.end(), *it)) {
+        if (toStore->AddUser(*it))
+            {
+            printfd(__FILE__, "Error adding user: %s\n", toStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+    } else {
+        printfd(__FILE__, "\t\t(adding passed)\n");
+    }
+    if (fromStore->RestoreUserConf(&uc, *it))
+        {
+        printfd(__FILE__, "Error getting user's conf: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    if (fromStore->RestoreUserStat(&us, *it))
+        {
+        printfd(__FILE__, "Error getting user's stat: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    if (toStore->SaveUserConf(uc, *it))
+        {
+        printfd(__FILE__, "Error saving user's conf: %s\n", toStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    if (toStore->SaveUserStat(us, *it))
+        {
+        printfd(__FILE__, "Error saving user's stat: %s\n", toStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    hdrs.erase(hdrs.begin(), hdrs.end());
+    if (fromStore->GetMessageHdrs(&hdrs, *it))
+        {
+        printfd(__FILE__, "Error getting user's messages: %s\n", fromStore->GetStrError().c_str());
+        dlclose(src_lh);
+        dlclose(dst_lh);
+        delete settings;
+        return -1;
+        }
+    for (mit = hdrs.begin(); mit != hdrs.end(); ++mit)
+        {
+        if (fromStore->GetMessage(mit->id, &msg, *it))
+            {
+            printfd(__FILE__, "Error getting message for a user: %s\n", fromStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+        printfd(__FILE__, "\t\t * %s\n", msg.text.c_str());
+        if (toStore->AddMessage(&msg, *it))
+            {
+            printfd(__FILE__, "Error adding message to a user: %s\n", toStore->GetStrError().c_str());
+            dlclose(src_lh);
+            dlclose(dst_lh);
+            delete settings;
+            return -1;
+            }
+        }
+
+    }
+
+dlclose(src_lh);
+dlclose(dst_lh);
+printfd(__FILE__, "Done\n");
+delete settings;
+return 0;
+}
diff --git a/projects/convertor/settings.cpp b/projects/convertor/settings.cpp
new file mode 100644 (file)
index 0000000..33f4457
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ *    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>
+ */
+
+/*
+$Revision: 1.6 $
+$Date: 2009/06/22 16:26:54 $
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+
+using namespace std;
+
+#include "settings.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+SETTINGS::SETTINGS(const char * cf)
+{
+confFile = string(cf);
+}
+//-----------------------------------------------------------------------------
+SETTINGS::~SETTINGS()
+{
+
+}
+//-----------------------------------------------------------------------------
+/*
+int SETTINGS::ParseYesNo(const string & value, bool * val)
+{
+if (0 == strcasecmp(value.c_str(), "yes"))
+    {
+    *val = true;
+    return 0;
+    }
+if (0 == strcasecmp(value.c_str(), "no"))
+    {
+    *val = false;
+    return 0;
+    }
+
+strError = "Incorrect value \'" + value + "\'.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseInt(const string & value, int * val)
+{
+char *res;
+*val = strtol(value.c_str(), &res, 10);
+if (*res != 0)
+    {
+    strError = "Cannot convert \'" + value + "\' to integer.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseIntInRange(const string & value, int min, int max, int * val)
+{
+if (ParseInt(value, val) != 0)
+    return -1;
+
+if (*val < min || *val > max)
+    {
+    strError = "Value \'" + value + "\' out of range.";
+    return -1;
+    }
+
+return 0;
+}
+*/
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseModuleSettings(const DOTCONFDocumentNode * node, vector<PARAM_VALUE> * params)
+{
+/*if (!node)
+    return 0;*/
+const DOTCONFDocumentNode * childNode;
+PARAM_VALUE pv;
+const char * value;
+
+pv.param = node->getName();
+
+if (node->getValue(1))
+    {
+    strError = "Unexpected value \'" + string(node->getValue(1)) + "\'.";
+    return -1;
+    }
+
+value = node->getValue(0);
+
+if (!value)
+    {
+    strError = "Module name expected.";
+    return -1;
+    }
+
+childNode = node->getChildNode();
+while (childNode)
+    {
+    pv.param = childNode->getName();
+    int i = 0;
+    while ((value = childNode->getValue(i)) != NULL)
+        {
+        //printfd(__FILE__, "--> param=\'%s\' value=\'%s\'\n", childNode->getName(), value);
+        pv.value.push_back(value);
+        i++;
+        }
+    params->push_back(pv);
+    pv.value.clear();
+    childNode = childNode->getNextNode();
+    }
+
+/*for (unsigned i = 0; i < params->size(); i++)
+    {
+    printfd(__FILE__, "param \'%s\'\n", (*params)[i].param.c_str());
+    for (unsigned j = 0; j < (*params)[i].value.size(); j++)
+        {
+        printfd(__FILE__, "value \'%s\'\n", (*params)[i].value[j].c_str());
+        }
+    }*/
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+string SETTINGS::GetStrError() const
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ReadSettings()
+{
+const char * requiredOptions[] = {
+    "ModulesPath",
+    "SourceStoreModule",
+    "DestStoreModule",
+    NULL
+    };
+int sourceStoreModulesCount = 0;
+int destStoreModulesCount = 0;
+
+DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
+conf.setRequiredOptionNames(requiredOptions);
+
+//printfd(__FILE__, "Conffile: %s\n", confFile.c_str());
+
+if(conf.setContent(confFile.c_str()) != 0)
+    {
+    strError = "Cannot read file " + confFile + ".";
+    return -1;
+    }
+
+const DOTCONFDocumentNode * node = conf.getFirstNode();
+
+while (node)
+    {
+    if (strcasecmp(node->getName(), "ModulesPath") == 0)
+        {
+        modulesPath = node->getValue(0);
+        //printfd(__FILE__, "ModulesPath: %s\n", logFile.c_str());
+        }
+
+    if (strcasecmp(node->getName(), "SourceStoreModule") == 0)
+        {
+        // íÙ ×ÎÕÔÒÉ ÓÅËÃÉÉ StoreModule
+        //printfd(__FILE__, "StoreModule\n");
+
+        if (node->getValue(1))
+            {
+            // StoreModule ÄÏÌÖÅΠÉÍÅÔØ 1 ÁÔÒÉÂÕÔ
+            strError = "Unexpected \'" + string(node->getValue(1)) + "\'.";
+            return -1;
+            }
+
+        if (sourceStoreModulesCount)
+            {
+            // äÏÌÖÅΠÂÙÔØ ÔÏÌØËÏ ÏÄÉΠÍÏÄÕÌØ StoreModule!
+            strError = "Should be only one source StoreModule.";
+            return -1;
+            }
+        sourceStoreModulesCount++;
+
+        //storeModuleSettings.clear(); //TODO To make constructor
+        //printfd(__FILE__, "StoreModule %s\n", node->getValue());
+        sourceStoreModuleSettings.moduleName = node->getValue(0);
+        ParseModuleSettings(node, &sourceStoreModuleSettings.moduleParams);
+        }
+
+    if (strcasecmp(node->getName(), "DestStoreModule") == 0)
+        {
+        // íÙ ×ÎÕÔÒÉ ÓÅËÃÉÉ StoreModule
+        //printfd(__FILE__, "StoreModule\n");
+
+        if (node->getValue(1))
+            {
+            // StoreModule ÄÏÌÖÅΠÉÍÅÔØ 1 ÁÔÒÉÂÕÔ
+            strError = "Unexpected \'" + string(node->getValue(1)) + "\'.";
+            return -1;
+            }
+
+        if (destStoreModulesCount)
+            {
+            // äÏÌÖÅΠÂÙÔØ ÔÏÌØËÏ ÏÄÉΠÍÏÄÕÌØ StoreModule!
+            strError = "Should be only one dest StoreModule.";
+            return -1;
+            }
+        destStoreModulesCount++;
+
+        //storeModuleSettings.clear(); //TODO To make constructor
+        //printfd(__FILE__, "StoreModule %s\n", node->getValue());
+        destStoreModuleSettings.moduleName = node->getValue(0);
+        ParseModuleSettings(node, &destStoreModuleSettings.moduleParams);
+        }
+
+    node = node->getNextNode();
+    }
+
+//sort(modulesSettings.begin(), modulesSettings.end());
+//modulesSettings.erase(unique(modulesSettings.begin(), modulesSettings.end()), modulesSettings.end());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::Reload ()
+{
+return ReadSettings();
+}
+//-----------------------------------------------------------------------------
+const MODULE_SETTINGS & SETTINGS::GetSourceStoreModuleSettings() const
+{
+return sourceStoreModuleSettings;
+}
+//-----------------------------------------------------------------------------
+const MODULE_SETTINGS & SETTINGS::GetDestStoreModuleSettings() const
+{
+return destStoreModuleSettings;
+}
+//-----------------------------------------------------------------------------
+const string & SETTINGS::GetModulesPath() const
+{
+return modulesPath;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/convertor/settings.h b/projects/convertor/settings.h
new file mode 100644 (file)
index 0000000..129e7f9
--- /dev/null
@@ -0,0 +1,78 @@
+ /*
+ $Revision: 1.6 $
+ $Date: 2009/06/22 16:26:54 $
+ */
+
+/*
+ *    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>
+ */
+
+#ifndef settingsh_h
+#define settingsh_h 1
+
+#include <sys/types.h>
+#include <vector>
+#include <dotconfpp.h>
+
+#include "common.h"
+#include "base_settings.h"
+#include "stg_logger.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+class SETTINGS
+{
+public:
+    SETTINGS(const char * cf = "./convertor.conf");
+    ~SETTINGS();
+    int Reload();
+    int ReadSettings();
+
+    string GetStrError() const;
+
+    const string &  GetConfDir() const;
+
+    const string &  GetModulesPath() const;
+    const MODULE_SETTINGS         & GetSourceStoreModuleSettings() const;
+    const MODULE_SETTINGS         & GetDestStoreModuleSettings() const;
+
+private:
+
+    //int ParseInt(const string & value, int * val);
+    //int ParseIntInRange(const string & value, int min, int max, int * val);
+    //int ParseYesNo(const string & value, bool * val);
+
+    int ParseModuleSettings(const DOTCONFDocumentNode * dirNameNode, vector<PARAM_VALUE> * params);
+
+    string      strError;
+    //////////settings
+    string      modulesPath;
+    string      confFile;
+
+    MODULE_SETTINGS         sourceStoreModuleSettings;
+    MODULE_SETTINGS         destStoreModuleSettings;
+};
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/projects/make_tarball/get_from_cvs b/projects/make_tarball/get_from_cvs
new file mode 100755 (executable)
index 0000000..362f402
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/expect
+
+# login_cvs host password
+
+set user    [lindex $argv 0]
+set pass    [lindex $argv 1]
+set host    [lindex $argv 2]
+set cvsroot [lindex $argv 3]
+set module  [lindex $argv 4]
+set dir     [lindex $argv 5]
+
+set timeout 30
+
+send_user "checkout module $module";
+
+spawn ssh $user@$host
+expect {
+    "(yes/no)? " { 
+        send  "yes\r"
+        send_user "Key accepted";
+        }
+    "assword:" {
+        close
+        send_user "Key accepting dont needed";
+        }
+    }
+    
+spawn cvs -d :ext:$user@$host:$cvsroot co -N -d $dir $module 
+expect {
+    "assword:" {
+        send "$pass\r"
+        expect {
+            "assword:" { 
+                send_user "<h3><font color=red>cvs checkout $module failed. Incorrect password</font></h3>";
+                exit 1
+                }
+            "aborted" {
+                 send_user "<h3><font color=red>cvs checkout $module failed.</font></h3>";
+                 exit 1
+                 }
+            expect eof {
+            if {[lindex [wait] 3]} {
+                send_user "<h3><font color=red>cvs checkout $module failed.</font></h3>"
+                exit 1
+                }
+                }
+            }
+        }
+        
+     "aborted" {
+         send_user "<h3><font color=red>cvs checkout $module failed.</font></h3>";
+         exit 1
+         }
+    }
+  
+
+
+
diff --git a/projects/make_tarball/mt.sh b/projects/make_tarball/mt.sh
new file mode 100755 (executable)
index 0000000..0ad2e6b
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+
+cvs_host=stgteam.dp.ua
+cvs_user=<user>
+cvs_pass=<password>
+
+#arc_name=stg-2.4-`date "+%Y.%m.%d-%H.%M.%S"`.tgz
+#arc_name=stg-2.4-`date "+%Y.%m.%d-%H.%M.%S"`.tgz
+src_dir=stg-2.4-`date "+%Y.%m.%d-%H.%M.%S"`
+arc_name=$src_dir.tar.gz
+
+#mkdir $src_dir
+
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stgincludes include $src_dir
+
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/common.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/ibpp.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/common_settings.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/conffiles.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/crypto.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/stg_logger.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/stg_locker.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/hostallow.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/pinger.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/dotconfpp.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/ia_auth_c.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/script_executer.lib $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/srvconf.lib $src_dir
+
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/Makefile $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stglibs stglibs/Makefile.in $src_dir
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stargazer convertor $src_dir/projects
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stargazer stargazer $src_dir/projects
+
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/sgauth sgauth $src_dir/projects
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/sgconf sgconf $src_dir/projects
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/rscriptd rscriptd $src_dir/projects
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stargazer rlm_stg $src_dir/projects
+
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stgplugins plugins/store/firebird $src_dir/projects/stargazer
+./get_from_cvs $cvs_user $cvs_pass $cvs_host /cvsroot/stg3plugins max_mods/mysql $src_dir/projects/stargazer/plugins/store
+mv $src_dir/projects/stargazer/plugins/store/max_mods/mysql $src_dir/projects/stargazer/plugins/store/
+rm -rf $src_dir/projects/stargazer/plugins/store/max_mods
+rm -rf $src_dir/projects/stargazer/plugins/other/userstat
+rm -rf $src_dir/projects/stargazer/plugins/authorization/stress
+rm -rf $src_dir/projects/stargazer/plugins/store/db
+rm -rf $src_dir/projects/stargazer/plugins/configuration/rpcconfig
+
+rm -f $src_dir/include/lp2_blocks.h
+rm -f $src_dir/include/stdstring.h
+
+mkdir -p $src_dir/lib
+
+rm -fr $(find $src_dir/ -name CVS -type d)
+
+rm -fr $src_dir/projects/stargazer/inst/var/stargazer/users/CVS
+
+tar -czf $arc_name $src_dir
diff --git a/projects/rlm_stg/Makefile b/projects/rlm_stg/Makefile
new file mode 100644 (file)
index 0000000..deaf437
--- /dev/null
@@ -0,0 +1,81 @@
+###############################################################################
+# $Id: Makefile,v 1.5 2009/03/03 15:49:34 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+LIB_NAME = rlm_stg
+
+PROG = $(LIB_NAME).so
+
+SRCS = ./rlm_stg.cpp \
+       ./stg_client.cpp
+
+STGLIBS = -lstg_common \
+          -lstg_crypto
+
+LIBS += $(LIB_THREAD)
+
+ifeq ($(OS),linux)
+LIBS += -ldl
+else
+LIBS += -lintl \
+        -lc
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS += -Wall -fPIC -I./ 
+LDFLAGS += -shared -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg
+
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs install uninstall install-bin uninstall-bin
+all: libs $(PROG) ../../Makefile.conf
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+$(PROG): $(OBJS) $(STGLIBS) 
+       $(CC) $^ $(LDFLAGS) -o $(PROG) $(LIBS)
+
+clean:
+       rm -f deps $(PROG) *.o tags *.*~ .OS
+       rm -f .OS
+       rm -f core*
+       $(MAKE) -C $(DIR_LIBSRC) clean
+
+distclean: clean
+       rm -f ../../Makefile.conf
+
+install: install-bin
+
+install-bin:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/lib
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/lib/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) install
+
+uninstall: uninstall-bin
+
+uninstall-bin:
+       rm -f $(PREFIX)/usr/sbin/$(PROG)
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/rlm_stg/build b/projects/rlm_stg/build
new file mode 100755 (executable)
index 0000000..e1102fc
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+#   $Author: faust $
+#   $Revision: 1.13 $
+#   $Date: 2010/04/14 08:58:44 $
+######################################################
+
+OS=unknown
+sys=`uname -s`
+release=`uname -r | cut -b1`
+BUILD_DIR=`pwd`
+CONFFILE="../../Makefile.conf"
+PREFIX="/"
+BIN_MODE=0755
+OWNER=root
+
+if [ -z $1 ]
+then
+    MAKEOPTS="-j1"
+else
+    if [ "$1" = "debug" ]
+    then
+        DEFS="-DDEBUG"
+        MAKEOPTS="-j1"
+        CXXFLAGS="$CXXFLAGS -g3 -W -Wall"
+    else
+        MAKEOPTS="-j1"
+    fi
+fi
+
+CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+
+if [ "$sys" = "Linux" ]
+then
+    OS=linux
+    release=""
+    MAKE="make"
+fi
+
+if [ "$sys" = "FreeBSD" ]
+then
+    case $release in
+        4) OS=bsd;;
+        5) OS=bsd5;;
+        6) OS=bsd5;;
+        7) OS=bsd7;;
+        8) OS=bsd7;;
+        *) OS=unknown;;
+    esac
+    MAKE="gmake"
+fi
+
+if [ "$OS" = "unknown" ]
+then 
+    echo "#############################################################################"
+    echo "# Sorry, but rlm_stg currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #"
+    echo "#############################################################################"
+    exit 1
+fi
+
+echo "#############################################################################"
+echo "       Building rlm_stg for $sys $release"
+echo "#############################################################################"
+
+STG_LIBS="crypto.lib common.lib"
+
+if [ "$OS" = "linux" ]
+then
+    DEFS="$DEFS -DLINUX"
+    LIB_THREAD=-lpthread
+    SHELL="/bin/bash"
+else
+    if [ "$OS" = "bsd" ]
+    then
+        DEFS="$DEFS -DFREE_BSD"
+    else
+        DEFS="$DEFS -DFREE_BSD5"
+        if [ "$OS" = "bsd7" ]
+        then
+            LIB_THREAD=-lpthread
+        else
+            LIB_THREAD=-lc_r
+        fi
+    fi
+    SHELL="/usr/local/bin/bash"
+fi
+
+echo -n "Checking endianess... "
+echo "int main() { int probe = 0x00000001; return *(char *)&probe; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    echo "FAIL!"
+    echo "Endianess checking failed"
+    exit;
+else
+    ./fake
+    if [ $? = 1 ]
+    then
+        ARCH=le
+        CXXFLAGS="$CXXFLAGS -DARCH_LE"
+        echo "Little Endian"
+    else
+        ARCH=be
+        CXXFLAGS="$CXXFLAGS -DARCH_BE"
+        echo "Big Endian"
+    fi
+fi
+rm -f fake
+
+echo "OS=$OS" > $CONFFILE
+echo "STG_TIME=yes" >> $CONFFILE
+echo "DIR_BUILD=$BUILD_DIR" >> $CONFFILE
+echo "DIR_LIB=\$(DIR_BUILD)/../../lib" >> $CONFFILE
+echo "DIR_LIBSRC=\$(DIR_BUILD)/../../stglibs" >> $CONFFILE
+echo "DIR_INCLUDE=\$(DIR_BUILD)/../../include" >> $CONFFILE
+echo "ARCH=$ARCH" >> $CONFFILE
+echo "DEFS=$DEFS" >> $CONFFILE
+echo -n "STG_LIBS=" >> $CONFFILE
+for lib in $STG_LIBS
+do
+    echo -n "$lib " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo "CXXFLAGS=$CXXFLAGS" >> $CONFFILE
+echo "LDFLAGS=$LDFLAGS" >> $CONFFILE
+echo "LIB_THREAD=$LIB_THREAD" >> $CONFFILE
+echo "PREFIX=$PREFIX" >> $CONFFILE
+echo "BIN_MODE=$BIN_MODE" >> $CONFFILE
+echo "DATA_MODE=$DATA_MODE" >> $CONFFILE
+echo "OWNER=$OWNER" >> $CONFFILE
+echo "SHELL=$SHELL" >> $CONFFILE
+$MAKE $MAKEOPTS
+
diff --git a/projects/rlm_stg/build_check.c b/projects/rlm_stg/build_check.c
new file mode 100644 (file)
index 0000000..a5a7341
--- /dev/null
@@ -0,0 +1 @@
+int main() { int probe = 0x00000001; return *(char *)&probe; }
diff --git a/projects/rlm_stg/conf.h b/projects/rlm_stg/conf.h
new file mode 100644 (file)
index 0000000..e96eb71
--- /dev/null
@@ -0,0 +1,38 @@
+/* Default Database File Names */
+
+#define RADIUS_DIR             RADDBDIR
+#define RADACCT_DIR            RADIR
+#define RADLOG_DIR             LOGDIR
+
+#define RADIUS_DICTIONARY      "dictionary"
+#define RADIUS_CLIENTS         "clients"
+#define RADIUS_NASLIST         "naslist"
+#define RADIUS_REALMS          "realms"
+
+#define RADUTMP                        LOGDIR "/radutmp"
+#define SRADUTMP               LOGDIR "/sradutmp"
+#define RADWTMP                        LOGDIR "/radwtmp"
+#define SRADWTMP               LOGDIR "/sradwtmp"
+
+/* Hack for funky ascend ports on MAX 4048 (and probably others)
+   The "NAS-Port-Id" value is "xyyzz" where "x" = 1 for digital, 2 for analog;
+   "yy" = line number (1 for first PRI/T1/E1, 2 for second, so on);
+   "zz" = channel number (on the PRI or Channelized T1/E1).
+    This should work with normal terminal servers, unless you have a TS with
+        more than 9999 ports ;^).
+    The "ASCEND_CHANNELS_PER_LINE" is the number of channels for each line into
+        the unit.  For my US/PRI that's 23.  A US/T1 would be 24, and a
+        European E1 would be 30 (I think ... never had one ;^).
+    This will NOT change the "NAS-Port-Id" reported in the detail log.  This
+        is simply to fix the dynamic IP assignments a la Cistron.
+    You can change the default of 23 with an argument to ./configure.
+    WARNING: This hack works for me, but I only have one PRI!!!  I've not
+        tested it on 2 or more (or with models other than the Max 4048)
+    Use at your own risk!
+  -- dgreer@austintx.com
+*/
+#ifdef ASCEND_PORT_HACK
+#  ifndef ASCEND_CHANNELS_PER_LINE
+#    define ASCEND_CHANNELS_PER_LINE        23
+#  endif
+#endif
diff --git a/projects/rlm_stg/conffile.h b/projects/rlm_stg/conffile.h
new file mode 100644 (file)
index 0000000..e940e11
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef _CONFFILE_H
+#define _CONFFILE_H
+
+/*
+ * conffile.h  Defines for the conffile parsing routines.
+ *
+ * Version:    $Id: conffile.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ */
+
+#include <freeradius/ident.h>
+RCSIDH(conffile_h, "$Id: conffile.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+#include <stddef.h>
+#include <freeradius/token.h>
+
+/*
+ * Export the minimum amount of information about these structs
+ */
+typedef struct conf_item CONF_ITEM;
+typedef struct conf_pair CONF_PAIR;
+typedef struct conf_part CONF_SECTION;
+typedef struct conf_data CONF_DATA;
+
+/*
+ *  Instead of putting the information into a configuration structure,
+ *  the configuration file routines MAY just parse it directly into
+ *  user-supplied variables.
+ */
+#define PW_TYPE_STRING_PTR     100
+#define PW_TYPE_BOOLEAN                101
+#define PW_TYPE_SUBSECTION     102
+#define PW_TYPE_FILENAME       103
+
+typedef struct CONF_PARSER {
+  const char *name;
+  int type;                    /* PW_TYPE_STRING, etc. */
+  size_t offset;               /* relative pointer within "base" */
+  void *data;                  /* absolute pointer if base is NULL */
+  const char *dflt;            /* default as it would appear in radiusd.conf */
+} CONF_PARSER;
+
+/* This preprocessor trick will be useful in initializing CONF_PARSER struct */
+#define XStringify(x) #x
+#define Stringify(x) XStringify(x)
+
+void           cf_pair_free(CONF_PAIR **cp);
+int            cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp,
+                               const char *value);
+void           cf_section_free(CONF_SECTION **cp);
+int            cf_item_parse(CONF_SECTION *cs, const char *name,
+                             int type, void *data, const char *dflt);
+int            cf_section_parse(CONF_SECTION *, void *base,
+                                const CONF_PARSER *variables);
+void           cf_section_parse_free(CONF_SECTION *cs, void *base);
+const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs);
+CONF_SECTION   *cf_file_read(const char *file);
+int            cf_file_include(const char *file, CONF_SECTION *cs);
+
+CONF_PAIR      *cf_pair_find(const CONF_SECTION *, const char *name);
+CONF_PAIR      *cf_pair_find_next(const CONF_SECTION *, CONF_PAIR *, const char *name);
+CONF_SECTION   *cf_section_find(const char *name);
+CONF_SECTION   *cf_section_sub_find(const CONF_SECTION *, const char *name);
+CONF_SECTION   *cf_section_sub_find_name2(const CONF_SECTION *, const char *name1, const char *name2);
+const char     *cf_section_value_find(const CONF_SECTION *, const char *attr);
+CONF_SECTION   *cf_top_section(CONF_SECTION *cs);
+
+void *cf_data_find(CONF_SECTION *, const char *);
+int cf_data_add(CONF_SECTION *, const char *, void *, void (*)(void *));
+
+const char *cf_pair_attr(CONF_PAIR *pair);
+const char *cf_pair_value(CONF_PAIR *pair);
+VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair);
+const char *cf_section_name1(const CONF_SECTION *);
+const char *cf_section_name2(const CONF_SECTION *);
+int dump_config(CONF_SECTION *cs);
+CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
+                                     CONF_SECTION *subsection,
+                                     const char *name1);
+CONF_SECTION *cf_section_find_next(CONF_SECTION *section,
+                                  CONF_SECTION *subsection,
+                                  const char *name1);
+int cf_section_lineno(CONF_SECTION *section);
+int cf_pair_lineno(CONF_PAIR *pair);
+const char *cf_pair_filename(CONF_PAIR *pair);
+const char *cf_section_filename(CONF_SECTION *section);
+CONF_ITEM *cf_item_find_next(CONF_SECTION *section, CONF_ITEM *item);
+int cf_item_is_section(CONF_ITEM *item);
+int cf_item_is_pair(CONF_ITEM *item);
+CONF_PAIR *cf_itemtopair(CONF_ITEM *item);
+CONF_SECTION *cf_itemtosection(CONF_ITEM *item);
+CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp);
+CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs);
+int cf_section_template(CONF_SECTION *cs, CONF_SECTION *_template);
+void cf_log_err(CONF_ITEM *ci, const char *fmt, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 2, 3)))
+#endif
+;
+void cf_log_info(CONF_SECTION *cs, const char *fmt, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 2, 3)))
+#endif
+;
+void cf_log_module(CONF_SECTION *cs, const char *fmt, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 2, 3)))
+#endif
+;
+CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
+                            CONF_SECTION *outercs,
+                            const char *ptr);
+extern int cf_log_config;
+extern int cf_log_modules;
+
+extern int cf_pair2xml(FILE *fp, CONF_PAIR *cp);
+extern int cf_section2xml(FILE *fp, CONF_SECTION *cs);
+extern int cf_pair2file(FILE *fp, CONF_PAIR *cp);
+extern int cf_section2file(FILE *fp, CONF_SECTION *cs);
+
+/*
+ *     Big magic.
+ */
+int cf_section_migrate(CONF_SECTION *dst, CONF_SECTION *src);
+
+#endif /* _CONFFILE_H */
diff --git a/projects/rlm_stg/event.h b/projects/rlm_stg/event.h
new file mode 100644 (file)
index 0000000..704f13c
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef FR_EVENT_H
+#define FR_EVENT_H
+
+/*
+ * event.h     Simple event queue
+ *
+ * Version:    $Id: event.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+#include <freeradius/ident.h>
+RCSIDH(event_h, "$Id: event.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+typedef struct fr_event_list_t fr_event_list_t;
+typedef struct fr_event_t fr_event_t;
+
+typedef        void (*fr_event_callback_t)(void *);
+typedef        void (*fr_event_status_t)(struct timeval *);
+typedef void (*fr_event_fd_handler_t)(fr_event_list_t *el, int sock, void *ctx);
+
+fr_event_list_t *fr_event_list_create(fr_event_status_t status);
+void fr_event_list_free(fr_event_list_t *el);
+
+int fr_event_list_num_elements(fr_event_list_t *el);
+
+int fr_event_insert(fr_event_list_t *el,
+                     fr_event_callback_t callback,
+                     void *ctx, struct timeval *when, fr_event_t **ev_p);
+int fr_event_delete(fr_event_list_t *el, fr_event_t **ev_p);
+
+int fr_event_run(fr_event_list_t *el, struct timeval *when);
+
+int fr_event_now(fr_event_list_t *el, struct timeval *when);
+
+int fr_event_fd_insert(fr_event_list_t *el, int type, int fd,
+                        fr_event_fd_handler_t handler, void *ctx);
+int fr_event_fd_delete(fr_event_list_t *el, int type, int fd);
+int fr_event_loop(fr_event_list_t *el);
+void fr_event_loop_exit(fr_event_list_t *el, int code);
+
+#endif /* FR_HASH_H */
diff --git a/projects/rlm_stg/libradius.h b/projects/rlm_stg/libradius.h
new file mode 100644 (file)
index 0000000..b184a75
--- /dev/null
@@ -0,0 +1,470 @@
+#ifndef LIBRADIUS_H
+#define LIBRADIUS_H
+
+/*
+ * libradius.h Structures and prototypes
+ *             for the radius library.
+ *
+ * Version:    $Id: libradius.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  The FreeRADIUS server project
+ */
+
+#include <freeradius/ident.h>
+RCSIDH(libradius_h, "$Id: libradius.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+#include <errno.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "os_int.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <freeradius/radius.h>
+#include <freeradius/token.h>
+#include <freeradius/hash.h>
+
+#ifdef SIZEOF_UNSIGNED_INT
+#if SIZEOF_UNSIGNED_INT != 4
+#error FATAL: sizeof(unsigned int) != 4
+#endif
+#endif
+
+/*
+ *  Include for modules.
+ */
+#include <freeradius/sha1.h>
+#include <freeradius/md4.h>
+
+#define EAP_START               2
+
+#define AUTH_VECTOR_LEN                16
+#define CHAP_VALUE_LENGTH       16
+#define MAX_STRING_LEN         254     /* RFC2138: string 0-253 octets */
+
+#  define VENDOR(x)            ((x >> 16) & 0xffff)
+
+#ifdef _LIBRADIUS
+#  define AUTH_HDR_LEN         20
+#  define VENDORPEC_USR                429
+#define VENDORPEC_LUCENT       4846
+#define VENDORPEC_STARENT      8164
+#  define DEBUG                        if (fr_debug_flag && fr_log_fp) fr_printf_log
+#  define debug_pair(vp)       do { if (fr_debug_flag && fr_log_fp) { \
+                                       fputc('\t', fr_log_fp); \
+                                       vp_print(fr_log_fp, vp); \
+                                       fputc('\n', fr_log_fp); \
+                                    } \
+                               } while(0)
+#  define TAG_VALID(x)          ((x) > 0 && (x) < 0x20)
+#  define TAG_VALID_ZERO(x)     ((x) < 0x20)
+#  define TAG_ANY               -128   /* minimum signed char */
+#endif
+
+#if defined(__GNUC__)
+# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
+# define NEVER_RETURNS __attribute__ ((noreturn))
+# define UNUSED __attribute__ ((unused))
+# define BLANK_FORMAT " "      /* GCC_LINT whines about empty formats */
+#else
+# define PRINTF_LIKE(n)        /* ignore */
+# define NEVER_RETURNS /* ignore */
+# define UNUSED /* ignore */
+# define BLANK_FORMAT ""
+#endif
+
+typedef struct attr_flags {
+       unsigned int            addport : 1;  /* add NAS-Port to IP address */
+       unsigned int            has_tag : 1;  /* tagged attribute */
+       unsigned int            do_xlat : 1;  /* strvalue is dynamic */
+       unsigned int            unknown_attr : 1; /* not in dictionary */
+       unsigned int            array : 1; /* pack multiples into 1 attr */
+       unsigned int            has_value : 1; /* has a value */
+       unsigned int            has_value_alias : 1; /* has a value alias */
+       unsigned int            has_tlv : 1; /* has sub attributes */
+       unsigned int            is_tlv : 1; /* is a sub attribute */
+       unsigned int            encoded : 1; /* has been put into packet */
+
+       int8_t                  tag;          /* tag for tunneled attributes */
+       uint8_t                 encrypt;      /* encryption method */
+} ATTR_FLAGS;
+
+/*
+ *  Values of the encryption flags.
+ */
+#define FLAG_ENCRYPT_NONE            (0)
+#define FLAG_ENCRYPT_USER_PASSWORD   (1)
+#define FLAG_ENCRYPT_TUNNEL_PASSWORD (2)
+#define FLAG_ENCRYPT_ASCEND_SECRET   (3)
+
+typedef struct dict_attr {
+       unsigned int            attr;
+       int                     type;
+       int                     vendor;
+        ATTR_FLAGS              flags;
+       char                    name[1];
+} DICT_ATTR;
+
+typedef struct dict_value {
+       unsigned int            attr;
+       int                     value;
+       char                    name[1];
+} DICT_VALUE;
+
+typedef struct dict_vendor {
+       int                     vendorpec;
+       int                     type; /* length of type data */
+       int                     length; /* length of length data */
+       int                     flags;
+       char                    name[1];
+} DICT_VENDOR;
+
+typedef union value_pair_data {
+       char                    strvalue[MAX_STRING_LEN];
+       uint8_t                 octets[MAX_STRING_LEN];
+       struct in_addr          ipaddr;
+       struct in6_addr         ipv6addr;
+       uint32_t                date;
+       uint32_t                integer;
+       int32_t                 sinteger;
+       uint8_t                 filter[32];
+       uint8_t                 ifid[8]; /* struct? */
+       uint8_t                 ipv6prefix[18]; /* struct? */
+       uint8_t                 ether[6];
+       uint8_t                 *tlv;
+} VALUE_PAIR_DATA;
+
+typedef struct value_pair {
+       const char              *name;
+       int                     attribute;
+       int                     vendor;
+       int                     type;
+       size_t                  length; /* of data */
+       FR_TOKEN                _operator;
+        ATTR_FLAGS              flags;
+       struct value_pair       *next;
+       uint32_t                lvalue;
+       VALUE_PAIR_DATA         data;
+} VALUE_PAIR;
+#define vp_strvalue   data.strvalue
+#define vp_octets     data.octets
+#define vp_ipv6addr   data.ipv6addr
+#define vp_ifid       data.ifid
+#define vp_ipv6prefix data.ipv6prefix
+#define vp_filter     data.filter
+#define vp_ether      data.ether
+#define vp_signed     data.sinteger
+#define vp_tlv       data.tlv
+
+#if 0
+#define vp_ipaddr     data.ipaddr.s_addr
+#define vp_date       data.date
+#define vp_integer    data.integer
+#else
+/*
+ *     These are left as lvalue until we audit the source for code
+ *     that prints to vp_strvalue for integer/ipaddr/date types.
+ */
+#define vp_ipaddr     lvalue
+#define vp_date       lvalue
+#define vp_integer    lvalue
+#endif
+
+
+typedef struct fr_ipaddr_t {
+       int             af;     /* address family */
+       union {
+               struct in_addr  ip4addr;
+               struct in6_addr ip6addr; /* maybe defined in missing.h */
+       } ipaddr;
+} fr_ipaddr_t;
+
+/*
+ *     vector:         Request authenticator from access-request packet
+ *                     Put in there by rad_decode, and must be put in the
+ *                     response RADIUS_PACKET as well before calling rad_send
+ *
+ *     verified:       Filled in by rad_decode for accounting-request packets
+ *
+ *     data,data_len:  Used between rad_recv and rad_decode.
+ */
+typedef struct radius_packet {
+       int                     sockfd;
+       fr_ipaddr_t             src_ipaddr;
+        fr_ipaddr_t            dst_ipaddr;
+       uint16_t                src_port;
+       uint16_t                dst_port;
+       int                     id;
+       unsigned int            code;
+       uint32_t                hash;
+       uint8_t                 vector[AUTH_VECTOR_LEN];
+       time_t                  timestamp;
+       uint8_t                 *data;
+       int                     data_len;
+       VALUE_PAIR              *vps;
+       ssize_t                 offset;
+} RADIUS_PACKET;
+
+/*
+ *     Printing functions.
+ */
+int            fr_utf8_char(const uint8_t *str);
+void           fr_print_string(const char *in, size_t inlen,
+                                char *out, size_t outlen);
+int            vp_prints_value(char *out, size_t outlen,
+                               VALUE_PAIR *vp, int delimitst);
+const char     *vp_print_name(char *buffer, size_t bufsize, int attr);
+int            vp_prints(char *out, size_t outlen, VALUE_PAIR *vp);
+void           vp_print(FILE *, VALUE_PAIR *);
+void           vp_printlist(FILE *, VALUE_PAIR *);
+#define                fprint_attr_val vp_print
+
+/*
+ *     Dictionary functions.
+ */
+int            dict_addvendor(const char *name, int value);
+int            dict_addattr(const char *name, int vendor, int type, int value, ATTR_FLAGS flags);
+int            dict_addvalue(const char *namestr, const char *attrstr, int value);
+int            dict_init(const char *dir, const char *fn);
+void           dict_free(void);
+DICT_ATTR      *dict_attrbyvalue(unsigned int attr);
+DICT_ATTR      *dict_attrbyname(const char *attr);
+DICT_VALUE     *dict_valbyattr(unsigned int attr, int val);
+DICT_VALUE     *dict_valbyname(unsigned int attr, const char *val);
+int            dict_vendorbyname(const char *name);
+DICT_VENDOR    *dict_vendorbyvalue(int vendor);
+
+#if 1 /* FIXME: compat */
+#define dict_attrget   dict_attrbyvalue
+#define dict_attrfind  dict_attrbyname
+#define dict_valfind   dict_valbyname
+/*#define dict_valget  dict_valbyattr almost but not quite*/
+#endif
+
+/* get around diffrent ctime_r styles */
+#ifdef CTIMERSTYLE
+#if CTIMERSTYLE == SOLARISSTYLE
+#define CTIME_R(a,b,c) ctime_r(a,b,c)
+#else
+#define CTIME_R(a,b,c) ctime_r(a,b)
+#endif
+#else
+#define CTIME_R(a,b,c) ctime_r(a,b)
+#endif
+
+/* md5.c */
+
+void           fr_md5_calc(uint8_t *, const uint8_t *, unsigned int);
+
+/* hmac.c */
+
+void fr_hmac_md5(const uint8_t *text, int text_len,
+                  const uint8_t *key, int key_len,
+                  unsigned char *digest);
+
+/* hmacsha1.c */
+
+void fr_hmac_sha1(const uint8_t *text, int text_len,
+                   const uint8_t *key, int key_len,
+                   uint8_t *digest);
+
+/* radius.c */
+int            rad_send(RADIUS_PACKET *, const RADIUS_PACKET *, const char *secret);
+int            rad_packet_ok(RADIUS_PACKET *packet, int flags);
+RADIUS_PACKET  *rad_recv(int fd, int flags);
+ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
+                       int *code);
+void           rad_recv_discard(int sockfd);
+int            rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
+                          const char *secret);
+int            rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret);
+int            rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+                          const char *secret);
+int            rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+                        const char *secret);
+
+RADIUS_PACKET  *rad_alloc(int newvector);
+RADIUS_PACKET  *rad_alloc_reply(RADIUS_PACKET *);
+void           rad_free(RADIUS_PACKET **);
+int            rad_pwencode(char *encpw, size_t *len, const char *secret,
+                            const uint8_t *vector);
+int            rad_pwdecode(char *encpw, size_t len, const char *secret,
+                            const uint8_t *vector);
+int            rad_tunnel_pwencode(char *encpw, size_t *len, const char *secret,
+                                   const uint8_t *vector);
+int            rad_tunnel_pwdecode(uint8_t *encpw, size_t *len,
+                                   const char *secret, const uint8_t *vector);
+int            rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output,
+                               int id, VALUE_PAIR *password);
+VALUE_PAIR     *rad_attr2vp(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
+                            const char *secret, int attribute, int length,
+                            const uint8_t *data);
+int            rad_vp2attr(const RADIUS_PACKET *packet,
+                           const RADIUS_PACKET *original, const char *secret,
+                           const VALUE_PAIR *vp, uint8_t *ptr);
+
+/* valuepair.c */
+VALUE_PAIR     *pairalloc(DICT_ATTR *da);
+VALUE_PAIR     *paircreate(int attr, int type);
+void           pairfree(VALUE_PAIR **);
+void            pairbasicfree(VALUE_PAIR *pair);
+VALUE_PAIR     *pairfind(VALUE_PAIR *, int);
+void           pairdelete(VALUE_PAIR **, int);
+void           pairadd(VALUE_PAIR **, VALUE_PAIR *);
+void            pairreplace(VALUE_PAIR **first, VALUE_PAIR *add);
+int            paircmp(VALUE_PAIR *check, VALUE_PAIR *data);
+VALUE_PAIR     *paircopyvp(const VALUE_PAIR *vp);
+VALUE_PAIR     *paircopy(VALUE_PAIR *vp);
+VALUE_PAIR     *paircopy2(VALUE_PAIR *vp, int attr);
+void           pairmove(VALUE_PAIR **to, VALUE_PAIR **from);
+void           pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr);
+VALUE_PAIR     *pairparsevalue(VALUE_PAIR *vp, const char *value);
+VALUE_PAIR     *pairmake(const char *attribute, const char *value, int _operator);
+VALUE_PAIR     *pairread(const char **ptr, FR_TOKEN *eol);
+FR_TOKEN       userparse(const char *buffer, VALUE_PAIR **first_pair);
+VALUE_PAIR     *readvp2(FILE *fp, int *pfiledone, const char *errprefix);
+
+/*
+ *     Error functions.
+ */
+#ifdef _LIBRADIUS
+void           fr_strerror_printf(const char *, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+#endif
+void           fr_perror(const char *, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+extern const char *fr_strerror(void);
+extern int     fr_dns_lookups; /* 0 = no dns lookups */
+extern int     fr_debug_flag;  /* 0 = no debugging information */
+extern int     fr_max_attributes; /* per incoming packet */
+#define        FR_MAX_PACKET_CODE (52)
+extern const char *fr_packet_codes[FR_MAX_PACKET_CODE];
+extern FILE    *fr_log_fp;
+void           fr_printf_log(const char *, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+
+/*
+ *     Several handy miscellaneous functions.
+ */
+const char *   ip_ntoa(char *, uint32_t);
+char           *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid);
+uint8_t                *ifid_aton(const char *ifid_str, uint8_t *ifid);
+int            rad_lockfd(int fd, int lock_len);
+int            rad_lockfd_nonblock(int fd, int lock_len);
+int            rad_unlockfd(int fd, int lock_len);
+void           fr_bin2hex(const uint8_t *bin, char *hex, size_t len);
+size_t         fr_hex2bin(const char *hex, uint8_t *bin, size_t len);
+#ifndef HAVE_CLOSEFROM
+int            closefrom(int fd);
+#endif
+int fr_ipaddr_cmp(const fr_ipaddr_t *a, const fr_ipaddr_t *b);
+
+int            ip_hton(const char *src, int af, fr_ipaddr_t *dst);
+const char     *ip_ntoh(const fr_ipaddr_t *src, char *dst, size_t cnt);
+int fr_ipaddr2sockaddr(const fr_ipaddr_t *ipaddr, int port,
+                      struct sockaddr_storage *sa, socklen_t *salen);
+int fr_sockaddr2ipaddr(const struct sockaddr_storage *sa, socklen_t salen,
+                      fr_ipaddr_t *ipaddr, int * port);
+
+
+#ifdef ASCEND_BINARY
+/* filters.c */
+int            ascend_parse_filter(VALUE_PAIR *pair);
+void           print_abinary(VALUE_PAIR *vp, char *buffer, size_t len);
+#endif /*ASCEND_BINARY*/
+
+/* random numbers in isaac.c */
+/* context of random number generator */
+typedef struct fr_randctx {
+  uint32_t randcnt;
+  uint32_t randrsl[256];
+  uint32_t randmem[256];
+  uint32_t randa;
+  uint32_t randb;
+  uint32_t randc;
+} fr_randctx;
+
+void fr_isaac(fr_randctx *ctx);
+void fr_randinit(fr_randctx *ctx, int flag);
+uint32_t fr_rand(void);        /* like rand(), but better. */
+void fr_rand_seed(const void *, size_t ); /* seed the random pool */
+
+
+/* crypt wrapper from crypt.c */
+int fr_crypt_check(const char *key, const char *salt);
+
+/* rbtree.c */
+typedef struct rbtree_t rbtree_t;
+typedef struct rbnode_t rbnode_t;
+
+rbtree_t       *rbtree_create(int (*Compare)(const void *, const void *),
+                              void (*freeNode)(void *),
+                              int replace_flag);
+void           rbtree_free(rbtree_t *tree);
+int            rbtree_insert(rbtree_t *tree, void *Data);
+rbnode_t       *rbtree_insertnode(rbtree_t *tree, void *Data);
+void           rbtree_delete(rbtree_t *tree, rbnode_t *Z);
+int            rbtree_deletebydata(rbtree_t *tree, const void *data);
+rbnode_t       *rbtree_find(rbtree_t *tree, const void *Data);
+void          *rbtree_finddata(rbtree_t *tree, const void *Data);
+int            rbtree_num_elements(rbtree_t *tree);
+void          *rbtree_min(rbtree_t *tree);
+void          *rbtree_node2data(rbtree_t *tree, rbnode_t *node);
+
+/* callback order for walking  */
+typedef enum { PreOrder, InOrder, PostOrder } RBTREE_ORDER;
+
+/*
+ *     The callback should be declared as:
+ *     int callback(void *context, void *data)
+ *
+ *     The "context" is some user-defined context.
+ *     The "data" is the pointer to the user data in the node,
+ *       NOT the node itself.
+ *
+ *     It should return 0 if all is OK, and !0 for any error.
+ *     The walking will stop on any error.
+ */
+int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order, int (*callback)(void *, void *), void *context);
+
+/*
+ *     FIFOs
+ */
+typedef struct fr_fifo_t fr_fifo_t;
+typedef void (*fr_fifo_free_t)(void *);
+fr_fifo_t *fr_fifo_create(int max_entries, fr_fifo_free_t freeNode);
+void fr_fifo_free(fr_fifo_t *fi);
+int fr_fifo_push(fr_fifo_t *fi, void *data);
+void *fr_fifo_pop(fr_fifo_t *fi);
+void *fr_fifo_peek(fr_fifo_t *fi);
+int fr_fifo_num_elements(fr_fifo_t *fi);
+
+#include <freeradius/packet.h>
+
+#endif /*LIBRADIUS_H*/
diff --git a/projects/rlm_stg/modules.h b/projects/rlm_stg/modules.h
new file mode 100644 (file)
index 0000000..e241ca8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * module.h    Interface to the RADIUS module system.
+ *
+ * Version:    $Id: modules.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ */
+
+#ifndef RADIUS_MODULES_H
+#define RADIUS_MODULES_H
+
+#include <freeradius/ident.h>
+RCSIDH(modules_h, "$Id: modules.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+#include "conffile.h"
+
+typedef int (*packetmethod)(void *instance, REQUEST *request);
+
+enum {
+  RLM_COMPONENT_AUTH = 0,
+  RLM_COMPONENT_AUTZ,          /* 1 */
+  RLM_COMPONENT_PREACCT,       /* 2 */
+  RLM_COMPONENT_ACCT,          /* 3 */
+  RLM_COMPONENT_SESS,          /* 4 */
+  RLM_COMPONENT_PRE_PROXY,     /* 5 */
+  RLM_COMPONENT_POST_PROXY,    /* 6 */
+  RLM_COMPONENT_POST_AUTH,     /* 7 */
+#ifdef WITH_COA
+  RLM_COMPONENT_RECV_COA,      /* 8 */
+  RLM_COMPONENT_SEND_COA,      /* 9 */
+#endif
+  RLM_COMPONENT_COUNT          /* 8 / 10: How many components are there */
+};
+
+#define RLM_TYPE_THREAD_SAFE           (0 << 0)
+#define RLM_TYPE_THREAD_UNSAFE         (1 << 0)
+#define RLM_TYPE_CHECK_CONFIG_SAFE     (1 << 1)
+#define RLM_TYPE_HUP_SAFE              (1 << 2)
+
+#define RLM_MODULE_MAGIC_NUMBER ((uint32_t) (0xf4ee4ad2))
+#define RLM_MODULE_INIT RLM_MODULE_MAGIC_NUMBER
+
+typedef struct module_t {
+       uint32_t        magic;  /* may later be opaque struct */
+       const char      *name;
+       int             type;
+       int             (*instantiate)(CONF_SECTION *mod_cs, void **instance);
+       int             (*detach)(void *instance);
+       packetmethod    methods[RLM_COMPONENT_COUNT];
+} module_t;
+
+enum {
+       RLM_MODULE_REJECT,      /* immediately reject the request */
+       RLM_MODULE_FAIL,        /* module failed, don't reply */
+       RLM_MODULE_OK,          /* the module is OK, continue */
+       RLM_MODULE_HANDLED,     /* the module handled the request, so stop. */
+       RLM_MODULE_INVALID,     /* the module considers the request invalid. */
+       RLM_MODULE_USERLOCK,    /* reject the request (user is locked out) */
+       RLM_MODULE_NOTFOUND,    /* user not found */
+       RLM_MODULE_NOOP,        /* module succeeded without doing anything */
+       RLM_MODULE_UPDATED,     /* OK (pairs modified) */
+       RLM_MODULE_NUMCODES     /* How many return codes there are */
+};
+
+int setup_modules(int, CONF_SECTION *);
+int detach_modules(void);
+int module_hup(CONF_SECTION *modules);
+int module_authorize(int type, REQUEST *request);
+int module_authenticate(int type, REQUEST *request);
+int module_preacct(REQUEST *request);
+int module_accounting(int type, REQUEST *request);
+int module_checksimul(int type, REQUEST *request, int maxsimul);
+int module_pre_proxy(int type, REQUEST *request);
+int module_post_proxy(int type, REQUEST *request);
+int module_post_auth(int type, REQUEST *request);
+#ifdef WITH_COA
+int module_recv_coa(int type, REQUEST *request);
+int module_send_coa(int type, REQUEST *request);
+#define MODULE_NULL_COA_FUNCS ,NULL,NULL
+#else
+#define MODULE_NULL_COA_FUNCS
+#endif
+int indexed_modcall(int comp, int idx, REQUEST *request);
+
+/*
+ *     For now, these are strongly tied together.
+ */
+int virtual_servers_load(CONF_SECTION *config);
+void virtual_servers_free(time_t when);
+
+
+#endif /* RADIUS_MODULES_H */
diff --git a/projects/rlm_stg/radiusd.h b/projects/rlm_stg/radiusd.h
new file mode 100644 (file)
index 0000000..2b93ee3
--- /dev/null
@@ -0,0 +1,633 @@
+#ifndef RADIUSD_H
+#define RADIUSD_H
+/*
+ * radiusd.h   Structures, prototypes and global variables
+ *             for the FreeRADIUS server.
+ *
+ * Version:    $Id: radiusd.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 1999,2000,2002,2003,2004,2005,2006,2007,2008  The FreeRADIUS server project
+ *
+ */
+
+#include <freeradius/ident.h>
+RCSIDH(radiusd_h, "$Id: radiusd.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+#include "libradius.h"
+#include <freeradius/radpaths.h>
+#include "conf.h"
+#include "conffile.h"
+#include "event.h"
+
+typedef struct auth_req REQUEST;
+
+#ifdef HAVE_PTHREAD_H
+#include       <pthread.h>
+#endif
+
+#ifndef NDEBUG
+#define REQUEST_MAGIC (0xdeadbeef)
+#endif
+
+/*
+ *     New defines for minimizing the size of the server, to strip
+ *     out functionality.  In order to ensure that people don't have
+ *     to re-run "configure", after "cvs update", we play some
+ *     special games with the defines.  i.e. any top-level "configure"
+ *     option should set both WITH_FOO and WITHOUT_FOO.  After a few
+ *     weeks, the WITHOUT_FOO can be deleted from the configure script.
+ */
+#ifndef WITHOUT_PROXY
+#define WITH_PROXY (1)
+#endif
+
+#ifndef WITHOUT_DETAIL
+#define WITH_DETAIL (1)
+#endif
+
+#ifndef WITHOUT_SESSION_MGMT
+#define WITH_SESSION_MGMT (1)
+#endif
+
+#ifndef WITHOUT_UNLANG
+#define WITH_UNLANG (1)
+#endif
+
+#ifndef WITHOUT_ACCOUNTING
+#define WITH_ACCOUNTING (1)
+#else
+#ifdef WITH_SESSION_MGMT
+#error WITH_SESSION_MGMT is defined, but WITH_ACCOUNTING is not.  Session management requires accounting.
+#endif
+#ifdef WITH_DETAIL
+#error WITH_DETAIL is defined, but WITH_ACCOUNTING is not.  Detail file reading requires accounting.
+#endif
+#endif
+
+#ifndef WITHOUT_DYNAMIC_CLIENTS
+#define WITH_DYNAMIC_CLIENTS (1)
+#endif
+
+#ifndef WITHOUT_STATS
+#define WITH_STATS
+#endif
+
+#ifndef WITHOUT_COMMAND_SOCKET
+#ifdef HAVE_SYS_UN_H
+#define WITH_COMMAND_SOCKET (1)
+#endif
+#endif
+
+#ifndef WITHOUT_COA
+#define WITH_COA (1)
+#ifndef WITH_PROXY
+#error WITH_COA requires WITH_PROXY
+#endif
+#endif
+
+#include "stats.h"
+#include "realms.h"
+
+
+/*
+ *     See util.c
+ */
+typedef struct request_data_t request_data_t;
+
+typedef struct radclient {
+       fr_ipaddr_t             ipaddr;
+       int                     prefix;
+       char                    *longname;
+       char                    *secret;
+       char                    *shortname;
+       int                     message_authenticator;
+       char                    *nastype;
+       char                    *login;
+       char                    *password;
+       char                    *server;
+       int                     number; /* internal use only */
+       const CONF_SECTION      *cs;
+#ifdef WITH_STATS
+       fr_stats_t              *auth;
+#ifdef WITH_ACCOUNTING
+       fr_stats_t              *acct;
+#endif
+#endif
+
+#ifdef WITH_DYNAMIC_CLIENTS
+       int                     lifetime;
+       int                     dynamic; /* was dynamically defined */
+       time_t                  created;
+       time_t                  last_new_client;
+       char                    *client_server;
+#endif
+} RADCLIENT;
+
+/*
+ *     Types of listeners.
+ *
+ *     Ordered by priority!
+ */
+typedef enum RAD_LISTEN_TYPE {
+       RAD_LISTEN_NONE = 0,
+#ifdef WITH_PROXY
+       RAD_LISTEN_PROXY,
+#endif
+       RAD_LISTEN_AUTH,
+#ifdef WITH_ACCOUNTING
+       RAD_LISTEN_ACCT,
+#endif
+#ifdef WITH_DETAIL
+       RAD_LISTEN_DETAIL,
+#endif
+#ifdef WITH_VMPS
+       RAD_LISTEN_VQP,
+#endif
+#ifdef WITH_DHCP
+       RAD_LISTEN_DHCP,
+#endif
+#ifdef WITH_COMMAND_SOCKET
+       RAD_LISTEN_COMMAND,
+#endif
+#ifdef WITH_COA
+       RAD_LISTEN_COA,
+#endif
+       RAD_LISTEN_MAX
+} RAD_LISTEN_TYPE;
+
+
+/*
+ *     For listening on multiple IP's and ports.
+ */
+typedef struct rad_listen_t rad_listen_t;
+typedef                void (*radlog_func_t)(int, int, REQUEST *, const char *, ...);
+
+#define REQUEST_DATA_REGEX (0xadbeef00)
+#define REQUEST_MAX_REGEX (8)
+
+struct auth_req {
+#ifndef NDEBUG
+       uint32_t                magic; /* for debugging only */
+#endif
+       RADIUS_PACKET           *packet;
+#ifdef WITH_PROXY
+       RADIUS_PACKET           *proxy;
+#endif
+       RADIUS_PACKET           *reply;
+#ifdef WITH_PROXY
+       RADIUS_PACKET           *proxy_reply;
+#endif
+       VALUE_PAIR              *config_items;
+       VALUE_PAIR              *username;
+       VALUE_PAIR              *password;
+
+       struct main_config_t    *root;
+
+       request_data_t          *data;
+       RADCLIENT               *client;
+#ifdef HAVE_PTHREAD_H
+       pthread_t               child_pid;
+#endif
+       time_t                  timestamp;
+       int                     number; /* internal server number */
+
+       rad_listen_t            *listener;
+#ifdef WITH_PROXY
+       rad_listen_t            *proxy_listener;
+#endif
+
+
+       int                     simul_max; /* see modcall.c && xlat.c */
+#ifdef WITH_SESSION_MGMT
+       int                     simul_count;
+       int                     simul_mpp; /* WEIRD: 1 is false, 2 is true */
+#endif
+
+       int                     options; /* miscellanous options */
+       const char              *module; /* for debugging unresponsive children */
+       const char              *component; /* ditto */
+
+       struct timeval          received;
+       struct timeval          when;           /* to wake up */
+       int                     delay;
+
+       int                     master_state;
+       int                     child_state;
+       RAD_LISTEN_TYPE         priority;
+
+       fr_event_t              *ev;
+       struct timeval          next_when;
+       fr_event_callback_t     next_callback;
+
+       int                     in_request_hash;
+
+       const char              *server;
+       REQUEST                 *parent;
+       radlog_func_t           radlog; /* logging function, if set */
+#ifdef WITH_COA
+       REQUEST                 *coa;
+       int                     num_coa_requests;
+#endif
+};                             /* REQUEST typedef */
+
+#define RAD_REQUEST_OPTION_NONE            (0)
+#define RAD_REQUEST_OPTION_DEBUG           (1)
+#define RAD_REQUEST_OPTION_DEBUG2          (2)
+#define RAD_REQUEST_OPTION_DEBUG3          (3)
+#define RAD_REQUEST_OPTION_DEBUG4          (4)
+
+#define REQUEST_ACTIVE                 (1)
+#define REQUEST_STOP_PROCESSING (2)
+#define REQUEST_COUNTED                (3)
+
+#define REQUEST_QUEUED         (1)
+#define REQUEST_RUNNING                (2)
+#define REQUEST_PROXIED                (3)
+#define REQUEST_REJECT_DELAY   (4)
+#define REQUEST_CLEANUP_DELAY  (5)
+#define REQUEST_DONE           (6)
+
+/*
+ *  Function handler for requests.
+ */
+typedef                int (*RAD_REQUEST_FUNP)(REQUEST *);
+
+typedef struct radclient_list RADCLIENT_LIST;
+
+typedef struct pair_list {
+       const char              *name;
+       VALUE_PAIR              *check;
+       VALUE_PAIR              *reply;
+       int                     lineno;
+       int                     order;
+       struct pair_list        *next;
+       struct pair_list        *lastdefault;
+} PAIR_LIST;
+
+
+typedef int (*rad_listen_recv_t)(rad_listen_t *, RAD_REQUEST_FUNP *, REQUEST **);
+typedef int (*rad_listen_send_t)(rad_listen_t *, REQUEST *);
+typedef int (*rad_listen_print_t)(rad_listen_t *, char *, size_t);
+typedef int (*rad_listen_encode_t)(rad_listen_t *, REQUEST *);
+typedef int (*rad_listen_decode_t)(rad_listen_t *, REQUEST *);
+
+struct rad_listen_t {
+       struct rad_listen_t *next; /* should be rbtree stuff */
+
+       /*
+        *      For normal sockets.
+        */
+       RAD_LISTEN_TYPE type;
+       int             fd;
+       const char      *server;
+       int             status;
+
+       rad_listen_recv_t recv;
+       rad_listen_send_t send;
+       rad_listen_encode_t encode;
+       rad_listen_decode_t decode;
+       rad_listen_print_t print;
+
+       void            *data;
+
+#ifdef WITH_STATS
+       fr_stats_t      stats;
+#endif
+};
+
+#define RAD_LISTEN_STATUS_INIT   (0)
+#define RAD_LISTEN_STATUS_KNOWN  (1)
+#define RAD_LISTEN_STATUS_CLOSED (2)
+#define RAD_LISTEN_STATUS_FINISH (3)
+
+typedef enum radlog_dest_t {
+  RADLOG_STDOUT = 0,
+  RADLOG_FILES,
+  RADLOG_SYSLOG,
+  RADLOG_STDERR,
+  RADLOG_NULL,
+  RADLOG_NUM_DEST
+} radlog_dest_t;
+
+typedef struct main_config_t {
+       struct main_config *next;
+       int             refcount;
+       fr_ipaddr_t     myip;   /* from the command-line only */
+       int             port;   /* from the command-line only */
+       int             log_auth;
+       int             log_auth_badpass;
+       int             log_auth_goodpass;
+       int             allow_core_dumps;
+       int             debug_level;
+       int             proxy_requests;
+       int             reject_delay;
+       int             status_server;
+       int             max_request_time;
+       int             cleanup_delay;
+       int             max_requests;
+#ifdef DELETE_BLOCKED_REQUESTS
+       int             kill_unresponsive_children;
+#endif
+       char            *log_file;
+       char            *checkrad;
+       const char      *pid_file;
+       rad_listen_t    *listen;
+       int             syslog_facility;
+       int             radlog_fd;
+       radlog_dest_t   radlog_dest;
+       CONF_SECTION    *config;
+       const char      *name;
+       const char      *auth_badpass_msg;
+       const char      *auth_goodpass_msg;
+} MAIN_CONFIG_T;
+
+#define DEBUG  if(debug_flag)log_debug
+#define DEBUG2  if (debug_flag > 1)log_debug
+#define DEBUG3  if (debug_flag > 2)log_debug
+#define DEBUG4  if (debug_flag > 3)log_debug
+
+#if __GNUC__ >= 3
+#define RDEBUG(fmt, ...)   if(request && request->radlog) request->radlog(L_DBG, 1, request, fmt, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...)  if(request && request->radlog) request->radlog(L_DBG, 2, request, fmt, ## __VA_ARGS__)
+#define RDEBUG3(fmt, ...)  if(request && request->radlog) request->radlog(L_DBG, 3, request, fmt, ## __VA_ARGS__)
+#define RDEBUG4(fmt, ...)  if(request && request->radlog) request->radlog(L_DBG, 4, request, fmt, ## __VA_ARGS__)
+#else
+#define RDEBUG  DEBUG
+#define RDEBUG2 DEBUG2
+#define RDEBUG3 DEBUG3
+#define RDEBUG4 DEBUG4
+#endif
+
+#define SECONDS_PER_DAY                86400
+#define MAX_REQUEST_TIME       30
+#define CLEANUP_DELAY          5
+#define MAX_REQUESTS           256
+#define RETRY_DELAY             5
+#define RETRY_COUNT             3
+#define DEAD_TIME               120
+
+#define L_DBG                  1
+#define L_AUTH                 2
+#define L_INFO                 3
+#define L_ERR                  4
+#define L_PROXY                        5
+#define L_ACCT                 6
+#define L_CONS                 128
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+/*
+ *     This definition of true as NOT false is definitive. :) Making
+ *     it '1' can cause problems on stupid platforms.  See articles
+ *     on C portability for more information.
+ */
+#define TRUE (!FALSE)
+#endif
+
+/* for paircompare_register */
+typedef int (*RAD_COMPARE_FUNC)(void *instance, REQUEST *,VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
+
+typedef enum request_fail_t {
+  REQUEST_FAIL_UNKNOWN = 0,
+  REQUEST_FAIL_NO_THREADS,     /* no threads to handle it */
+  REQUEST_FAIL_DECODE,         /* rad_decode didn't like it */
+  REQUEST_FAIL_PROXY,          /* call to proxy modules failed */
+  REQUEST_FAIL_PROXY_SEND,     /* proxy_send didn't like it */
+  REQUEST_FAIL_NO_RESPONSE,    /* we weren't told to respond, so we reject */
+  REQUEST_FAIL_HOME_SERVER,    /* the home server didn't respond */
+  REQUEST_FAIL_HOME_SERVER2,   /* another case of the above */
+  REQUEST_FAIL_HOME_SERVER3,   /* another case of the above */
+  REQUEST_FAIL_NORMAL_REJECT,  /* authentication failure */
+  REQUEST_FAIL_SERVER_TIMEOUT  /* the server took too long to process the request */
+} request_fail_t;
+
+/*
+ *     Global variables.
+ *
+ *     We really shouldn't have this many.
+ */
+extern const char      *progname;
+extern int             debug_flag;
+extern const char      *radacct_dir;
+extern const char      *radlog_dir;
+extern const char      *radlib_dir;
+extern const char      *radius_dir;
+extern const char      *radius_libdir;
+extern uint32_t                expiration_seconds;
+extern int             log_stripped_names;
+extern int             log_auth_detail;
+extern const char      *radiusd_version;
+void                   radius_signal_self(int flag);
+
+#define RADIUS_SIGNAL_SELF_NONE                (0)
+#define RADIUS_SIGNAL_SELF_HUP         (1 << 0)
+#define RADIUS_SIGNAL_SELF_TERM                (1 << 1)
+#define RADIUS_SIGNAL_SELF_EXIT                (1 << 2)
+#define RADIUS_SIGNAL_SELF_DETAIL      (1 << 3)
+#define RADIUS_SIGNAL_SELF_NEW_FD      (1 << 4)
+#define RADIUS_SIGNAL_SELF_MAX         (1 << 5)
+
+
+/*
+ *     Function prototypes.
+ */
+
+/* acct.c */
+int            rad_accounting(REQUEST *);
+
+/* session.c */
+int            rad_check_ts(uint32_t nasaddr, unsigned int port, const char *user,
+                            const char *sessionid);
+int            session_zap(REQUEST *request, uint32_t nasaddr,
+                           unsigned int port, const char *user,
+                           const char *sessionid, uint32_t cliaddr,
+                           char proto,int session_time);
+
+/* radiusd.c */
+#undef debug_pair
+void           debug_pair(VALUE_PAIR *);
+void           debug_pair_list(VALUE_PAIR *);
+int            log_err (char *);
+
+/* util.c */
+void (*reset_signal(int signo, void (*func)(int)))(int);
+void           request_free(REQUEST **request);
+int            rad_mkdir(char *directory, int mode);
+int            rad_checkfilename(const char *filename);
+void           *rad_malloc(size_t size); /* calls exit(1) on error! */
+REQUEST                *request_alloc(void);
+REQUEST                *request_alloc_fake(REQUEST *oldreq);
+REQUEST                *request_alloc_coa(REQUEST *request);
+int            request_data_add(REQUEST *request,
+                                void *unique_ptr, int unique_int,
+                                void *opaque, void (*free_opaque)(void *));
+void           *request_data_get(REQUEST *request,
+                                 void *unique_ptr, int unique_int);
+void           *request_data_reference(REQUEST *request,
+                                 void *unique_ptr, int unique_int);
+int            rad_copy_string(char *dst, const char *src);
+int            rad_copy_variable(char *dst, const char *from);
+
+/* client.c */
+RADCLIENT_LIST *clients_init(void);
+void           clients_free(RADCLIENT_LIST *clients);
+RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section);
+void           client_free(RADCLIENT *client);
+int            client_add(RADCLIENT_LIST *clients, RADCLIENT *client);
+#ifdef WITH_DYNAMIC_CLIENTS
+void           client_delete(RADCLIENT_LIST *clients, RADCLIENT *client);
+RADCLIENT      *client_create(RADCLIENT_LIST *clients, REQUEST *request);
+#endif
+RADCLIENT      *client_find(const RADCLIENT_LIST *clients,
+                            const fr_ipaddr_t *ipaddr);
+RADCLIENT      *client_findbynumber(const RADCLIENT_LIST *clients,
+                                    int number);
+RADCLIENT      *client_find_old(const fr_ipaddr_t *ipaddr);
+int            client_validate(RADCLIENT_LIST *clients, RADCLIENT *master,
+                               RADCLIENT *c);
+RADCLIENT      *client_read(const char *filename, int in_server, int flag);
+
+
+/* files.c */
+int            pairlist_read(const char *file, PAIR_LIST **list, int complain);
+void           pairlist_free(PAIR_LIST **);
+
+/* version.c */
+void           version(void);
+
+/* log.c */
+int            vradlog(int, const char *, va_list ap);
+int            radlog(int, const char *, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 2, 3)))
+#endif
+;
+int            log_debug(const char *, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+void           vp_listdebug(VALUE_PAIR *vp);
+void radlog_request(int lvl, int priority, REQUEST *request, const char *msg, ...)
+#ifdef __GNUC__
+               __attribute__ ((format (printf, 4, 5)))
+#endif
+;
+
+/* auth.c */
+char   *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli);
+int            rad_authenticate (REQUEST *);
+int            rad_postauth(REQUEST *);
+
+/* exec.c */
+int            radius_exec_program(const char *,  REQUEST *, int,
+                                   char *user_msg, int msg_len,
+                                   VALUE_PAIR *input_pairs,
+                                   VALUE_PAIR **output_pairs,
+                                       int shell_escape);
+
+/* timestr.c */
+int            timestr_match(char *, time_t);
+
+/* valuepair.c */
+int            paircompare_register(int attr, int otherattr,
+                                    RAD_COMPARE_FUNC func,
+                                    void *instance);
+void           paircompare_unregister(int attr, RAD_COMPARE_FUNC func);
+int            paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
+                           VALUE_PAIR **reply);
+void           pairxlatmove(REQUEST *, VALUE_PAIR **to, VALUE_PAIR **from);
+int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp);
+int radius_callback_compare(REQUEST *req, VALUE_PAIR *request,
+                           VALUE_PAIR *check, VALUE_PAIR *check_pairs,
+                           VALUE_PAIR **reply_pairs);
+int radius_find_compare(int attribute);
+VALUE_PAIR     *radius_paircreate(REQUEST *request, VALUE_PAIR **vps,
+                                 int attribute, int type);
+VALUE_PAIR *radius_pairmake(REQUEST *request, VALUE_PAIR **vps,
+                           const char *attribute, const char *value,
+                           int _operator);
+
+/* xlat.c */
+typedef size_t (*RADIUS_ESCAPE_STRING)(char *out, size_t outlen, const char *in);
+
+int            radius_xlat(char * out, int outlen, const char *fmt,
+                          REQUEST * request, RADIUS_ESCAPE_STRING func);
+typedef size_t (*RAD_XLAT_FUNC)(void *instance, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING func);
+int            xlat_register(const char *module, RAD_XLAT_FUNC func,
+                             void *instance);
+void           xlat_unregister(const char *module, RAD_XLAT_FUNC func);
+void           xlat_free(void);
+
+/* threads.c */
+extern         int thread_pool_init(CONF_SECTION *cs, int *spawn_flag);
+extern         int thread_pool_addrequest(REQUEST *, RAD_REQUEST_FUNP);
+extern         pid_t rad_fork(void);
+extern         pid_t rad_waitpid(pid_t pid, int *status);
+extern          int total_active_threads(void);
+extern          void thread_pool_lock(void);
+extern          void thread_pool_unlock(void);
+extern         void thread_pool_queue_stats(int *array);
+
+#ifndef HAVE_PTHREAD_H
+#define rad_fork(n) fork()
+#define rad_waitpid(a,b) waitpid(a,b, 0)
+#endif
+
+/* mainconfig.c */
+/* Define a global config structure */
+extern struct main_config_t mainconfig;
+
+int read_mainconfig(int reload);
+int free_mainconfig(void);
+void hup_mainconfig(void);
+void fr_suid_down(void);
+void fr_suid_up(void);
+void fr_suid_down_permanent(void);
+
+/* listen.c */
+void listen_free(rad_listen_t **head);
+int listen_init(CONF_SECTION *cs, rad_listen_t **head);
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr, int exists);
+RADCLIENT *client_listener_find(const rad_listen_t *listener,
+                               const fr_ipaddr_t *ipaddr, int src_port);
+#ifdef WITH_STATS
+RADCLIENT_LIST *listener_find_client_list(const fr_ipaddr_t *ipaddr,
+                                         int port);
+rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port);
+#endif
+
+/* event.c */
+int radius_event_init(CONF_SECTION *cs, int spawn_flag);
+void radius_event_free(void);
+int radius_event_process(void);
+void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun);
+int received_request(rad_listen_t *listener,
+                    RADIUS_PACKET *packet, REQUEST **prequest,
+                    RADCLIENT *client);
+REQUEST *received_proxy_response(RADIUS_PACKET *packet);
+void event_new_fd(rad_listen_t *listener);
+
+/* evaluate.c */
+int radius_evaluate_condition(REQUEST *request, int modreturn, int depth,
+                             const char **ptr, int evaluate_it, int *presult);
+int radius_update_attrlist(REQUEST *request, CONF_SECTION *cs,
+                          VALUE_PAIR *input_vps, const char *name);
+void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from);
+#endif /*RADIUSD_H*/
diff --git a/projects/rlm_stg/realms.h b/projects/rlm_stg/realms.h
new file mode 100644 (file)
index 0000000..6b03bcd
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef REALMS_H
+#define REALMS_H
+
+/*
+ * realms.h    Structures, prototypes and global variables
+ *             for realms
+ *
+ * Version:    $Id: realms.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ */
+
+#include <freeradius/ident.h>
+RCSIDH(realms_h, "$Id: realms.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+#define HOME_TYPE_INVALID (0)
+#define HOME_TYPE_AUTH    (1)
+#define HOME_TYPE_ACCT    (2)
+#ifdef WITH_COA
+#define HOME_TYPE_COA     (3)
+#endif
+
+#define HOME_PING_CHECK_NONE           (0)
+#define HOME_PING_CHECK_STATUS_SERVER  (1)
+#define HOME_PING_CHECK_REQUEST                (2)
+
+#define HOME_STATE_ALIVE               (0)
+#define HOME_STATE_ZOMBIE              (1)
+#define HOME_STATE_IS_DEAD             (2)
+
+typedef struct home_server {
+       const char      *name;
+
+       const char      *hostname;
+       const char      *server; /* for internal proxying */
+
+       fr_ipaddr_t     ipaddr;
+
+       int             port;
+       int             type;           /* auth/acct */
+
+       /*
+        *      Maybe also have list of source IP/ports, && socket?
+        */
+
+       const char      *secret;
+
+       fr_event_t      *ev;
+       struct timeval  when;
+
+       int             response_window;
+       int             no_response_fail;
+       int             max_outstanding; /* don't overload it */
+       int             currently_outstanding;
+       int             message_authenticator;
+
+       struct timeval  revive_time;
+       struct timeval  zombie_period_start;
+       int             zombie_period; /* unresponsive for T, mark it dead */
+
+       int             state;
+
+       int             ping_check;
+       const char      *ping_user_name;
+       const char      *ping_user_password;
+
+       int             ping_interval;
+       int             num_pings_to_alive;
+       int             num_received_pings;
+       int             ping_timeout;
+
+       int             revive_interval; /* if it doesn't support pings */
+       CONF_SECTION    *cs;
+#ifdef WITH_COA
+       int                     coa_irt;
+       int                     coa_mrc;
+       int                     coa_mrt;
+       int                     coa_mrd;
+#endif
+#ifdef WITH_STATS
+       int             number;
+
+       fr_ipaddr_t     src_ipaddr; /* preferred source IP address */
+
+       fr_stats_t      stats;
+
+       fr_stats_ema_t  ema;
+#endif
+} home_server;
+
+
+typedef enum home_pool_type_t {
+       HOME_POOL_INVALID = 0,
+       HOME_POOL_LOAD_BALANCE,
+       HOME_POOL_FAIL_OVER,
+       HOME_POOL_CLIENT_BALANCE,
+       HOME_POOL_CLIENT_PORT_BALANCE,
+       HOME_POOL_KEYED_BALANCE
+} home_pool_type_t;
+
+
+typedef struct home_pool_t {
+       const char              *name;
+       home_pool_type_t        type;
+
+       int                     server_type;
+       CONF_SECTION            *cs;
+
+       const char              *virtual_server; /* for pre/post-proxy */
+       
+       home_server             *fallback;
+
+       int                     num_home_servers;
+       home_server             *servers[1];
+} home_pool_t;
+
+
+typedef struct _realm {
+       const char              *name;
+
+       int                     striprealm;
+
+       home_pool_t             *auth_pool;
+       home_pool_t             *acct_pool;
+} REALM;
+
+int realms_init(CONF_SECTION *config);
+void realms_free(void);
+REALM *realm_find(const char *name); /* name is from a packet */
+REALM *realm_find2(const char *name); /* ... with name taken from realm_find */
+
+home_server *home_server_ldb(const char *realmname, home_pool_t *pool, REQUEST *request);
+home_server *home_server_find(fr_ipaddr_t *ipaddr, int port);
+int    home_server_create_listeners(void *head);
+#ifdef WITH_COA
+home_server *home_server_byname(const char *name, int type);
+#endif
+#ifdef WITH_STATS
+home_server *home_server_bynumber(int number);
+#endif
+home_pool_t *home_pool_byname(const char *name, int type);
+
+#endif /* REALMS_H */
diff --git a/projects/rlm_stg/rlm_stg.cpp b/projects/rlm_stg/rlm_stg.cpp
new file mode 100644 (file)
index 0000000..f3860cf
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ *    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>
+ */
+
+/*
+ *  FreeRADIUS module for data access via Stargazer
+ *
+ *  $Revision: 1.8 $
+ *  $Date: 2010/08/14 04:15:08 $
+ *
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+extern "C" {
+//#include <freeradius/libradius.h>
+#include "radiusd.h"
+#include "modules.h"
+//#include <freeradius/conffile.h>
+}
+
+#include "stg_client.h"
+#include "common.h"
+
+STG_CLIENT * cli;
+volatile time_t stgTime;
+
+/*
+ *     Define a structure for our module configuration.
+ *
+ *     These variables do not need to be in a structure, but it's
+ *     a lot cleaner to do so, and a pointer to the structure can
+ *     be used as the instance handle.
+ */
+typedef struct rlm_stg_t {
+    char * server;
+    char * password;
+    uint32_t port;
+    uint32_t localPort;
+} rlm_stg_t;
+
+/*
+ *     A mapping of configuration file names to internal variables.
+ *
+ *     Note that the string is dynamically allocated, so it MUST
+ *     be freed.  When the configuration file parse re-reads the string,
+ *     it free's the old one, and strdup's the new one, placing the pointer
+ *     to the strdup'd string into 'config.string'.  This gets around
+ *     buffer over-flows.
+ */
+static CONF_PARSER module_config[] = {
+  { "password",  PW_TYPE_STRING_PTR, offsetof(rlm_stg_t,password), NULL,  NULL},
+  { "server",  PW_TYPE_STRING_PTR, offsetof(rlm_stg_t,server), NULL,  NULL},
+  { "port",  PW_TYPE_INTEGER,     offsetof(rlm_stg_t,port), NULL,  "5555" },
+  { "local_port", PW_TYPE_INTEGER,    offsetof(rlm_stg_t,localPort), NULL,   "0" },
+
+  { NULL, -1, 0, NULL, NULL }          /* end the list */
+};
+
+/*
+ *     Do any per-module initialization that is separate to each
+ *     configured instance of the module.  e.g. set up connections
+ *     to external databases, read configuration files, set up
+ *     dictionary entries, etc.
+ *
+ *     If configuration information is given in the config section
+ *     that must be referenced in later calls, store a handle to it
+ *     in *instance otherwise put a null pointer there.
+ */
+static int stg_instantiate(CONF_SECTION *conf, void **instance)
+{
+       rlm_stg_t *data;
+
+       /*
+        *      Set up a storage area for instance data
+        */
+        DEBUG("rlm_stg: stg_instantiate()");
+       data = (rlm_stg_t *)rad_malloc(sizeof(rlm_stg_t));
+       if (!data) {
+               return -1;
+       }
+       memset(data, 0, sizeof(rlm_stg_t));
+
+       /*
+        *      If the configuration parameters can't be parsed, then
+        *      fail.
+        */
+       if (cf_section_parse(conf, data, module_config) < 0) {
+               free(data);
+               return -1;
+       }
+
+        cli = new STG_CLIENT();
+        cli->SetServer(data->server);
+        cli->SetPort(data->port);
+        cli->SetLocalPort(data->localPort);
+        cli->SetPassword(data->password);
+        if (cli->Start()) {
+            DEBUG("rlm_stg: stg_instantiate() error: '%s'", cli->GetError().c_str());
+            return -1;
+        }
+
+       *instance = data;
+
+       return 0;
+}
+
+/*
+ *     Find the named user in this modules database.  Create the set
+ *     of attribute-value pairs to check and reply with for this user
+ *     from the database. The authentication code only needs to check
+ *     the password, the rest is done here.
+ */
+static int stg_authorize(void *instance, REQUEST *request)
+{
+       VALUE_PAIR *uname;
+       VALUE_PAIR *pwd;
+       VALUE_PAIR *svc;
+        DEBUG("rlm_stg: stg_authorize()");
+
+       /* quiet the compiler */
+       instance = instance;
+       request = request;
+
+        uname = pairfind(request->packet->vps, PW_USER_NAME);
+        if (uname) {
+            DEBUG("rlm_stg: stg_authorize() user name defined as '%s'", uname->vp_strvalue);
+        } else {
+            DEBUG("rlm_stg: stg_authorize() user name undefined");
+            return RLM_MODULE_FAIL;
+        }
+        if (request->username) {
+            DEBUG("rlm_stg: stg_authorize() request username field: '%s'", request->username->vp_strvalue);
+        }
+        if (request->password) {
+            DEBUG("rlm_stg: stg_authorize() request password field: '%s'", request->password->vp_strvalue);
+        }
+        // Here we need to define Framed-Protocol
+        svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
+        if (svc) {
+            DEBUG("rlm_stg: stg_authorize() Service-Type defined as '%s'", svc->vp_strvalue);
+            if (cli->Authorize((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue)) {
+                DEBUG("rlm_stg: stg_authorize() stg status: '%s'", cli->GetError().c_str());
+                return RLM_MODULE_REJECT;
+            }
+        } else {
+            DEBUG("rlm_stg: stg_authorize() Service-Type undefined");
+            if (cli->Authorize((const char *)request->username->vp_strvalue, "")) {
+                DEBUG("rlm_stg: stg_authorize() stg status: '%s'", cli->GetError().c_str());
+                return RLM_MODULE_REJECT;
+            }
+        }
+        pwd = pairmake("Cleartext-Password", cli->GetUserPassword().c_str(), T_OP_SET);
+        pairadd(&request->config_items, pwd);
+        //pairadd(&request->reply->vps, uname);
+
+       return RLM_MODULE_UPDATED;
+}
+
+/*
+ *     Authenticate the user with the given password.
+ */
+static int stg_authenticate(void *instance, REQUEST *request)
+{
+       /* quiet the compiler */
+        VALUE_PAIR *svc;
+       instance = instance;
+       request = request;
+        DEBUG("rlm_stg: stg_authenticate()");
+        svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
+        if (svc) {
+            DEBUG("rlm_stg: stg_authenticate() Service-Type defined as '%s'", svc->vp_strvalue);
+            if (cli->Authenticate((char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue)) {
+                DEBUG("rlm_stg: stg_authenticate() stg status: '%s'", cli->GetError().c_str());
+                return RLM_MODULE_REJECT;
+            }
+        } else {
+            DEBUG("rlm_stg: stg_authenticate() Service-Type undefined");
+            if (cli->Authenticate((char *)request->username->vp_strvalue, "")) {
+                DEBUG("rlm_stg: stg_authenticate() stg status: '%s'", cli->GetError().c_str());
+                return RLM_MODULE_REJECT;
+            }
+        }
+
+       return RLM_MODULE_NOOP;
+}
+
+/*
+ *     Massage the request before recording it or proxying it
+ */
+static int stg_preacct(void *instance, REQUEST *request)
+{
+       /* quiet the compiler */
+       instance = instance;
+       request = request;
+        DEBUG("rlm_stg: stg_preacct()");
+
+       return RLM_MODULE_OK;
+}
+
+/*
+ *     Write accounting information to this modules database.
+ */
+static int stg_accounting(void *instance, REQUEST *request)
+{
+       /* quiet the compiler */
+        VALUE_PAIR * sttype;
+        VALUE_PAIR * svc;
+        VALUE_PAIR * sessid;
+        svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
+       instance = instance;
+       request = request;
+        DEBUG("rlm_stg: stg_accounting()");
+
+        sessid = pairfind(request->packet->vps, PW_ACCT_SESSION_ID);
+        if (!sessid) {
+            DEBUG("rlm_stg: stg_accounting() Acct-Session-ID undefined");
+            return RLM_MODULE_FAIL;
+        }
+        sttype = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE);
+        if (sttype) {
+            DEBUG("Acct-Status-Type := %s", sttype->vp_strvalue);
+            if (svc) {
+                DEBUG("rlm_stg: stg_accounting() Service-Type defined as '%s'", svc->vp_strvalue);
+                if (cli->Account((const char *)sttype->vp_strvalue, (const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue, (const char *)sessid->vp_strvalue)) {
+                    DEBUG("rlm_stg: stg_accounting error: '%s'", cli->GetError().c_str());
+                    return RLM_MODULE_FAIL;
+                }
+            } else {
+                DEBUG("rlm_stg: stg_accounting() Service-Type undefined");
+                if (cli->Account((const char *)sttype->vp_strvalue, (const char *)request->username->vp_strvalue, "", (const char *)sessid->vp_strvalue)) {
+                    DEBUG("rlm_stg: stg_accounting error: '%s'", cli->GetError().c_str());
+                    return RLM_MODULE_FAIL;
+                }
+            }
+        } else {
+            DEBUG("Acct-Status-Type := NULL");
+        }
+
+       return RLM_MODULE_OK;
+}
+
+/*
+ *     See if a user is already logged in. Sets request->simul_count to the
+ *     current session count for this user and sets request->simul_mpp to 2
+ *     if it looks like a multilink attempt based on the requested IP
+ *     address, otherwise leaves request->simul_mpp alone.
+ *
+ *     Check twice. If on the first pass the user exceeds his
+ *     max. number of logins, do a second pass and validate all
+ *     logins by querying the terminal server (using eg. SNMP).
+ */
+static int stg_checksimul(void *instance, REQUEST *request)
+{
+        instance = instance;
+        DEBUG("rlm_stg: stg_checksimul()");
+
+        request->simul_count=0;
+
+        return RLM_MODULE_OK;
+}
+
+static int stg_postauth(void *instance, REQUEST *request)
+{
+        instance = instance;
+        VALUE_PAIR *fia;
+        VALUE_PAIR *svc;
+        struct in_addr fip;
+        DEBUG("rlm_stg: stg_postauth()");
+        svc = pairfind(request->packet->vps, PW_SERVICE_TYPE);
+        if (svc) {
+            DEBUG("rlm_stg: stg_postauth() Service-Type defined as '%s'", svc->vp_strvalue);
+            if (cli->PostAuthenticate((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue)) {
+                DEBUG("rlm_stg: stg_postauth() error: '%s'", cli->GetError().c_str());
+                return RLM_MODULE_FAIL;
+            }
+        } else {
+            DEBUG("rlm_stg: stg_postauth() Service-Type undefined");
+            if (cli->PostAuthenticate((const char *)request->username->vp_strvalue, "")) {
+                DEBUG("rlm_stg: stg_postauth() error: '%s'", cli->GetError().c_str());
+                return RLM_MODULE_FAIL;
+            }
+        }
+        if (strncmp((const char *)svc->vp_strvalue, "Framed-User", 11) == 0) {
+            fip.s_addr = cli->GetFramedIP();
+            DEBUG("rlm_stg: stg_postauth() ip = '%s'", inet_ntostring(fip.s_addr).c_str());
+            fia = pairmake("Framed-IP-Address", inet_ntostring(fip.s_addr).c_str(), T_OP_SET);
+            pairadd(&request->reply->vps, fia);
+        }
+
+        return RLM_MODULE_UPDATED;
+}
+
+static int stg_detach(void *instance)
+{
+        DEBUG("rlm_stg: stg_detach()");
+        cli->Stop();
+        delete cli;
+       free(((struct rlm_stg_t *)instance)->server);
+       free(((struct rlm_stg_t *)instance)->password);
+       free(instance);
+       return 0;
+}
+
+/*
+ *     The module name should be the only globally exported symbol.
+ *     That is, everything else should be 'static'.
+ *
+ *     If the module needs to temporarily modify it's instantiation
+ *     data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ *     The server will then take care of ensuring that the module
+ *     is single-threaded.
+ */
+module_t rlm_stg = {
+        RLM_MODULE_INIT,
+       "stg",
+       RLM_TYPE_THREAD_SAFE,           /* type */
+       stg_instantiate,                /* instantiation */
+       stg_detach,                     /* detach */
+       {
+               stg_authenticate,       /* authentication */
+               stg_authorize,  /* authorization */
+               stg_preacct,    /* preaccounting */
+               stg_accounting, /* accounting */
+               stg_checksimul, /* checksimul */
+               NULL,                   /* pre-proxy */
+               NULL,                   /* post-proxy */
+               stg_postauth                    /* post-auth */
+       },
+};
diff --git a/projects/rlm_stg/stats.h b/projects/rlm_stg/stats.h
new file mode 100644 (file)
index 0000000..f584cba
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef FR_STATS_H
+#define FR_STATS_H
+
+/*
+ * stats.h     Structures and functions for statistics.
+ *
+ * Version:    $Id: stats.h,v 1.1 2010/08/14 04:13:52 faust Exp $
+ *
+ *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2005,2006,2007,2008  The FreeRADIUS server project
+ */
+
+#include <freeradius/ident.h>
+RCSIDH(stats_h, "$Id: stats.h,v 1.1 2010/08/14 04:13:52 faust Exp $")
+
+#ifdef WITH_STATS_64BIT
+typedef uint64_t fr_uint_t;
+#else
+typedef uint32_t fr_uint_t;
+#endif
+
+#ifdef WITH_STATS
+typedef struct fr_stats_t {
+       fr_uint_t               total_requests;
+       fr_uint_t               total_invalid_requests;
+       fr_uint_t               total_dup_requests;
+       fr_uint_t               total_responses;
+       fr_uint_t               total_access_accepts;
+       fr_uint_t               total_access_rejects;
+       fr_uint_t               total_access_challenges;
+       fr_uint_t               total_malformed_requests;
+       fr_uint_t               total_bad_authenticators;
+       fr_uint_t               total_packets_dropped;
+       fr_uint_t               total_no_records;
+       fr_uint_t               total_unknown_types;
+} fr_stats_t;
+
+typedef struct fr_stats_ema_t {
+       int             window;
+
+       int             f1, f10;
+       int             ema1, ema10;
+
+} fr_stats_ema_t;
+
+extern fr_stats_t      radius_auth_stats;
+extern fr_stats_t      radius_acct_stats;
+#ifdef WITH_PROXY
+extern fr_stats_t      proxy_auth_stats;
+extern fr_stats_t      proxy_acct_stats;
+#endif
+
+void radius_stats_init(int flag);
+void request_stats_final(REQUEST *request);
+void request_stats_reply(REQUEST *request);
+void radius_stats_ema(fr_stats_ema_t *ema,
+                     struct timeval *start, struct timeval *end);
+
+#define RAD_STATS_INC(_x) _x++
+#ifdef WITH_ACCOUNTING
+#define RAD_STATS_TYPE_INC(_listener, _x) if (_listener->type == RAD_LISTEN_AUTH) { \
+                                       radius_auth_stats._x++; \
+                                    } else if (_listener->type == RAD_LISTEN_ACCT) { \
+                                       radius_acct_stats._x++; } \
+                                      _listener->stats._x++
+
+#define RAD_STATS_CLIENT_INC(_listener, _client, _x) if (_listener->type == RAD_LISTEN_AUTH) \
+                                       _client->auth->_x++; \
+                                    else if (_listener->type == RAD_LISTEN_ACCT) \
+                                       _client->acct->_x++
+
+#else  /* WITH_ACCOUNTING */
+
+#define RAD_STATS_TYPE_INC(_listener, _x) { radius_auth_stats._x++; _listener->stats._x++; }
+
+#define RAD_STATS_CLIENT_INC(_listener, _client, _x) _client->auth->_x++
+
+#endif /* WITH_ACCOUNTING */
+
+
+#else  /* WITH_STATS */
+#define request_stats_init(_x)
+#define request_stats_final(_x)
+
+#define  RAD_STATS_INC(_x)
+#define RAD_STATS_TYPE_INC(_listener, _x)
+#define RAD_STATS_CLIENT_INC(_listener, _client, _x)
+
+#endif
+
+#endif /* FR_STATS_H */
diff --git a/projects/rlm_stg/stg_client.cpp b/projects/rlm_stg/stg_client.cpp
new file mode 100644 (file)
index 0000000..7be0a55
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Realization of data access via Stargazer for RADIUS
+ *
+ *  $Revision: 1.8 $
+ *  $Date: 2010/04/16 12:30:02 $
+ *
+ */
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <unistd.h> // close
+#include <cstring>
+
+#include "stg_client.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+STG_CLIENT::STG_CLIENT()
+    : port(0),
+      localPort(0),
+      sock(0)
+{
+}
+//-----------------------------------------------------------------------------
+STG_CLIENT::~STG_CLIENT()
+{
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::SetServer(const string & host)
+{
+STG_CLIENT::host = host;
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::SetPort(uint16_t port)
+{
+STG_CLIENT::port = port;
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::SetLocalPort(uint16_t port)
+{
+STG_CLIENT::localPort = port;
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::SetPassword(const string & password)
+{
+STG_CLIENT::password = password;
+}
+//-----------------------------------------------------------------------------
+uint32_t STG_CLIENT::GetFramedIP() const
+{
+return framedIP;
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::InitEncrypt()
+{
+unsigned char keyL[RAD_PASSWORD_LEN];
+memset(keyL, 0, RAD_PASSWORD_LEN);
+strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
+Blowfish_Init(&ctx, keyL, RAD_PASSWORD_LEN);
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::PrepareNet()
+{
+sock = socket(AF_INET, SOCK_DGRAM, 0);
+if (sock == -1)
+    {
+    errorStr = "Socket create error";
+    return -1;
+    }
+
+struct hostent * he = NULL;
+he = gethostbyname(host.c_str());
+if (he == NULL)
+    {
+    errorStr = "gethostbyname error";
+    return -1;
+    }
+
+if (localPort != 0)
+    {
+    struct sockaddr_in localAddr;
+    localAddr.sin_family = AF_INET;
+    localAddr.sin_port = htons(localPort);
+    localAddr.sin_addr.s_addr = inet_addr("0.0.0.0");;
+
+    if (bind(sock, (struct sockaddr *)&localAddr, sizeof(localAddr)))
+        {
+        errorStr = "Bind failed";
+        return -1;
+        }
+    }
+
+outerAddr.sin_family = AF_INET;
+outerAddr.sin_port = htons(port);
+outerAddr.sin_addr.s_addr = *(uint32_t *)he->h_addr;
+
+outerAddrLen = sizeof(struct sockaddr_in);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::FinalizeNet()
+{
+close(sock);
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Start()
+{
+InitEncrypt();
+
+return PrepareNet();
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Stop()
+{
+FinalizeNet();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+string STG_CLIENT::GetUserPassword() const
+{
+return userPassword;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Send(const RAD_PACKET & packet)
+{
+char buf[RAD_MAX_PACKET_LEN];
+    
+Encrypt(buf, (char *)&packet, sizeof(RAD_PACKET) / 8);
+
+int res = sendto(sock, buf, sizeof(RAD_PACKET), 0, (struct sockaddr *)&outerAddr, outerAddrLen);
+
+if (res == -1)
+    errorStr = "Error sending data";
+
+return res;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::RecvData(RAD_PACKET * packet)
+{
+char buf[RAD_MAX_PACKET_LEN];
+int res;
+
+outerAddrLen = sizeof(struct sockaddr_in);
+
+res = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, (struct sockaddr *)&outerAddr, &outerAddrLen);
+if (res == -1)
+    {
+    errorStr = "Error receiving data";
+    return -1;
+    }
+
+Decrypt((char *)packet, buf, res / 8);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType)
+{
+int res;
+
+memcpy((void *)&packet->magic, (void *)RAD_ID, RAD_MAGIC_LEN);
+packet->protoVer[0] = '0';
+packet->protoVer[1] = '1';
+packet->packetType = packetType;
+packet->ip = 0;
+strncpy((char *)packet->login, login.c_str(), RAD_LOGIN_LEN);
+strncpy((char *)packet->service, svc.c_str(), RAD_SERVICE_LEN);
+
+res = Send(*packet);
+if (res == -1)
+    return -1;
+
+res = RecvData(packet);
+if (res == -1)
+    return -1;
+
+if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
+    {
+    errorStr = "Magic invalid. Wanted: '";
+    errorStr += RAD_ID;
+    errorStr += "', got: '";
+    errorStr += (char *)packet->magic;
+    errorStr += "'";
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Authorize(const string & login, const string & svc)
+{
+RAD_PACKET packet;
+
+userPassword = "";
+
+if (Request(&packet, login, svc, RAD_AUTZ_PACKET))
+    return -1;
+
+if (packet.packetType != RAD_ACCEPT_PACKET)
+    return -1;
+
+userPassword = (char *)packet.password;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Authenticate(const string & login, const string & svc)
+{
+RAD_PACKET packet;
+
+userPassword = "";
+
+if (Request(&packet, login, svc, RAD_AUTH_PACKET))
+    return -1;
+
+if (packet.packetType != RAD_ACCEPT_PACKET)
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::PostAuthenticate(const string & login, const string & svc)
+{
+RAD_PACKET packet;
+
+userPassword = "";
+
+if (Request(&packet, login, svc, RAD_POST_AUTH_PACKET))
+    return -1;
+
+if (packet.packetType != RAD_ACCEPT_PACKET)
+    return -1;
+
+if (svc == "Framed-User")
+    framedIP = packet.ip;
+else
+    framedIP = 0;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CLIENT::Account(const std::string & type, const string & login, const string & svc, const string & sessid)
+{
+RAD_PACKET packet;
+
+userPassword = "";
+strncpy((char *)packet.sessid, sessid.c_str(), RAD_SESSID_LEN);
+
+if (type == "Start")
+    {
+    if (Request(&packet, login, svc, RAD_ACCT_START_PACKET))
+        return -1;
+    }
+else if (type == "Stop")
+    {
+    if (Request(&packet, login, svc, RAD_ACCT_STOP_PACKET))
+        return -1;
+    }
+else if (type == "Interim-Update")
+    {
+    if (Request(&packet, login, svc, RAD_ACCT_UPDATE_PACKET))
+        return -1;
+    }
+else
+    {
+    if (Request(&packet, login, svc, RAD_ACCT_OTHER_PACKET))
+        return -1;
+    }
+
+if (packet.packetType != RAD_ACCEPT_PACKET)
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void STG_CLIENT::Encrypt(char * dst, const char * src, int len8)         
+{
+// len8 - длина в 8-ми байтовых блоках                                                   
+if (dst != src) 
+    memcpy(dst, src, len8 * 8);                                                          
+    
+for (int i = 0; i < len8; i++)
+    Blowfish_Encrypt(&ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
+}
+//-----------------------------------------------------------------------------          
+void STG_CLIENT::Decrypt(char * dst, const char * src, int len8)
+{
+// len8 - длина в 8-ми байтовых блоках
+if (dst != src)
+    memcpy(dst, src, len8 * 8);
+
+for (int i = 0; i < len8; i++)
+    Blowfish_Decrypt(&ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/rlm_stg/stg_client.h b/projects/rlm_stg/stg_client.h
new file mode 100644 (file)
index 0000000..60ed6af
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+/*
+ *  Header file for client part of data access via Stargazer for RADIUS
+ *
+ *  $Revision: 1.4 $
+ *  $Date: 2010/04/16 12:30:02 $
+ *
+ */
+
+#ifndef STG_CLIENT_H
+#define STG_CLIENT_H
+
+#include <string>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h> // socklen_t
+
+#include "blowfish.h"
+#include "rad_packets.h"
+
+class STG_CLIENT
+{
+public:
+    STG_CLIENT();
+    ~STG_CLIENT();
+
+    void SetServer(const std::string & host);
+    void SetPort(uint16_t port);
+    void SetLocalPort(uint16_t port);
+    void SetPassword(const std::string & password);
+
+    int Start();
+    int Stop();
+
+    std::string GetUserPassword() const;
+
+    int Authorize(const std::string & login, const std::string & svc);
+    int Authenticate(const std::string & login, const std::string & svc);
+    int PostAuthenticate(const std::string & login, const std::string & svc);
+    int Account(const std::string & type, const std::string & login, const std::string & svc, const std::string & sessid);
+
+    uint32_t GetFramedIP() const;
+
+
+    const std::string & GetError() const { return errorStr; };
+
+private:
+    std::string host;
+    uint16_t port;
+    uint16_t localPort;
+    std::string password;
+    int sock;
+    std::string errorStr;
+
+    struct sockaddr_in outerAddr;
+    socklen_t outerAddrLen;
+
+    std::string userPassword;
+
+    uint32_t framedIP;
+
+    BLOWFISH_CTX ctx;
+
+    int PrepareNet();
+    void FinalizeNet();
+
+    void InitEncrypt();
+    void Encrypt(char * dst, const char * src, int len8);
+    void Decrypt(char * dst, const char * src, int len8);
+
+    int Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType);
+
+    int RecvData(RAD_PACKET * packet);
+    int Send(const RAD_PACKET & packet);
+
+};
+
+#endif
diff --git a/projects/rscriptd/Makefile b/projects/rscriptd/Makefile
new file mode 100644 (file)
index 0000000..03e95fa
--- /dev/null
@@ -0,0 +1,94 @@
+###############################################################################
+# $Id: Makefile,v 1.18 2010/02/11 12:22:01 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = rscriptd
+
+SRCS = ./main.cpp \
+       ./listener.cpp \
+       ./pidfile.cpp
+
+STGLIBS =  -lstg_logger \
+           -lstg_common \
+          -lstg_crypto \
+           -lscript_executer \
+           -lconffiles
+
+LIBS += $(LIB_THREAD)
+
+#ifeq ($(OS),linux)
+#LIBS += -ldl
+#else
+#LIBS += -lc
+#endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS += -Wall
+LDFLAGS += -Wl,-E -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-rpath-link,$(DIR_LIB)
+
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs install uninstall
+all: libs $(PROG) ../../Makefile.conf
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+$(PROG): $(OBJS) $(STGLIBS) 
+       $(CC) $^ $(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*
+       $(MAKE) -C $(DIR_LIBSRC) clean
+
+distclean: clean
+       rm -f ../../Makefile.conf
+
+install: install-bin install-data
+
+install-bin:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/sbin
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) install
+
+install-data:
+       # Install etc
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/etc/stargazer
+       install -m $(DATA_MODE) -o $(OWNER) ./rscriptd.conf $(PREFIX)/etc/stargazer/rscriptd.conf
+
+uninstall: uninstall-bin uninstall-data
+
+uninstall-bin:
+       rm -f $(PREFIX)/usr/sbin/$(PROG)
+
+uninstall-data:
+       # Uninstall etc
+       rm -f $(PREFIX)/etc/stragazer/rscriptd.conf
+
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/rscriptd/build b/projects/rscriptd/build
new file mode 100755 (executable)
index 0000000..38302ee
--- /dev/null
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+#   $Author: faust $
+#   $Revision: 1.21 $
+#   $Date: 2010/04/14 08:58:52 $
+######################################################
+
+OS=unknown
+sys=`uname -s`
+release=`uname -r | cut -b1`
+BUILD_DIR=`pwd`
+CONFFILE="../../Makefile.conf"
+PREFIX="/"
+BIN_MODE=0755
+DATA_MODE=0644
+OWNER=root
+
+if [ -z $1 ]
+then
+    MAKEOPTS="-j1"
+else
+    if [ "$1" = "debug" ]
+    then
+        DEFS="-DDEBUG"
+        MAKEOPTS="-j1"
+        CXXFLAGS="$CXXFLAGS -g3 -W -Wall"
+    else
+        MAKEOPTS="-j1"
+    fi
+fi
+
+CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+
+if [ "$sys" = "Linux" ]
+then
+    OS=linux
+    release=""
+    MAKE="make"
+fi
+
+if [ "$sys" = "FreeBSD" ]
+then
+    case $release in
+        4) OS=bsd;;
+        5) OS=bsd5;;
+        6) OS=bsd5;;
+        7) OS=bsd7;;
+        8) OS=bsd7;;
+        *) OS=unknown;;
+    esac
+    MAKE="gmake"
+fi
+
+if [ "$OS" = "unknown" ]
+then 
+    echo "#############################################################################"
+    echo "# Sorry, but rscriptd currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #"
+    echo "#############################################################################"
+    exit 1
+fi
+
+echo "#############################################################################"
+echo "       Building rscriptd for $sys $release"
+echo "#############################################################################"
+
+STG_LIBS="stg_logger.lib 
+          stg_locker.lib
+         crypto.lib 
+         common.lib 
+         script_executer.lib 
+         conffiles.lib"
+
+if [ "$OS" = "linux" ]
+then
+    DEFS="$DEFS -DLINUX"
+    LIB_THREAD=-lpthread
+    SHELL="/bin/bash"
+else
+    if [ "$OS" = "bsd" ]
+    then
+        DEFS="$DEFS -DFREE_BSD"
+        LIB_THREAD=-lc_r
+    else
+        DEFS="$DEFS -DFREE_BSD5"
+        if [ "$OS" = "bsd7" ]
+        then
+            LIB_THREAD=-lpthread
+        else
+            LIB_THREAD=-lc_r
+        fi
+    fi
+    SHELL="/usr/local/bin/bash"
+fi
+
+echo -n "Checking endianess... "
+echo "int main() { int probe = 0x00000001; return *(char *)&probe; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    echo "FAIL!"
+    echo "Endianess checking failed"
+    exit;
+else
+    ./fake
+    if [ $? = 1 ]
+    then
+        ARCH=le
+        CXXFLAGS="$CXXFLAGS -DARCH_LE"
+        echo "Little Endian"
+    else
+        ARCH=be
+        CXXFLAGS="$CXXFLAGS -DARCH_BE"
+        echo "Big Endian"
+    fi
+fi
+rm -f fake
+rm -f build_check.c
+
+echo "OS=$OS" > $CONFFILE
+echo "STG_TIME=yes" >> $CONFFILE
+echo "DIR_BUILD=$BUILD_DIR" >> $CONFFILE
+echo "DIR_LIB=\$(DIR_BUILD)/../../lib" >> $CONFFILE
+echo "DIR_LIBSRC=\$(DIR_BUILD)/../../stglibs" >> $CONFFILE
+echo "DIR_INCLUDE=\$(DIR_BUILD)/../../include" >> $CONFFILE
+echo "ARCH=$ARCH" >> $CONFFILE
+echo "DEFS=$DEFS" >> $CONFFILE
+echo -n "STG_LIBS=" >> $CONFFILE
+for lib in $STG_LIBS
+do
+    echo -n "$lib " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo "LIB_THREAD=$LIB_THREAD" >> $CONFFILE
+echo "SHELL=$SHELL" >> $CONFFILE
+echo "CXXFLAGS=$CXXFLAGS" >> $CONFFILE
+echo "LDFLAGS=$LDFLAGS" >> $CONFFILE
+echo "PREFIX=$PREFIX" >> $CONFFILE
+echo "BIN_MODE=$BIN_MODE" >> $CONFFILE
+echo "DATA_MODE=$DATA_MODE" >> $CONFFILE
+echo "OWNER=$OWNER" >> $CONFFILE
+
+$MAKE $MAKEOPTS
+
diff --git a/projects/rscriptd/listener.cpp b/projects/rscriptd/listener.cpp
new file mode 100644 (file)
index 0000000..87a85eb
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include <arpa/inet.h>
+#include <sys/uio.h> // readv
+#include <sys/types.h> // for historical versions of BSD
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <csignal>
+#include <ctime>
+#include <cstring>
+#include <sstream>
+#include <algorithm>
+
+#include "listener.h"
+#include "script_executer.h"
+#include "stg_locker.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+LISTENER::LISTENER()
+    : WriteServLog(GetStgLogger()),
+      port(0),
+      running(false),
+      receiverStopped(true),
+      processorStopped(true),
+      userTimeout(0),
+      listenSocket(0)
+{
+version = "rscriptd listener v.1.2";
+
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+void LISTENER::SetPassword(const string & p)
+{
+password = p;
+printfd(__FILE__, "Encryption initiated with password \'%s\'\n", password.c_str());
+InitEncrypt(&ctxS, password);
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Start()
+{
+printfd(__FILE__, "LISTENER::Start()\n");
+running = true;
+
+if (PrepareNet())
+    {
+    return true;
+    }
+
+if (receiverStopped)
+    {
+    if (pthread_create(&receiverThread, NULL, Run, this))
+        {
+        errorStr = "Cannot create thread.";
+        return true;
+        }
+    }
+
+if (processorStopped)
+    {
+    if (pthread_create(&processorThread, NULL, RunProcessor, this))
+        {
+        errorStr = "Cannot create thread.";
+        return true;
+        }
+    }
+
+errorStr = "";
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Stop()
+{
+running = false;
+
+printfd(__FILE__, "LISTENER::Stop()\n");
+
+usleep(500000);
+
+if (!processorStopped)
+    {
+    //5 seconds to thread stops itself
+    for (int i = 0; i < 25 && !processorStopped; i++)
+        {
+        usleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (!processorStopped)
+        {
+        //TODO pthread_cancel()
+        if (pthread_kill(processorThread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            return true;
+            }
+        printfd(__FILE__, "LISTENER killed Timeouter\n");
+        }
+    }
+
+if (!receiverStopped)
+    {
+    //5 seconds to thread stops itself
+    for (int i = 0; i < 25 && !receiverStopped; i++)
+        {
+        usleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (!receiverStopped)
+        {
+        //TODO pthread_cancel()
+        if (pthread_kill(receiverThread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            return true;
+            }
+        printfd(__FILE__, "LISTENER killed Run\n");
+        }
+    }
+
+pthread_join(receiverThread, NULL);
+pthread_join(processorThread, NULL);
+
+pthread_mutex_destroy(&mutex);
+
+FinalizeNet();
+
+std::for_each(users.begin(), users.end(), DisconnectUser(*this));
+
+printfd(__FILE__, "LISTENER::Stoped successfully.\n");
+
+return false;
+}
+//-----------------------------------------------------------------------------
+void * LISTENER::Run(void * d)
+{
+LISTENER * ia = static_cast<LISTENER *>(d);
+
+ia->Runner();
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::Runner()
+{
+receiverStopped = false;
+
+while (running)
+    {
+    RecvPacket();
+    }
+
+receiverStopped = true;
+}
+//-----------------------------------------------------------------------------
+void * LISTENER::RunProcessor(void * d)
+{
+LISTENER * ia = static_cast<LISTENER *>(d);
+
+ia->ProcessorRunner();
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::ProcessorRunner()
+{
+processorStopped = false;
+
+while (running)
+    {
+    usleep(500000);
+    if (!pending.empty())
+        ProcessPending();
+    ProcessTimeouts();
+    }
+
+processorStopped = true;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::PrepareNet()
+{
+listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (listenSocket < 0)
+    {
+    errorStr = "Cannot create socket.";
+    return true;
+    }
+
+printfd(__FILE__, "Port: %d\n", port);
+
+struct sockaddr_in listenAddr;
+listenAddr.sin_family = AF_INET;
+listenAddr.sin_port = htons(port);
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+if (bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0)
+    {
+    errorStr = "LISTENER: Bind failed.";
+    return true;
+    }
+
+printfd(__FILE__, "LISTENER::PrepareNet() >>>> Start successfull.\n");
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::FinalizeNet()
+{
+close(listenSocket);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::RecvPacket()
+{
+struct iovec iov[2];
+
+char buffer[RS_MAX_PACKET_LEN];
+RS_PACKET_HEADER packetHead;
+
+iov[0].iov_base = reinterpret_cast<char *>(&packetHead);
+iov[0].iov_len = sizeof(packetHead);
+iov[1].iov_base = buffer;
+iov[1].iov_len = sizeof(buffer);
+
+size_t dataLen = 0;
+while (dataLen < sizeof(buffer))
+    {
+    if (!WaitPackets(listenSocket))
+        {
+        if (!running)
+            return false;
+        continue;
+        }
+    int portion = readv(listenSocket, iov, 2);
+    if (portion < 0)
+        {
+        return true;
+        }
+    dataLen += portion;
+    }
+
+if (CheckHeader(packetHead))
+    {
+    printfd(__FILE__, "Invalid packet or incorrect protocol version!\n");
+    return true;
+    }
+
+std::string userLogin((char *)packetHead.login);
+PendingData data;
+data.login = userLogin;
+data.ip = ntohl(packetHead.ip);
+data.id = ntohl(packetHead.id);
+
+if (packetHead.packetType == RS_ALIVE_PACKET)
+    {
+    data.type = PendingData::ALIVE;
+    }
+else if (packetHead.packetType == RS_CONNECT_PACKET)
+    {
+    data.type = PendingData::CONNECT;
+    if (GetParams(buffer, data))
+        {
+        return true;
+        }
+    }
+else if (packetHead.packetType == RS_DISCONNECT_PACKET)
+    {
+    data.type = PendingData::DISCONNECT;
+    if (GetParams(buffer, data))
+        {
+        return true;
+        }
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+pending.push_back(data);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::GetParams(char * buffer, UserData & data)
+{
+RS_PACKET_TAIL packetTail;
+
+Decrypt(&ctxS, (char *)&packetTail, buffer, sizeof(packetTail) / 8);
+
+if (strncmp((char *)packetTail.magic, RS_ID, RS_MAGIC_LEN))
+    {
+    printfd(__FILE__, "Invalid crypto magic\n");
+    return true;
+    }
+
+std::stringstream params;
+params << data.login << " "
+       << inet_ntostring(data.ip) << " "
+       << ntohl(data.id) << " "
+       << (char *)packetTail.params;
+
+data.params = params.str();
+
+return false;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::ProcessPending()
+{
+printfd(__FILE__, "Pending data size: %d\n", pending.size());
+std::list<PendingData>::iterator it(pending.begin());
+while (it != pending.end())
+    {
+    std::vector<AliveData>::iterator uit(
+            std::lower_bound(
+                users.begin(),
+                users.end(),
+                it->login)
+            );
+    if (it->type == PendingData::CONNECT)
+        {
+        if (uit == users.end() || uit->login != it->login)
+            {
+            // Add new user
+            Connect(*it);
+            users.insert(uit, AliveData(static_cast<UserData>(*it)));
+            }
+        else if (uit->login == it->login)
+            {
+            // Update already existing user
+            time(&uit->lastAlive);
+            uit->params = it->params;
+            }
+        }
+    else if (it->type == PendingData::ALIVE)
+        {
+        if (uit != users.end() && uit->login == it->login)
+            {
+            // Update existing user
+            time(&uit->lastAlive);
+            }
+        }
+    else if (it->type == PendingData::DISCONNECT)
+        {
+        if (uit != users.end() && uit->login == it->login.c_str())
+            {
+            // Disconnect existing user
+            Disconnect(*uit);
+            users.erase(uit);
+            }
+        }
+
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    pending.erase(it++);
+    }
+}
+//-----------------------------------------------------------------------------
+void LISTENER::ProcessTimeouts()
+{
+const std::vector<AliveData>::iterator it(
+        std::stable_partition(
+            users.begin(),
+            users.end(),
+            IsNotTimedOut(userTimeout)
+        )
+    );
+
+if (it != users.end())
+    {
+    printfd(__FILE__, "Total users: %d, users to disconnect: %d\n", users.size(), std::distance(it, users.end()));
+
+    std::for_each(
+            it,
+            users.end(),
+            DisconnectUser(*this)
+        );
+
+    users.erase(it, users.end());
+    }
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Connect(const UserData & data) const
+{
+printfd(__FILE__, "Connect %s\n", data.login.c_str());
+if (access(scriptOnConnect.c_str(), X_OK) == 0)
+    {
+    if (ScriptExec(scriptOnConnect + " " + data.params))
+        {
+        WriteServLog("Script %s cannot be executed for an unknown reason.", scriptOnConnect.c_str());
+        return true;
+        }
+    }
+else
+    {
+    WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
+    return true;
+    }
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::Disconnect(const UserData & data) const
+{
+printfd(__FILE__, "Disconnect %s\n", data.login.c_str());
+if (access(scriptOnDisconnect.c_str(), X_OK) == 0)
+    {
+    if (ScriptExec(scriptOnDisconnect + " " + data.params))
+        {
+        WriteServLog("Script %s cannot be executed for an unknown reson.", scriptOnDisconnect.c_str());
+        return true;
+        }
+    }
+else
+    {
+    WriteServLog("Script %s cannot be executed. File not found.", scriptOnDisconnect.c_str());
+    return true;
+    }
+return false;
+}
+//-----------------------------------------------------------------------------
+void LISTENER::InitEncrypt(BLOWFISH_CTX * ctx, const string & password)
+{
+unsigned char keyL[PASSWD_LEN];
+memset(keyL, 0, PASSWD_LEN);
+strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+}
+//-----------------------------------------------------------------------------
+void LISTENER::Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
+{
+if (dst != src)
+    memcpy(dst, src, len8 * 8);
+
+for (int i = 0; i < len8; i++)
+    Blowfish_Decrypt(ctx, (uint32_t *)(dst + i * 8), (uint32_t *)(dst + i * 8 + 4));
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::CheckHeader(const RS_PACKET_HEADER & header) const
+{
+if (strncmp((char *)header.magic, RS_ID, RS_MAGIC_LEN))
+    {
+    return true;
+    }
+if (strncmp((char *)header.protoVer, "02", RS_PROTO_VER_LEN))
+    {
+    return true;
+    }
+return false;
+}
+//-----------------------------------------------------------------------------
+bool LISTENER::WaitPackets(int sd) const
+{
+fd_set rfds;
+FD_ZERO(&rfds);
+FD_SET(sd, &rfds);
+
+struct timeval tv;
+tv.tv_sec = 0;
+tv.tv_usec = 500000;
+
+int res = select(sd + 1, &rfds, NULL, NULL, &tv);
+if (res == -1) // Error
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
+        }
+    return false;
+    }
+
+if (res == 0) // Timeout
+    {
+    return false;
+    }
+
+return true;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/rscriptd/listener.h b/projects/rscriptd/listener.h
new file mode 100644 (file)
index 0000000..4a012c7
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+#include <pthread.h>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <functional>
+
+#include "os_int.h"
+#include "blowfish.h"
+#include "rs_packets.h"
+#include "stg_logger.h"
+
+struct UserData
+{
+    std::string params;
+    std::string login;
+    uint32_t    ip;
+    uint32_t    id;
+};
+
+struct PendingData : public UserData
+{
+    enum {CONNECT, ALIVE, DISCONNECT} type;
+};
+
+struct AliveData : public UserData
+{
+    explicit AliveData(const UserData & data)
+        : UserData(data),
+          lastAlive(time(NULL))
+    {};
+    bool operator<(const std::string & rvalue) const { return login < rvalue; };
+    time_t      lastAlive;
+};
+
+class IsNotTimedOut : public std::unary_function<const AliveData &, bool> {
+    public:
+        IsNotTimedOut(double to) : timeout(to), now(time(NULL)) {}
+        bool operator()(const AliveData & data) const
+        {
+            return difftime(now, data.lastAlive) < timeout;
+        }
+    private:
+        double timeout;
+        time_t now;
+};
+
+class LISTENER
+{
+public:
+                        LISTENER();
+                        ~LISTENER(){};
+
+    void                SetPort(uint16_t p) { port = p; };
+    void                SetPassword(const std::string & p);
+    void                SetUserTimeout(int t) { userTimeout = t; };
+    void                SetScriptOnConnect(const std::string & script) { scriptOnConnect = script; };
+    void                SetScriptOnDisconnect(const std::string & script) { scriptOnDisconnect = script; };
+
+    bool                Start();
+    bool                Stop();
+    bool                IsRunning() const { return !receiverStopped && !processorStopped; };
+
+    const std::string & GetStrError() const { return errorStr; };
+    const std::string & GetVersion() const { return version; };
+
+private:
+    // Threading stuff
+    static void *       Run(void * self);
+    static void *       RunProcessor(void * self);
+    void                Runner();
+    void                ProcessorRunner();
+    // Networking stuff
+    bool                PrepareNet();
+    bool                FinalizeNet();
+    bool                WaitPackets(int sd) const;
+    bool                RecvPacket();
+    // Parsing stuff
+    bool                CheckHeader(const RS_PACKET_HEADER & header) const;
+    bool                GetParams(char * buffer, UserData & data);
+    // Processing stuff
+    void                ProcessPending();
+    void                ProcessTimeouts();
+    bool                Disconnect(const UserData & data) const;
+    bool                Connect(const UserData & data) const;
+    // Decryption stuff
+    void                InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password);
+    void                Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
+
+    BLOWFISH_CTX        ctxS;
+    STG_LOGGER &        WriteServLog;
+
+    mutable std::string errorStr;
+    std::string         scriptOnConnect;
+    std::string         scriptOnDisconnect;
+    std::string         password;
+    uint16_t            port;
+
+    bool                running;
+    bool                receiverStopped;
+    bool                processorStopped;
+    std::vector<AliveData> users;
+    std::list<PendingData> pending;
+    int                 userTimeout;
+
+    pthread_t           receiverThread;
+    pthread_t           processorThread;
+    pthread_mutex_t     mutex;
+
+    int                 listenSocket;
+
+    std::string         version;
+
+    friend class DisconnectUser;
+};
+
+class DisconnectUser : public std::unary_function<const UserData &, void> {
+    public:
+        DisconnectUser(LISTENER & l) : listener(l) {};
+        void operator()(const UserData & data)
+        {
+            listener.Disconnect(data);
+        };
+    private:
+        LISTENER & listener;
+};
+//-----------------------------------------------------------------------------
diff --git a/projects/rscriptd/main.cpp b/projects/rscriptd/main.cpp
new file mode 100644 (file)
index 0000000..4c53c2c
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.19 $
+ $Author: faust $
+ $Date: 2010/09/10 06:37:45 $
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h> // creat
+#include <unistd.h>
+
+#include <cstdlib>
+#include <csignal>
+#include <set>
+
+#include "common.h"
+#include "stg_logger.h"
+#include "script_executer.h"
+#include "conffiles.h"
+#include "listener.h"
+#include "pidfile.h"
+#include "version.h"
+
+using namespace std;
+
+#ifdef DEBUG
+# define MAIN_DEBUG  1
+# define NO_DAEMON    1
+#endif
+
+#define START_FILE "/._ST_ART_ED_"
+
+static bool childExited = false;
+set<pid_t> executersPid;
+static pid_t stgChildPid;
+volatile time_t stgTime = time(NULL);
+
+class STG_STOPPER
+{
+public:
+    STG_STOPPER() { nonstop = true; }
+    bool GetStatus() const { return nonstop; };
+    void Stop(const char * __file__, int __line__)
+        {
+        #ifdef NO_DAEMON
+        printfd(__FILE__, "rscriptd stopped at %s:%d\n", __file__, __line__);
+        #endif
+        nonstop = false;
+        }
+private:
+    bool nonstop;
+};
+//-----------------------------------------------------------------------------
+STG_STOPPER nonstop;
+//-----------------------------------------------------------------------------
+void CatchPROF(int)
+{
+}
+//-----------------------------------------------------------------------------
+void CatchUSR1(int)
+{
+}
+//-----------------------------------------------------------------------------
+void CatchTERM(int sig)
+{
+/*
+ *Function Name:CatchINT
+ *Parameters: sig_num - signal number
+ *Description: INT signal handler
+ *Returns: Nothing
+ */
+STG_LOGGER & WriteServLog = GetStgLogger();
+WriteServLog("Shutting down... %d", sig);
+
+nonstop.Stop(__FILE__, __LINE__);
+
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+}
+//-----------------------------------------------------------------------------
+void CatchPIPE(int)
+{
+STG_LOGGER & WriteServLog = GetStgLogger();
+WriteServLog("Broken pipe!");
+}
+//-----------------------------------------------------------------------------
+void CatchHUP(int)
+{
+}
+//-----------------------------------------------------------------------------
+void CatchCHLD(int)
+{
+int status;
+pid_t childPid;
+childPid = waitpid(-1, &status, WNOHANG);
+
+set<pid_t>::iterator pid;
+pid = executersPid.find(childPid);
+if (pid != executersPid.end())
+    {
+    executersPid.erase(pid);
+    }
+if (childPid == stgChildPid)
+    {
+    childExited = true;
+    }
+}
+//-----------------------------------------------------------------------------
+void SetSignalHandlers()
+{
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR1);
+newsa.sa_handler = CatchUSR1;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR1, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGPIPE);
+newsa.sa_handler = CatchPIPE;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGPIPE, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGHUP);
+newsa.sa_handler = CatchHUP;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGHUP, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGCHLD);
+newsa.sa_handler = CatchCHLD;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGCHLD, &newsa, &oldsa);
+}
+//-----------------------------------------------------------------------------
+int StartScriptExecuter(char * procName, int msgKey, int * msgID)
+{
+STG_LOGGER & WriteServLog = GetStgLogger();
+
+if (*msgID == -11)   // If msgID == -11 - first call. Create queue
+    {
+    for (int i = 0; i < 2; i++)
+        {
+        *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
+
+        if (*msgID == -1)
+            {
+            *msgID = msgget(msgKey, 0);
+            if (*msgID == -1)
+                {
+                WriteServLog("Message queue not created.");
+                return -1;
+                }
+            else
+                {
+                msgctl(*msgID, IPC_RMID, NULL);
+                }
+            }
+        else
+            {
+            WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
+            break;
+            }
+        }
+    }
+
+pid_t executerPid = fork();
+
+switch (executerPid)
+    {
+    case -1:    // Failure
+        WriteServLog("Fork error!");
+        return -1;
+
+    case 0:     // Child
+        //close(0);
+        //close(1);
+        //close(2);
+        //setsid();
+        Executer(msgKey, *msgID, executerPid, procName);
+        return 1;
+
+    default:    // Parent
+        if (executersPid.empty())
+            Executer(msgKey, *msgID, executerPid, NULL);
+        executersPid.insert(executerPid);
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+#ifdef NO_DAEMON
+int ForkAndWait(const string &)
+#else
+int ForkAndWait(const string & confDir)
+#endif
+{
+#ifndef NO_DAEMON
+stgChildPid = fork();
+string startFile = confDir + START_FILE;
+unlink(startFile.c_str());
+
+switch (stgChildPid)
+    {
+    case -1:    // Failure
+        return -1;
+        break;
+
+    case 0:     // Child
+        //close(0);
+        close(1);
+        close(2);
+        setsid();
+        break;
+
+    default:    // Parent
+        for (int i = 0; i < 120 * 5; i++)
+            {
+            if (access(startFile.c_str(), F_OK) == 0)
+                {
+                //printf("Fork successfull. Exit.\n");
+                unlink(startFile.c_str());
+                exit(0);
+                }
+
+            if (childExited)
+                {
+                unlink(startFile.c_str());
+                exit(1);
+                }
+            usleep(200000);
+            }
+        unlink(startFile.c_str());
+        exit(1);
+        break;
+    }
+#endif
+return 0;
+}
+//-----------------------------------------------------------------------------
+void KillExecuters()
+{
+set<pid_t>::iterator pid;
+pid = executersPid.begin();
+while (pid != executersPid.end())
+    {
+    printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
+    kill(*pid, SIGUSR1);
+    ++pid;
+    }
+}
+//-----------------------------------------------------------------------------
+int main(int argc, char * argv[])
+{
+
+/*
+  Initialization order:
+  - Logger
+  - Config
+  - Set signal nandlers
+  - Fork and exit
+ */
+
+CONFIGFILE * cfg = NULL;
+LISTENER * listener = NULL;
+int msgID = -11;
+int execNum = 0;
+int execMsgKey = 0;
+
+string logFileName;
+string confDir;
+string password;
+string onConnect;
+string onDisconnect;
+int port;
+int userTimeout;
+
+if (getuid())
+    {
+    printf("You must be root. Exit.\n");
+    exit(1);
+    }
+
+if (argc == 2)
+    cfg = new CONFIGFILE(argv[1]);
+else
+    cfg = new CONFIGFILE("/etc/rscriptd/rscriptd.conf");
+
+if (cfg->Error())
+    {
+    STG_LOGGER & WriteServLog = GetStgLogger();
+    WriteServLog.SetLogFileName("/var/log/rscriptd.log");
+    WriteServLog("Error reading config file!");
+    delete cfg;
+    return EXIT_FAILURE;
+    }
+
+cfg->ReadString("LogFileName", &logFileName, "/var/log/rscriptd.log");
+cfg->ReadInt("ExecutersNum", &execNum, 1);
+cfg->ReadInt("ExecMsgKey", &execMsgKey, 5555);
+cfg->ReadString("ConfigDir", &confDir, "/etc/rscriptd");
+cfg->ReadString("Password", &password, "");
+cfg->ReadInt("Port", &port, 5555);
+cfg->ReadInt("UserTimeout", &userTimeout, 60);
+cfg->ReadString("ScriptOnConnect", &onConnect, "/etc/rscriptd/OnConnect");
+cfg->ReadString("ScriptOnDisconnect", &onDisconnect, "/etc/rscriptd/OnDisconnect");
+
+SetSignalHandlers();
+if (ForkAndWait(confDir) < 0)
+    {
+    STG_LOGGER & WriteServLog = GetStgLogger();
+    WriteServLog("Fork error!");
+    delete cfg;
+    return EXIT_FAILURE;
+    }
+
+STG_LOGGER & WriteServLog = GetStgLogger();
+PIDFile pidFile("/var/run/rscriptd.pid");
+WriteServLog.SetLogFileName(logFileName);
+WriteServLog("rscriptd v. %s", SERVER_VERSION);
+
+for (int i = 0; i < execNum; i++)
+    {
+    int ret = StartScriptExecuter(argv[0], execMsgKey, &msgID);
+    if (ret < 0)
+        {
+        STG_LOGGER & WriteServLog = GetStgLogger();
+        WriteServLog("Start Script Executer error!");
+        delete cfg;
+        return EXIT_FAILURE;
+        }
+    if (ret == 1)
+        {
+        delete cfg;
+        return EXIT_SUCCESS;
+        }
+    }
+
+listener = new LISTENER();
+listener->SetPort(port);
+listener->SetPassword(password);
+listener->SetUserTimeout(userTimeout);
+listener->SetScriptOnConnect(onConnect);
+listener->SetScriptOnDisconnect(onDisconnect);
+
+listener->Start();
+
+WriteServLog("rscriptd started successfully.");
+WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+#ifndef NO_DAEMON
+string startFile(confDir + START_FILE);
+creat(startFile.c_str(), S_IRUSR);
+#endif
+
+while (nonstop.GetStatus())
+    {
+    usleep(100000);
+    }
+
+listener->Stop();
+
+WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+int res = msgctl(msgID, IPC_RMID, NULL);
+if (res)
+    WriteServLog("Queue was not removed. id=%d", msgID);
+else
+    WriteServLog("Queue removed successfully.");
+
+KillExecuters();
+
+WriteServLog("rscriptd stopped successfully.");
+WriteServLog("---------------------------------------------");
+
+delete listener;
+delete cfg;
+return EXIT_SUCCESS;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/rscriptd/pidfile.cpp b/projects/rscriptd/pidfile.cpp
new file mode 100644 (file)
index 0000000..5f3f497
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.1 $
+ $Date: 2010/02/11 12:32:25 $
+ $Author: faust $
+ */
+
+/*
+ *  An implementation of RAII pid-file writer
+ */
+
+#include <fstream>
+#include <unistd.h>
+
+#include "pidfile.h"
+
+PIDFile::PIDFile(const std::string & fn)
+    : fileName(fn)
+{
+if (fileName != "")
+    {
+    std::ofstream pf(fileName.c_str());
+    pf << getpid() << std::endl;
+    pf.close();
+    }
+}
+
+PIDFile::~PIDFile()
+{
+if (fileName != "")
+    {
+    unlink(fileName.c_str());
+    }
+}
diff --git a/projects/rscriptd/pidfile.h b/projects/rscriptd/pidfile.h
new file mode 100644 (file)
index 0000000..a8a7bb3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Header file for RAII pid-file writer
+ */
+
+/*
+ $Revision: 1.1 $
+ $Date: 2010/02/11 12:32:25 $
+ $Author: faust $
+ */
+
+#ifndef __PID_FILE_H__
+#define __PID_FILE_H__
+
+#include <string>
+
+class PIDFile {
+public:
+    PIDFile(const std::string & fn);
+    ~PIDFile();
+private:
+    std::string fileName;
+};
+
+#endif
diff --git a/projects/rscriptd/rscriptd.conf b/projects/rscriptd/rscriptd.conf
new file mode 100644 (file)
index 0000000..d668d46
--- /dev/null
@@ -0,0 +1,8 @@
+LogFileName=/var/log/rscriptd.log
+ExecutersNum=1
+ConfigDir=/etc/rscriptd
+Password=123456
+Port=9999
+UserTimeout=60
+ScriptOnConnect=/etc/rscriptd/OnConnect
+ScriptOnDisconnect=/etc/rscriptd/OnDisconnect
diff --git a/projects/sgauth/Makefile b/projects/sgauth/Makefile
new file mode 100644 (file)
index 0000000..47488cc
--- /dev/null
@@ -0,0 +1,97 @@
+###############################################################################
+# $Id: Makefile,v 1.18 2009/08/06 12:50:55 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = sgauth
+
+SRCS = ./main.cpp \
+       ./web.cpp
+
+STGLIBS =  -lconffiles \
+           -lstg_crypto \
+           -lstg_common \
+           -lia_auth_c \
+           -lcommon_settings
+
+LIBS += $(LIB_THREAD) \
+       -lexpat
+
+ifeq ($(OS),linux)
+LIBS += -ldl
+else
+LIBS += -lintl \
+        -lc
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS += -Wall
+LDFLAGS += -Wl,-E -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-rpath-link,$(DIR_LIB)
+
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs install uninstall install-bin install-data uninstall-bin uninstall-data
+all: libs $(PROG) ../../Makefile.conf
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+$(PROG): $(OBJS) $(STGLIBS) 
+       $(CC) $^ $(LDFLAGS) -o $(PROG) $(LIBS)
+
+clean:
+       rm -f deps $(PROG) *.o tags *.*~ .OS
+       rm -f .OS
+       rm -f .store
+       rm -f .db.sql
+       rm -f core*
+       rm -f css.h
+       $(MAKE) -C $(DIR_LIBSRC) clean
+
+distclean: clean
+       rm -f ../../Makefile.conf
+
+install: install-bin install-data
+
+install-bin:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/sbin
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) install
+
+install-data:
+       # Install etc
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/etc
+       install -m $(DATA_MODE) -o $(OWNER) ./sgauth.conf $(PREFIX)/etc/sgauth.conf
+
+uninstall: uninstall-bin uninstall-data
+
+uninstall-bin:
+       rm -f $(PREFIX)/usr/sbin/$(PROG)
+
+uninstall-data:
+       # Uninstall etc
+       rm -f $(PREFIX)/etc/stargazer/sgauth.conf
+
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf sgauth.css
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       ./make_css.sh
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/sgauth/build b/projects/sgauth/build
new file mode 100755 (executable)
index 0000000..e61b957
--- /dev/null
@@ -0,0 +1,142 @@
+#!/bin/sh
+
+#   $Author: faust $
+#   $Revision: 1.24 $
+#   $Date: 2010/04/14 08:59:02 $
+######################################################
+
+OS=unknown
+sys=`uname -s`
+release=`uname -r | cut -b1`
+BUILD_DIR=`pwd`
+CONFFILE="../../Makefile.conf"
+PREFIX="/"
+BIN_MODE=0755
+DATA_MODE=0644
+OWNER=root
+
+if [ -z $1 ]
+then
+    MAKEOPTS="-j1"
+else
+    if [ "$1" = "debug" ]
+    then
+        DEFS="-DDEBUG"
+        MAKEOPTS="-j1"
+        CXXFLAGS="$CXXFLAGS -g3 -W -Wall"
+    else
+        MAKEOPTS="-j1"
+    fi
+fi
+
+CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+LDFLAGS="$CXXFLAGS -L/usr/local/lib"
+
+if [ "$sys" = "Linux" ]
+then
+    OS=linux
+    release=""
+    MAKE="make"
+fi
+
+if [ "$sys" = "FreeBSD" ]
+then
+    case $release in
+        4) OS=bsd;;
+        5) OS=bsd5;;
+        6) OS=bsd5;;
+        7) OS=bsd7;;
+        8) OS=bsd7;;
+        *) OS=unknown;;
+    esac
+    MAKE="gmake"
+fi
+
+if [ "$OS" = "unknown" ]
+then 
+    echo "#############################################################################"
+    echo "# Sorry, but sgauth currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #"
+    echo "#############################################################################"
+    exit 1
+fi
+
+echo "#############################################################################"
+echo "       Building sgauth for $sys $release"
+echo "#############################################################################"
+
+STG_LIBS="crypto.lib 
+         common.lib 
+         common_settings.lib
+         conffiles.lib
+         ia_auth_c.lib"
+
+if [ "$OS" = "linux" ]
+then
+    DEFS="$DEFS -DLINUX"
+    LIB_THREAD=-lpthread
+    SHELL="/bin/bash"
+else
+    if [ "$OS" = "bsd" ]
+    then
+        DEFS="$DEFS -DFREE_BSD"
+        LIB_THREAD=-lc_r
+    else
+        DEFS="$DEFS -DFREE_BSD5"
+        if [ "$OS" = "bsd7" ]
+        then
+            LIB_THREAD=-lpthread
+        else
+            LIB_THREAD=-lc_r
+        fi
+    fi
+    SHELL="/usr/local/bin/bash"
+fi
+
+echo -n "Checking endianess... "
+echo "int main() { int probe = 0x00000001; return *(char *)&probe; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    echo "FAIL!"
+    echo "Endianess checking failed"
+    exit;
+else
+    ./fake
+    if [ $? = 1 ]
+    then
+        ARCH=le
+        CXXFLAGS="$CXXFLAGS -DARCH_LE"
+        echo "Little Endian"
+    else
+        ARCH=be
+        CXXFLAGS="$CXXFLAGS -DARCH_BE"
+        echo "Big Endian"
+    fi
+fi
+rm -f fake
+rm -f build_check.c
+
+echo "OS=$OS" > $CONFFILE
+echo "STG_TIME=yes" >> $CONFFILE
+echo "DIR_BUILD=$BUILD_DIR" >> $CONFFILE
+echo "DIR_LIB=\$(DIR_BUILD)/../../lib" >> $CONFFILE
+echo "DIR_LIBSRC=\$(DIR_BUILD)/../../stglibs" >> $CONFFILE
+echo "DIR_INCLUDE=\$(DIR_BUILD)/../../include" >> $CONFFILE
+echo "ARCH=$ARCH" >> $CONFFILE
+echo "DEFS=$DEFS" >> $CONFFILE
+echo -n "STG_LIBS=" >> $CONFFILE
+for lib in $STG_LIBS
+do
+    echo -n "$lib " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo "LIB_THREAD=$LIB_THREAD" >> $CONFFILE
+echo "SHELL=$SHELL" >> $CONFFILE
+echo "CXXFLAGS=$CXXFLAGS" >> $CONFFILE
+echo "LDFLAGS=$LDFLAGS" >> $CONFFILE
+echo "PREFIX=$PREFIX" >> $CONFFILE
+echo "BIN_MODE=$BIN_MODE" >> $CONFFILE
+echo "DATA_MODE=$DATA_MODE" >> $CONFFILE
+echo "OWNER=$OWNER" >> $CONFFILE
+$MAKE $MAKEOPTS
+
diff --git a/projects/sgauth/main.cpp b/projects/sgauth/main.cpp
new file mode 100644 (file)
index 0000000..1aae7aa
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.13 $
+ $Date: 2010/04/14 09:01:29 $
+ $Author: faust $
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include "conffiles.h"
+#endif
+
+#include <string.h>
+#include <vector>
+#include <iostream>
+
+#include "ia_auth_c.h"
+#include "common.h"
+#include "common_settings.h"
+#include "web.h"
+
+int mes;
+char infoText[256];
+char messageText[256];
+
+const int winKOI = 0;
+
+IA_CLIENT_PROT * clnp;
+WEB * web = NULL;
+
+using namespace std;
+
+time_t stgTime;
+
+//-----------------------------------------------------------------------------
+class SETTINGS: public COMMON_SETTINGS
+{
+public:
+                    SETTINGS();
+    virtual         ~SETTINGS(){};
+    virtual int     Reload(){ return 0; };
+    void            SetConfFile(string confFile);
+    virtual int     ReadSettings();
+
+    virtual string  GetStrError() const;
+
+    string          GetServerName() const;
+    uint16_t        GetServerPort() const;
+    uint16_t        GetLocalPort() const;
+
+    string          GetLogin() const;
+    string          GetPassword() const;
+
+    bool            GetDaemon() const;
+    bool            GetShowPid() const;
+    bool            GetNoWeb() const;
+    bool            GetReconnect() const;
+    int             GetRefreshPeriod() const;
+    uint32_t        GetListenWebIP() const;
+
+    void            Print() const;
+
+private:
+    string          login;
+    string          password;
+    string          serverName;
+    int             port;
+    int             localPort;
+    uint32_t        listenWebIP;
+    int             refreshPeriod;
+
+    bool            daemon;
+    bool            noWeb;
+    bool            reconnect;
+    bool            showPid;
+
+    string          confFile;
+};
+//-----------------------------------------------------------------------------
+SETTINGS::SETTINGS()
+{
+confFile = "/etc/sgauth.conf";
+}
+//-----------------------------------------------------------------------------
+void SETTINGS::SetConfFile(string confFile)
+{
+SETTINGS::confFile = confFile;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ReadSettings()
+{
+CONFIGFILE * cf;
+
+cf = new CONFIGFILE(confFile);
+string tmp;
+int e = cf->Error();
+
+if (e)
+    {
+    printf("Cannot read file.\n");
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("Login", &login, "/?--?--?*");
+if (login == "/?--?--?*")
+    {
+    strError = "Parameter \'Login\' not found.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("Password", &password, "/?--?--?*");
+if (login == "/?--?--?*")
+    {
+    strError = "Parameter \'Password\' not found.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("ServerName", &serverName, "?*?*?");
+if (serverName == "?*?*?")
+    {
+    strError = "Parameter \'ServerName\' not found.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("ListenWebIP", &tmp, "127.0.0.1");
+listenWebIP = inet_addr(tmp.c_str());
+if (listenWebIP == INADDR_NONE)
+    {
+    strError = "Parameter \'ListenWebIP\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("ServerPort", &tmp, "5555");
+if (ParseIntInRange(tmp, 1, 65535, &port))
+    {
+    strError = "Parameter \'ServerPort\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("LocalPort", &tmp, "0");
+if (ParseIntInRange(tmp, 0, 65535, &localPort))
+    {
+    strError = "Parameter \'LocalPort\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+printf("LocalPort=%d\n", localPort);
+
+cf->ReadString("RefreshPeriod", &tmp, "5");
+if (ParseIntInRange(tmp, 1, 24*3600, &refreshPeriod))
+    {
+    strError = "Parameter \'RefreshPeriod\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("Reconnect", &tmp, "yes");
+if (ParseYesNo(tmp, &reconnect))
+    {
+    strError = "Parameter \'Reconnect\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("Daemon", &tmp, "yes");
+if (ParseYesNo(tmp, &daemon))
+    {
+    strError = "Parameter \'Daemon\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("ShowPid", &tmp, "no");
+if (ParseYesNo(tmp, &showPid))
+    {
+    strError = "Parameter \'ShowPid\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+cf->ReadString("DisableWeb", &tmp, "no");
+if (ParseYesNo(tmp, &noWeb))
+    {
+    strError = "Parameter \'DisableWeb\' is not valid.";
+    delete cf;
+    return -1;
+    }
+
+delete cf;
+return 0;
+}
+//-----------------------------------------------------------------------------
+string SETTINGS::GetStrError() const
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+string SETTINGS::GetLogin() const
+{
+return login;
+}
+//-----------------------------------------------------------------------------
+string SETTINGS::GetPassword() const
+{
+return password;
+}
+//-----------------------------------------------------------------------------
+string SETTINGS::GetServerName() const
+{
+return serverName;
+}
+//-----------------------------------------------------------------------------
+uint16_t SETTINGS::GetServerPort() const
+{
+return port;
+}
+//-----------------------------------------------------------------------------
+uint16_t SETTINGS::GetLocalPort() const
+{
+return localPort;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::GetRefreshPeriod() const
+{
+return refreshPeriod;
+}
+//-----------------------------------------------------------------------------
+bool SETTINGS::GetDaemon() const
+{
+return daemon;
+}
+//-----------------------------------------------------------------------------
+bool SETTINGS::GetNoWeb() const
+{
+return noWeb;
+}
+//-----------------------------------------------------------------------------
+bool SETTINGS::GetShowPid() const
+{
+return showPid;
+}
+//-----------------------------------------------------------------------------
+bool SETTINGS::GetReconnect() const
+{
+return reconnect;
+}
+//-----------------------------------------------------------------------------
+uint32_t SETTINGS::GetListenWebIP() const
+{
+return listenWebIP;
+}
+//-----------------------------------------------------------------------------
+void SETTINGS::Print() const
+{
+cout << "login = " << login << endl;
+cout << "password = " << password << endl;
+cout << "ip = " << serverName << endl;
+cout << "port = " << port << endl;
+cout << "localPort = " << localPort << endl;
+cout << "listenWebIP = " << inet_ntostring(listenWebIP) << endl;
+cout << "DisableWeb = " << noWeb << endl;
+cout << "refreshPeriod = " << refreshPeriod << endl;
+cout << "daemon = " << daemon << endl;
+cout << "reconnect = " << reconnect << endl;
+}
+//-----------------------------------------------------------------------------
+void Usage()
+{
+printf("sgauth <server> <port> <login> <password>\n"); //TODO change to correct
+}
+//-----------------------------------------------------------------------------
+void EventsFn(int)
+{
+LOADSTAT ls;
+clnp->GetStat(&ls);
+}
+//-----------------------------------------------------------------------------
+void SetDirName(const vector<string> & dn, void *)
+{
+for (int j = 0; j < DIR_NUM; j++)
+    {
+    if (winKOI)
+        {
+        string dir;
+        KOIToWin(dn[j], &dir);
+        if (web)
+            web->SetDirName(dir, j);
+        }
+    else
+        {
+        if (web)
+            web->SetDirName(dn[j], j);
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void StatUpdate(const LOADSTAT & ls, void *)
+{
+if (web)
+    web->UpdateStat(ls);
+}
+//-----------------------------------------------------------------------------
+void StatusChanged(int, void *)
+{
+
+}
+//-----------------------------------------------------------------------------
+void ShowMessage(const string & message, int i, int, int, void *)
+{
+if (web)
+    web->AddMessage(message, i);
+}
+//-----------------------------------------------------------------------------
+void ShowError(const string & message, int, void *)
+{
+if (web)
+     web->AddMessage(message, 0);
+}
+//-----------------------------------------------------------------------------
+#ifndef WIN32
+void CatchUSR1(int)
+{
+if (clnp->GetAuthorized())
+    {
+    cout << "Connect" << endl;
+    clnp->Connect();
+       }
+}
+//-----------------------------------------------------------------------------
+void CatchUSR2(int)
+{
+cout << "Disconnect" << endl;
+clnp->Disconnect();
+}
+//-----------------------------------------------------------------------------
+void CatchTERM(int)
+{
+cout << "Terminated" << endl;
+clnp->Disconnect();
+sleep(2);
+exit(0);
+}
+//-----------------------------------------------------------------------------
+static void SetSignalHandlers()
+{
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR1);
+newsa.sa_handler = CatchUSR1;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR1, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR2);
+newsa.sa_handler = CatchUSR2;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR2, &newsa, &oldsa);
+
+return;
+}
+#endif
+//-----------------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+//int port;
+//char *endptr;
+
+SETTINGS settings;
+
+#ifndef WIN32
+if (argc == 2)
+#else
+if(0)
+#endif
+    {
+    settings.SetConfFile(argv[1]);
+    if (settings.ReadSettings())
+        {
+        printf("ReadSettingsError\n");
+        printf("%s\n", settings.GetStrError().c_str());
+        exit(-1);
+        }
+    settings.Print();
+    }
+else
+    {
+    /*if (argc != 5)
+        {
+        Usage();
+        exit(1);
+        }
+    else
+        {
+        string serverName(argv[1]);
+        port = strtol(argv[2], &endptr, 10);
+        if (*endptr != 0)
+            {
+            printf("Invalid port!\n");
+            exit(1);
+            }
+        login = argv[3];
+        passwd = argv[4];
+        }*/
+    }
+
+//settings.Print();
+
+#ifndef WIN32
+if (settings.GetDaemon())
+    {
+    /*close(0);
+    close(1);
+    close(2);*/
+
+    switch (fork())
+        {
+        case -1:    // ìÁÖÁ
+            exit(1);
+            break;
+
+        case 0:    // ðÏÔÏÍÏË
+            setsid();
+            break;
+
+        default:    // ïÓÎÏ×ÎÏÊ ÐÒÏÃÅÓÓ
+            exit(0);
+            break;
+        }
+    }
+
+
+
+#endif
+
+clnp = new IA_CLIENT_PROT(settings.GetServerName(), settings.GetServerPort(), settings.GetLocalPort());
+
+if (!settings.GetNoWeb())
+    {
+    web = new WEB();
+    web->SetRefreshPagePeriod(settings.GetRefreshPeriod());
+    web->SetListenAddr(settings.GetListenWebIP());
+    web->Start();
+    }
+
+clnp->SetLogin(settings.GetLogin());
+clnp->SetPassword(settings.GetPassword());
+
+clnp->SetStatusChangedCb(StatusChanged, NULL);
+clnp->SetInfoCb(ShowMessage, NULL);
+clnp->SetErrorCb(ShowError, NULL);
+clnp->SetDirNameCb(SetDirName, NULL);
+clnp->SetStatChangedCb(StatUpdate, NULL);
+clnp->SetReconnect(settings.GetReconnect());
+
+
+clnp->Start();
+
+SetSignalHandlers();
+
+#ifdef LINUX
+for (int i = 1; i < argc; i++)
+    memset(argv[i], 0, strlen(argv[i]));
+
+if(argc > 1)
+    strcpy(argv[1], "Connecting...");
+#endif
+
+#ifdef FREEBSD
+setproctitle("Connecting...");
+#endif
+clnp->Connect();
+
+while (1)
+    {
+    #ifdef WIN32
+    Sleep(200);
+    #else
+    usleep(200000);
+    #endif
+
+    char state[20];
+
+    if (clnp->GetAuthorized())
+        {
+        if (settings.GetShowPid())
+            sprintf(state, "On %d", getpid());
+        else
+            strcpy(state, "Online");
+        }
+    else
+        {
+        if (settings.GetShowPid())
+            sprintf(state, "Off %d", getpid());
+        else
+            strcpy(state, "Offline");
+        }
+
+    #ifdef LINUX
+    for (int i = 1; i < argc; i++)
+        memset(argv[i], 0, strlen(argv[i]));
+    if(argc > 1)
+        strcpy(argv[1], state);
+    #endif
+
+    #ifdef FREEBSD
+    setproctitle(state);
+    #endif
+
+    #ifdef FREEBSD_5
+    setproctitle(state);
+    #endif
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/sgauth/make_css.sh b/projects/sgauth/make_css.sh
new file mode 100755 (executable)
index 0000000..b4de011
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+OUT_FILE=css.h
+
+
+echo "const char * css =" > $OUT_FILE
+echo "\"/*------*/\\\\n\"" >> $OUT_FILE
+sed -e 's/$/\\n"/g' -e 's/^/"/g' sgauth.css >> $OUT_FILE
+echo ";" >> $OUT_FILE
+
diff --git a/projects/sgauth/readme b/projects/sgauth/readme
new file mode 100644 (file)
index 0000000..08d510e
--- /dev/null
@@ -0,0 +1,13 @@
+äÌÑ ËÏÍÉÐÉÌÑÃÉÉ ÐÒÏÇÒÁÍÍÙ ÚÁÐÕÓÔÉÔÅ ÓËÒÉÐÔ ./build
+
+ðÒÏÇÒÁÍÍÁ ÚÁÐÕÓËÁÅÔÓÑ ÓÏ ÓÌÅÄÕÀÝÉÍÉ ÐÁÒÁÍÅÔÒÁÍÉ:
+    > sgauth <server> <port> <login> <password>
+ÉÌÉ
+    > sgauth <config_file_name>
+ÉÌÉ
+    > sgauth
+
+÷ ÐÏÓÌÅÄÎÅÍ ÓÌÕÞÁÅ ÉÓÐÏÌØÚÕÅÔÓÑ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ /etc/sgauth.conf
+
+ðÒÉ ÐÏÄËÌÀÞÅÎÉÉ ÂÒÁÕÚÅÒÏÍ ÐÏ ÁÄÒÅÓÕ http://localhost:5580
+ÍÏÖÎÏ ÐÏÓÍÏÔÒÅÔØ ÓÔÁÔÉÓÔÉËÕ.
diff --git a/projects/sgauth/sgauth.conf b/projects/sgauth/sgauth.conf
new file mode 100644 (file)
index 0000000..1b7d435
--- /dev/null
@@ -0,0 +1,37 @@
+#Stargazer server ip
+ServerName=192.168.1.2
+
+#Stargazer server port
+#Default value 5555
+ServerPort=5555
+
+#User's login
+Login=test
+
+#
+#
+LocalPort=12345
+
+#User's password
+Password=1234567
+
+#
+#Default value yes
+#Reconnect=no
+
+#
+#Default value yes
+#Daemon=yes
+
+#Refresh web page period
+#Default value 10
+#RefreshPeriod=10
+
+#
+#Default value 127.0.0.1
+ListenWebIP=0.0.0.0
+
+#Default value no
+DisableWeb=no
+
+#ShowPid=no
diff --git a/projects/sgauth/sgauth.css b/projects/sgauth/sgauth.css
new file mode 100644 (file)
index 0000000..f816dbf
--- /dev/null
@@ -0,0 +1,78 @@
+H3
+{
+color: black;
+}
+
+body
+{
+background-color: silver;
+}
+
+#TraffTable
+{
+background-color: white;
+}
+
+#TraffTableCaptionRow
+{
+background-color: silver;
+}
+
+#TraffTableCaptionCellC,
+#TraffTableUMCellC,
+#TraffTableDMCellC,
+#TraffTableUSCellC,
+#TraffTableDSCellC
+{
+background-color: silver;
+}
+
+#TraffTableDMRow,
+#TraffTableDSRow
+{
+background-color: #f2f0cc;
+}
+
+#TraffTableUMRow,
+#TraffTableUSRow
+{
+background-color: white;
+}
+
+#ConnectionStateOnline
+{
+color: green;
+font-size: 20px
+}
+
+#ConnectionStateOffline
+{
+color: red;
+font-size: 20px
+}
+
+p
+{
+padding: 2px;
+margin: 0px;
+}
+
+#MessagesTable
+{
+background-color: white;
+}
+
+#MessagesTableRowC
+{
+background-color: silver;
+}
+
+
+#MessagesTableRow0,
+#MessagesTableRow2,
+#MessagesTableRow4,
+#MessagesTableRow6,
+#MessagesTableRow8
+{
+background-color: #f2f0cc;
+}
diff --git a/projects/sgauth/web.cpp b/projects/sgauth/web.cpp
new file mode 100644 (file)
index 0000000..caec33a
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.7 $
+ $Date: 2010/03/15 12:58:17 $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <libintl.h>
+
+#include "web.h"
+#include "common.h"
+#include "ia_auth_c.h"
+
+extern WEB * web;
+extern IA_CLIENT_PROT * clnp;
+
+#define LISTEN_PORT (5580)
+
+#include "css.h"
+
+//---------------------------------------------------------------------------
+#ifndef WIN32
+void * RunWeb(void *)
+#else
+unsigned long WINAPI RunWeb(void *)
+#endif
+{
+while (1)
+    web->Run();
+return NULL;
+}
+//---------------------------------------------------------------------------
+WEB::WEB()
+    : res(0),
+      listenSocket(0),
+      outerSocket(0),
+      refreshPeriod(0),
+      listenWebAddr(0),
+      outerAddrLen(0)
+{
+#ifdef WIN32
+res = WSAStartup(MAKEWORD(2,0), &wsaData);
+#endif
+
+for (int i = 0; i < DIR_NUM; i++)
+    dirName[i] = "-";
+
+refreshPeriod = 5;
+}
+//---------------------------------------------------------------------------
+void WEB::Start()
+{
+#ifdef WIN32
+unsigned long pt;
+CreateThread(
+    NULL,   // pointer to thread security attributes
+    16384,  // initial thread stack size, in bytes
+    RunWeb, // pointer to thread function
+    NULL,   // argument for new thread
+    0,      // CREATE_SUSPENDED, // creation flags
+    &pt     // pointer to returned thread identifier
+   );
+#else
+pthread_create(&thread, NULL, RunWeb, NULL);
+#endif
+}
+//---------------------------------------------------------------------------
+void WEB::PrepareNet()
+{
+listenSocket = socket(PF_INET, SOCK_STREAM, 0);
+listenAddr.sin_family = AF_INET;
+listenAddr.sin_port = htons(LISTEN_PORT);
+listenAddr.sin_addr.s_addr = listenWebAddr;
+
+int lng = 1;
+
+#ifndef WIN32
+if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
+    {
+    printf("Setsockopt Fail\n");
+    printf(">>> Error %s\n", strerror(errno));
+    }
+#else
+//??? TODO
+#endif
+
+
+res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
+
+if (res == -1)
+    {
+    printf("Bind failed.\n");
+    exit(0);
+    }
+
+res = listen(listenSocket, 0);
+if (res == -1)
+    {
+    printf("Listen failed.\n");
+    exit(0);
+    }
+
+outerAddrLen = sizeof(outerAddr);
+}
+//---------------------------------------------------------------------------
+void WEB::SetRefreshPagePeriod(int p)
+{
+refreshPeriod = p;
+if (refreshPeriod <= 0 || refreshPeriod > 24*3600)
+    refreshPeriod = 5;
+}
+//---------------------------------------------------------------------------
+void WEB::SetListenAddr(uint32_t ip)
+{
+listenWebAddr = ip;
+}
+//---------------------------------------------------------------------------
+void WEB::Run()
+{
+PrepareNet();
+char recvBuffer[4096];
+while (1)
+    {
+    outerSocket = accept(listenSocket, (struct sockaddr*)&outerAddr, &outerAddrLen);
+    if (outerSocket == -1)
+        {
+        printf(">>> Error %s\n", strerror(errno));
+        continue;
+        }
+    recv(outerSocket, recvBuffer, sizeof(recvBuffer), 0);
+
+    if (strncmp(recvBuffer, "GET /sgauth.css", strlen("GET /sgauth.css")) == 0)
+        {
+        SendCSS();
+        //printf("(1) recvBuffer=%s\n", recvBuffer);
+        }
+    else if (strncmp(recvBuffer, "GET /disconnect", strlen("GET /disconnect")) == 0)
+        {
+        clnp->Disconnect();
+        Redirect("/");
+        //printf("(2) recvBuffer=%s\n", recvBuffer);
+        }
+    else if (strncmp(recvBuffer, "GET /connect", strlen("GET /connect")) == 0)
+        {
+        clnp->Connect();
+        Redirect("/");
+        //printf("(3) recvBuffer=%s\n", recvBuffer);
+        }
+    else if (strncmp(recvBuffer, "GET /exit", strlen("GET /exit")) == 0)
+        {
+        Redirect("/");
+        clnp->Disconnect();
+        #ifdef WIN32
+        Sleep(1000);
+        #else
+        usleep(1000000);
+        #endif
+        exit(0);
+        }
+    else
+       {
+       SendReply();
+       //printf("(4) recvBuffer=%s\n", recvBuffer);
+       }
+
+    #ifdef WIN32
+    closesocket(outerSocket);
+    #else
+    close(outerSocket);
+    #endif
+    }
+}
+//---------------------------------------------------------------------------
+int WEB::Redirect(const char * url)
+{
+const char * redirect =
+    "HTTP/1.0 200 OK\n"
+    "Content-Type: text/html\n"
+    "Connection: close"
+    "\n\n"
+    "<html>\n"
+    "<head>\n"
+    "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;%s\">\n"
+    "</head>\n"
+    "<body>\n"
+    "</body></html>\n\n";
+
+char buff[2000];
+sprintf(buff, redirect, url);
+send(outerSocket, buff, strlen(buff), 0);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int WEB::SendReply()
+{
+int j, rowNum;
+
+const char * replyHeader =
+    "HTTP/1.0 200 OK\n"
+    "Content-Type: text/html\n"
+    "Connection: close"
+    "\n\n"
+    "<html>\n"
+    "<head>\n"
+    "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">\n"
+    "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">\n"
+    "<title>sgauth</title>\n"
+    "<link rel=\"Stylesheet\" href=\"sgauth.css\">"
+    "</head>\n"
+    "<body>\n"
+    "<H3>Stargazer</H3><p>\n";
+
+const char * replyFooter = "</body></html>\n\n";
+
+char replyHeaderBuffer[2000];
+sprintf(replyHeaderBuffer, replyHeader, refreshPeriod);
+
+send(outerSocket, replyHeaderBuffer, strlen(replyHeaderBuffer), 0);
+
+char str[512];
+
+int st = clnp->GetAuthorized();
+
+sprintf(str, "<a href=\"connect\">%s</a><p>\n", gettext("Connect"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<a href=\"disconnect\">%s</a><p>\n", gettext("Disconnect"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<a href=\"/\">%s</a><p>\n", gettext("Refresh"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<a href=\"exit\">%s</a><p>\n", gettext("Exit"));
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<div id=\"%s\">%s</div><p>\n" , st ? "ConnectionStateOnline":"ConnectionStateOffline", st ? "Online":"Offline");
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<div id=\"Cash\">%s: %.3f</div><p>\n" , gettext("Cash"), ls.cash / 1000.0);
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<div id=\"Prepaid Traffic\">%s: %s</div><p>\n" ,
+        gettext("PrepaidTraffic"),
+        ls.freeMb[0] == 'C' ? ls.freeMb + 1 : ls.freeMb);
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str, "<TABLE id=\"TraffTable\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str, "    <TR id=\"TraffTableCaptionRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str, "       <TD id=\"TraffTableCaptionCellC\">&nbsp;</TD>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+    {
+    if (dirName[j][0] == 0)
+        continue;
+    string s;
+    KOIToWin(dirName[j], &s);// +++++++++ sigsegv ==========   TODO too long dir name crashes sgauth
+    sprintf(str, "       <TD id=\"TraffTableCaptionCell%d\">%s</TD>\n", rowNum++, s.c_str());
+    send(outerSocket, str, strlen(str), 0);
+    }
+
+sprintf(str,"    </TR>\n");
+send(outerSocket, str, strlen(str), 0);
+
+sprintf(str,"    <TR id=\"TraffTableUMRow\">\n");
+send(outerSocket, str, strlen(str), 0);
+
+sprintf(str,"        <TD id=\"TraffTableUMCellC\">%s</TD>\n", gettext("Month Upload"));
+send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+    {
+    if (dirName[j][0] == 0)
+        continue;
+    sprintf(str,"        <TD id=\"TraffTableUMCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.mu[j], ST_F));
+    res = send(outerSocket, str, strlen(str), 0);
+    }
+
+sprintf(str,"    </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str,"    <TR id=\"TraffTableDMRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str,"        <TD id=\"TraffTableDMCellC\">%s</TD>\n", gettext("Month Download"));
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+    {
+    if (dirName[j][0] == 0)
+        continue;
+    sprintf(str,"        <TD id=\"TraffTableDMCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.md[j], ST_F));
+    res = send(outerSocket, str, strlen(str), 0);
+    }
+sprintf(str,"    </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+
+sprintf(str,"    <TR id=\"TraffTableUSRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str,"        <TD id=\"TraffTableUSCellC\">%s</TD>\n", gettext("Session Upload"));
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+    {
+    if (dirName[j][0] == 0)
+        continue;
+    sprintf(str,"        <TD id=\"TraffTableUSCell%d\">%s</TD>\n", rowNum++, IntToKMG(ls.su[j], ST_F));
+    res = send(outerSocket, str, strlen(str), 0);
+    }
+
+sprintf(str,"    </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str,"    <TR id=\"TraffTableDSRow\">\n");
+res = send(outerSocket, str, strlen(str), 0);
+sprintf(str,"        <TD id=\"TraffTableDSCellC\">%s</TD>\n", gettext("Session Download"));
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+for (j = 0; j < DIR_NUM; j++)
+    {
+    if (dirName[j][0] == 0)
+        continue;
+    sprintf(str,"        <TD id=\"TraffTableDSCell%d\">%s</TD>\n", j, IntToKMG(ls.sd[j], ST_F));
+    res = send(outerSocket, str, strlen(str), 0);
+    }
+
+sprintf(str,"    </TR>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+sprintf(str,"</TABLE>\n");
+res = send(outerSocket, str, strlen(str), 0);
+
+rowNum = 0;
+if (!messages.empty())
+    {
+    sprintf(str,"    <TABLE id=\"MessagesTable\">\n");
+    res = send(outerSocket, str, strlen(str), 0);
+
+    sprintf(str,"        <TR id=\"MessagesTableRowC\">\n");
+    send(outerSocket, str, strlen(str), 0);
+    sprintf(str,"            <TD>Date</TD>\n");
+    send(outerSocket, str, strlen(str), 0);
+    sprintf(str,"            <TD>Text</TD>\n");
+    send(outerSocket, str, strlen(str), 0);
+    sprintf(str,"        </TR>\n");
+    send(outerSocket, str, strlen(str), 0);
+
+    list<STG_MESSAGE>::reverse_iterator it;
+    it = messages.rbegin();
+    while (it != messages.rend())
+        {
+        sprintf(str,"        <TR id=\"MessagesTableRow%d\">\n", rowNum);
+        send(outerSocket, str, strlen(str), 0);
+        sprintf(str,"            <TD>%s</TD>\n", it->recvTime.c_str());
+        send(outerSocket, str, strlen(str), 0);
+        sprintf(str,"            <TD>%s</TD>\n", it->msg.c_str());
+        send(outerSocket, str, strlen(str), 0);
+        sprintf(str,"        </TR>\n");
+        send(outerSocket, str, strlen(str), 0);
+        ++it;
+        ++rowNum;
+        }
+
+    sprintf(str,"   </TABLE>\n");
+    res = send(outerSocket, str, strlen(str), 0);
+    }
+
+time_t t = time(NULL);
+sprintf(str,"Îáíîâëåíî: %s</b>" , ctime(&t));
+res = send(outerSocket, str, strlen(str), 0);
+
+send(outerSocket, replyFooter, strlen(replyFooter), 0);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int WEB::SendCSS()
+{
+const char * replyHeader =
+    "HTTP/1.0 200 OK\n"
+    "Content-Type: text/css\n"
+    "Connection: close\n\n";
+
+const char * replyFooter= "\n\n";
+
+send(outerSocket, replyHeader, strlen(replyHeader), 0);
+send(outerSocket, css, strlen(css), 0);
+send(outerSocket, replyFooter, strlen(replyFooter), 0);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+void WEB::SetDirName(const string & dn, int n)
+{
+web->dirName[n] =  dn;
+}
+//---------------------------------------------------------------------------
+void WEB::AddMessage(const string & message, int type)
+{
+time_t t = time(NULL);
+STG_MESSAGE m;
+
+m.msg = message;
+m.type = type;
+m.recvTime = ctime(&t);
+
+messages.push_back(m);
+
+if (messages.size() > MAX_MESSAGES)
+    messages.pop_front();
+
+}
+//---------------------------------------------------------------------------
+void WEB::UpdateStat(const LOADSTAT & ls)
+{
+memcpy((void*)&(WEB::ls), &ls, sizeof(LOADSTAT));
+}
+//---------------------------------------------------------------------------
+
diff --git a/projects/sgauth/web.h b/projects/sgauth/web.h
new file mode 100644 (file)
index 0000000..b734f16
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.3 $
+ $Date: 2007/12/17 08:39:08 $
+ */
+
+#ifndef WIN32
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#else
+#include <winsock2.h>
+#endif
+
+#include <string>
+#include <list>
+
+#include "stg_const.h"
+#include "ia_packets.h"
+
+using namespace std;
+
+#define MAX_MESSAGES    (10)
+//-----------------------------------------------------------------------------
+struct STG_MESSAGE
+{
+string  msg;
+string  recvTime;
+int     type;
+};
+//-----------------------------------------------------------------------------
+class WEB
+{
+public:
+    WEB();
+    void Run();
+    void SetDirName(const string & dn, int n);
+    void SetRefreshPagePeriod(int p);
+    void SetListenAddr(uint32_t ip);
+    void AddMessage(const string & message, int type);
+    void UpdateStat(const LOADSTAT & ls);
+    void Start();
+private:
+
+    void PrepareNet();
+
+    #ifdef WIN32
+    WSADATA wsaData;
+    #else
+    pthread_t thread;
+    #endif
+
+    int         SendReply();
+    int         SendCSS();
+    int         Redirect(const char * url);
+
+    string      dirName[DIR_NUM];
+    int         res;
+    int         listenSocket;
+    int         outerSocket;
+    struct sockaddr_in listenAddr;
+    struct sockaddr_in outerAddr;
+    int         refreshPeriod;
+
+    uint32_t    listenWebAddr;
+    LOADSTAT    ls;
+
+    list<STG_MESSAGE> messages;
+
+    #ifndef WIN32
+    socklen_t   outerAddrLen;
+    #else
+    int         outerAddrLen;
+    #endif
+};
+//-----------------------------------------------------------------------------
+
diff --git a/projects/sgconf/CHANGES b/projects/sgconf/CHANGES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/projects/sgconf/Makefile b/projects/sgconf/Makefile
new file mode 100644 (file)
index 0000000..f9f0042
--- /dev/null
@@ -0,0 +1,99 @@
+###############################################################################
+# $Id: Makefile,v 1.21 2010/02/11 12:34:14 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = sgconf
+
+SRCS = ./main.cpp \
+       ./common_sg.cpp
+
+STGLIBS =  -lconffiles \
+           -lstg_common \
+          -lstg_crypto \
+           -lsrvconf
+
+LIBS += -lexpat \
+       $(LIB_THREAD)
+
+ifeq ($(OS),linux)
+LIBS += -ldl
+else
+LIBS += -lc \
+       -liconv
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+ifeq ($(OS),bsd)
+SEARCH_DIRS += -I/usr/local/include
+CXXFLAGS += -DHAVE_DECL_GETOPT=1
+endif
+
+ifeq ($(OS),bsd5)
+SEARCH_DIRS += -I/usr/local/include
+CXXFLAGS += -DHAVE_DECL_GETOPT=1
+endif
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS += -Wall
+LDFLAGS += -Wl,-E -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-rpath-link,$(DIR_LIB)
+
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs install uninstall install-bin install-data uninstall-bin uninstall-data
+all: libs $(PROG) ../../Makefile.conf
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+$(PROG): $(OBJS) $(STGLIBS)
+       $(CC) $^ $(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*
+       $(MAKE) -C $(DIR_LIBSRC) clean
+
+distclean: clean
+       rm -f ../../Makefile.conf
+
+install: install-bin install-data
+
+install-bin:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/sbin
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) install
+
+install-data:
+
+uninstall: uninstall-bin uninstall-data
+
+uninstall-bin:
+       rm -f $(PREFIX)/usr/sbin/$(PROG)
+
+uninstall-data:
+
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/sgconf/README.txt b/projects/sgconf/README.txt
new file mode 100644 (file)
index 0000000..cbdf9ac
--- /dev/null
@@ -0,0 +1,3 @@
+Compiling:
+> ./build
+
diff --git a/projects/sgconf/build b/projects/sgconf/build
new file mode 100755 (executable)
index 0000000..434d6b0
--- /dev/null
@@ -0,0 +1,161 @@
+#!/bin/sh
+
+#   $Author: faust $
+#   $Revision: 1.21 $
+#   $Date: 2010/04/14 08:59:11 $
+######################################################
+
+OS=unknown
+sys=`uname -s`
+release=`uname -r | cut -b1`
+BUILD_DIR=`pwd`
+CONFFILE="../../Makefile.conf"
+PREFIX="/"
+BIN_MODE=0755
+DATA_MODE=0644
+OWNER=root
+
+if [ -z $1 ]
+then
+    MAKEOPTS="-j1"
+else
+    if [ "$1" = "debug" ]
+    then
+        DEFS="-DDEBUG"
+        MAKEOPTS="-j1"
+        CXXFLAGS="$CXXFLAGS -g3 -W -Wall"
+    else
+        MAKEOPTS="-j1"
+    fi
+fi
+
+CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+
+if [ "$sys" = "Linux" ]
+then
+    OS=linux
+    release=""
+    MAKE="make"
+fi
+
+if [ "$sys" = "FreeBSD" ]
+then
+    case $release in
+        4) OS=bsd;;
+        5) OS=bsd5;;
+        6) OS=bsd5;;
+        7) OS=bsd7;;
+        8) OS=bsd7;;
+        *) OS=unknown;;
+    esac
+    MAKE="gmake"
+fi
+
+if [ "$OS" = "unknown" ]
+then 
+    echo "#############################################################################"
+    echo "# Sorry, but sgconf currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #"
+    echo "#############################################################################"
+    exit 1
+fi
+
+echo "#############################################################################"
+echo "       Building sgconf for $sys $release"
+echo "#############################################################################"
+
+STG_LIBS="conffiles.lib
+         crypto.lib 
+         common.lib 
+         srvconf.lib"
+
+if [ "$OS" = "linux" ]
+then
+    DEFS="$DEFS -DLINUX"
+    LIB_THREAD=-lpthread
+    SHELL="/bin/bash"
+else
+    if [ "$OS" = "bsd" ]
+    then
+        DEFS="$DEFS -DFREE_BSD"
+    else
+        DEFS="$DEFS -DFREE_BSD5"
+        if [ "$OS" = "bsd7" ]
+        then
+            LIB_THREAD=-lpthread
+        else
+            LIB_THREAD=-lc_r
+        fi
+    fi
+    SHELL="/usr/local/bin/bash"
+fi
+
+echo -n "Checking endianess... "
+echo "int main() { int probe = 0x00000001; return *(char *)&probe; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    echo "FAIL!"
+    echo "Endianess checking failed"
+    exit;
+else
+    ./fake
+    if [ $? = 1 ]
+    then
+        ARCH=le
+        CXXFLAGS="$CXXFLAGS -DARCH_LE"
+        echo "Little Endian"
+    else
+        ARCH=be
+        CXXFLAGS="$CXXFLAGS -DARCH_BE"
+        echo "Big Endian"
+    fi
+fi
+rm -f fake
+
+echo -n "Checking for -lexpat... "
+echo "int main() { return 0; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -lexpat -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_EXPAT=no
+    echo "no"
+else
+    CHECK_EXPAT=yes
+    echo "yes"
+fi
+rm -f fake
+rm -f build_check.c
+
+if [ "$CHECK_EXPAT" != "yes" ]
+then
+    echo "-lexpat not found!"
+    exit 1
+fi
+
+echo "OS=$OS" > $CONFFILE
+echo "STG_TIME=yes" >> $CONFFILE
+echo "DIR_BUILD=$BUILD_DIR" >> $CONFFILE
+echo "DIR_LIB=\$(DIR_BUILD)/../../lib" >> $CONFFILE
+echo "DIR_LIBSRC=\$(DIR_BUILD)/../../stglibs" >> $CONFFILE
+echo "DIR_INCLUDE=\$(DIR_BUILD)/../../include" >> $CONFFILE
+echo "ARCH=$ARCH" >> $CONFFILE
+echo "CHECK_EXPAT=$CHECK_EXPAT" >> $CONFFILE
+echo "DEFS=$DEFS" >> $CONFFILE
+echo -n "STG_LIBS=" >> $CONFFILE
+for lib in $STG_LIBS
+do
+    echo -n "$lib " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo "LIB_THREAD=$LIB_THREAD" >> $CONFFILE
+echo "SHELL=$SHELL" >> $CONFFILE
+echo "CXXFLAGS=$CXXFLAGS" >> $CONFFILE
+echo "LDFLAGS=$LDFLAGS" >> $CONFFILE
+echo "PREFIX=$PREFIX" >> $CONFFILE
+echo "BIN_MODE=$BIN_MODE" >> $CONFFILE
+echo "DATA_MODE=$DATA_MODE" >> $CONFFILE
+echo "OWNER=$OWNER" >> $CONFFILE
+
+$MAKE $MAKEOPTS
+
diff --git a/projects/sgconf/common_sg.cpp b/projects/sgconf/common_sg.cpp
new file mode 100644 (file)
index 0000000..77d7476
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Author: faust $
+ $Revision: 1.12 $
+ $Date: 2009/06/08 10:02:28 $
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <iostream>
+#include <iconv.h>
+
+#include "common_sg.h"
+#include "version_sg.h"
+#include "common.h"
+#include "sg_error_codes.h"
+
+using namespace std;
+
+const int usageConf = 0;
+const int usageInfo = 1;
+
+const int TO_KOI8 = 0;
+const int FROM_KOI8 = 1;
+//-----------------------------------------------------------------------------
+struct GetUserCbData
+{
+    void * data;
+    bool * result;
+};
+//---------------------------------------------------------------------------
+struct HelpParams
+{
+    string setActionName;
+    string getActionName;
+    string valueName;
+    string valueParam;
+};
+//---------------------------------------------------------------------------
+void Usage(int usageType)
+{
+printf("Sgconf version: %s\n\n", VERSION_SG);
+
+char action[4];
+if (usageType == usageConf)
+    strcpy(action, "set");
+else
+    strcpy(action, "get");
+
+printf("To add or to set cash use:\n");
+printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -c <add_cash[:log message]>\n");
+printf("sgconf set -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -v <set_cash[:log message]>\n");
+printf("To get cash use:\n");
+printf("sgconf get -s <server> -p <port> -a <admin> -w <admin_pass> -u <user> -c\n\n");
+
+HelpParams hp[] =
+{
+    {"set tariff",              "get tariff",           "-t",   "<tariff:now|delayed>"},
+    {"set credit",              "get credit",           "-r",   "<credit>"},
+    {"set 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 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] == '-'))
+        {
+        return 1;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+short int ParseServerPort(const char * p)
+{
+int port;
+if (str2x(p, port) != 0)
+    {
+    printf("Incorresct server port %s\n", p);
+    exit(NETWORK_ERR_CODE);
+    }
+return (short)port;
+}
+//-----------------------------------------------------------------------------
+char * ParseAdminLogin(char * adm)
+{
+if (CheckLogin(adm))
+    {
+    printf("Incorresct admin login %s\n", adm);
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+return adm;
+}
+//-----------------------------------------------------------------------------
+char * ParsePassword(char * pass)
+{
+if (strlen(pass) >= ADM_PASSWD_LEN)
+    {
+    printf("Password too big %s\n", pass);
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+
+return pass;
+}
+//-----------------------------------------------------------------------------
+char * ParseUser(char * usr)
+{
+if (CheckLogin(usr))
+    {
+    printf("Incorresct user login %s\n", usr);
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+return usr;
+}
+//-----------------------------------------------------------------------------
+void ConvertKOI8(const string & src, string * dst, int encType)
+{
+iconv_t cd;
+char * ob = new char[src.size() * 2 + 1];
+char * ib = new char[src.size() + 1];
+
+strcpy(ib, src.c_str());
+
+char * outbuf = ob;
+char * inbuf = ib;
+
+setlocale(LC_ALL, "");
+
+char charsetF[100];
+char charsetT[100];
+
+if (encType == TO_KOI8)
+    {
+    strcpy(charsetF, nl_langinfo(CODESET));
+    strcpy(charsetT, "koi8-r");
+    }
+else
+    {
+    strcpy(charsetT, nl_langinfo(CODESET));
+    strcpy(charsetF, "koi8-r");
+    }
+
+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 string & src, string * dst)
+{
+ConvertKOI8(src, dst, FROM_KOI8);
+}
+//-----------------------------------------------------------------------------
+void ConvertToKOI8(const string & src, string * dst)
+{
+ConvertKOI8(src, dst, TO_KOI8);
+}
+//-----------------------------------------------------------------------------
+int RecvSetUserAnswer(const char * ans, void * d)
+{
+GetUserCbData * gucbd;
+gucbd = (GetUserCbData *)d;
+
+bool * result = gucbd->result;
+
+//REQUEST * req = (REQUEST *)gucbd->data;
+
+//printf("ans=%s\n", ans);
+if (strcasecmp("Ok", ans) == 0)
+    *result = true;
+else
+    *result = false;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+struct StringReqParams
+{
+    string name;
+    RESETABLE<string> reqParam;
+    string * value;
+};
+//-----------------------------------------------------------------------------
+void RecvUserData(USERDATA * ud, void * d)
+{
+GetUserCbData * gucbd;
+gucbd = (GetUserCbData *)d;
+
+bool * result = gucbd->result;
+
+REQUEST * req = (REQUEST *)gucbd->data;
+
+if (ud->login == "")
+    {
+    *result = false;
+    return;
+    }
+
+if (!req->cash.res_empty())
+    cout << "cash=" << ud->cash << endl;
+
+if (!req->credit.res_empty())
+    cout << "credit=" << ud->credit << endl;
+
+if (!req->down.res_empty())
+    cout << "down=" << ud->down << endl;
+
+if (!req->passive.res_empty())
+    cout << "passive=" << ud->passive << endl;
+
+if (!req->disableDetailStat.res_empty())
+    cout << "disableDetailStat=" << ud->disableDetailStat << endl;
+
+if (!req->alwaysOnline.res_empty())
+    cout << "alwaysOnline=" << ud->alwaysOnline << endl;
+
+if (!req->prepaidTraff.res_empty())
+    cout << "prepaidTraff=" << ud->prepaidTraff << endl;
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    if (!req->u[i].res_empty())
+        cout << "u" << i << "=" << ud->stat.mu[i] << endl;
+    if (!req->d[i].res_empty())
+        cout << "d" << i << "=" << ud->stat.md[i] << endl;
+    }
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    if (!req->ud[i].res_empty())
+        {
+        string str;
+        ConvertFromKOI8(ud->userData[i], &str);
+        cout << "userdata" << i << "=" << str << endl;
+        }
+    }
+
+StringReqParams strReqParams[] =
+{
+    {"note",     req->note,        &ud->note},
+    {"name",     req->name,        &ud->name},
+    {"address",  req->address,     &ud->address},
+    {"email",    req->email,       &ud->email},
+    {"phone",    req->phone,       &ud->phone},
+    {"group",    req->group,       &ud->group},
+    {"tariff",   req->tariff,      &ud->tariff},
+    {"password", req->usrPasswd,   &ud->password},
+    {"ip",      req->ips,         &ud->ips}    // IP-address of user
+};
+for (unsigned i = 0; i < sizeof(strReqParams) / sizeof(StringReqParams); i++)
+    {
+    if (!strReqParams[i].reqParam.res_empty())
+        {
+        string str;
+        ConvertFromKOI8(*strReqParams[i].value, &str);
+        cout << strReqParams[i].name << "=" << str << endl;
+        }
+    }
+*result = true;
+}
+//-----------------------------------------------------------------------------
+int ProcessSetUser(const std::string &server,
+                   int port,
+                   const std::string &admLogin,
+                   const std::string &admPasswd,
+                   const std::string &str,
+                   void * data,
+                   bool isMessage)
+{
+SERVCONF sc;
+
+bool result = false;
+
+
+sc.SetServer(server.c_str());  // õÓÔÁÎÁ×ÌÉ×ÁÅÍ ÉÍÑ ÓÅÒ×ÅÒÁ Ó ËÏÔÏÒÇÏ ÚÁÂÉÒÁÔØ ÉÎÆÕ
+sc.SetPort(port);           // ÁÄÍÉÎÓËÉÊ ÐÏÒÔ ÓÅÒ×ÅÒÁÐÏÒÔ
+sc.SetAdmLogin(admLogin.c_str());    // ÷ÙÓÔÁ×ÌÑÅÍ ÌÏÇÉΠɠÐÁÒÏÌØ ÁÄÍÉÎÁ
+sc.SetAdmPassword(admPasswd.c_str());
+
+// TODO Good variable name :)
+GetUserCbData gucbd;
+
+gucbd.data = data;
+gucbd.result = &result;
+
+if (isMessage)
+    {
+    sc.SetSendMessageCb(RecvSetUserAnswer, &gucbd);
+    sc.MsgUser(str.c_str());
+    }
+else
+    {
+    sc.SetChgUserCb(RecvSetUserAnswer, &gucbd);
+    sc.ChgUser(str.c_str());
+    }
+
+if (result)
+    {
+    printf("Ok\n");
+    return 0;
+    }
+else
+    {
+    printf("Error\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ProcessGetUser(const std::string &server,
+                   int port,
+                   const std::string &admLogin,
+                   const std::string &admPasswd,
+                   const std::string &login,
+                   void * data)
+{
+SERVCONF sc;
+
+bool result = false;
+
+sc.SetServer(server.c_str());  // õÓÔÁÎÁ×ÌÉ×ÁÅÍ ÉÍÑ ÓÅÒ×ÅÒÁ Ó ËÏÔÏÒÇÏ ÚÁÂÉÒÁÔØ ÉÎÆÕ
+sc.SetPort(port);           // ÁÄÍÉÎÓËÉÊ ÐÏÒÔ ÓÅÒ×ÅÒÁÐÏÒÔ
+sc.SetAdmLogin(admLogin.c_str());    // ÷ÙÓÔÁ×ÌÑÅÍ ÌÏÇÉΠɠÐÁÒÏÌØ ÁÄÍÉÎÁ
+sc.SetAdmPassword(admPasswd.c_str());
+
+// TODO Good variable name :)
+GetUserCbData gucbd;
+
+gucbd.data = data;
+gucbd.result = &result;
+
+sc.SetGetUserDataRecvCb(RecvUserData, &gucbd);
+sc.GetUser(login.c_str());
+
+if (result)
+    {
+    printf("Ok\n");
+    return 0;
+    }
+else
+    {
+    printf("Error\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/sgconf/common_sg.h b/projects/sgconf/common_sg.h
new file mode 100644 (file)
index 0000000..d36ed75
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Author: faust $
+ $Revision: 1.5 $
+ $Date: 2009/06/08 10:02:28 $
+ */
+
+
+#ifndef COMMON_SG_H
+#define COMMON_SG_H
+
+#include <string>
+
+#include "servconf.h"
+#include "request.h"
+
+void UsageConf();
+void UsageInfo();
+
+char * ParseUser(char * usr);
+char * ParsePassword(char * pass);
+char * ParseAdminLogin(char * adm);
+short int ParseServerPort(const char * p);
+void ParseAnyString(const char * c, string * msg, const char * enc = "cp1251");
+int CheckLogin(const char * login);
+void ConvertFromKOI8(const std::string & src, std::string * dst);
+void ConvertToKOI8(const std::string & src, std::string * dst);
+
+int ProcessGetUser(const std::string &server,
+                   int port,
+                   const std::string &admLogin,
+                   const std::string &admPasswd,
+                   const std::string &login,
+                   void * data);
+
+int ProcessSetUser(const std::string &server,
+                   int port,
+                   const std::string &admLogin,
+                   const std::string &admPasswd,
+                   const std::string &str,
+                   void * data,
+                   bool isMessage = false);
+
+#endif
+
diff --git a/projects/sgconf/main.cpp b/projects/sgconf/main.cpp
new file mode 100644 (file)
index 0000000..d2671be
--- /dev/null
@@ -0,0 +1,1095 @@
+/*
+ *    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.25 $
+ $Date: 2010/03/25 14:37:43 $
+ */
+
+#include <unistd.h>
+#include <getopt.h>
+#include <iconv.h>
+#include <langinfo.h>
+
+#include <cerrno>
+#include <clocale>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <list>
+#include <sstream>
+
+#include "request.h"
+#include "common.h"
+#include "netunit.h"
+#include "common_sg.h"
+#include "sg_error_codes.h"
+
+using namespace std;
+
+time_t stgTime;
+
+int ParseReplyGet(void * data, list<string> * ans);
+//int ParseReplySet(void * data, list<string> * ans);
+
+struct option long_options_get[] = {
+{"server",      1, 0, 's'},  //Server
+{"port",        1, 0, 'p'},  //Port
+{"admin",       1, 0, 'a'},  //Admin
+{"admin_pass",  1, 0, 'w'},  //passWord
+{"user",        1, 0, 'u'},  //User
+{"addcash",     0, 0, 'c'},  //Add Cash
+//{"setcash",     0, 0, 'v'},  //Set Cash
+{"credit",      0, 0, 'r'},  //cRedit
+{"tariff",      0, 0, 't'},  //Tariff
+{"message",     0, 0, 'm'},  //message
+{"password",    0, 0, 'o'},  //password
+{"down",        0, 0, 'd'},  //down
+{"passive",     0, 0, 'i'},  //passive
+{"disable-stat",0, 0, 'S'},  //disable detail stat
+{"always-online",0, 0, 'O'}, //always online
+{"u0",          0, 0, 500},  //U0
+{"u1",          0, 0, 501},  //U1
+{"u2",          0, 0, 502},  //U2
+{"u3",          0, 0, 503},  //U3
+{"u4",          0, 0, 504},  //U4
+{"u5",          0, 0, 505},  //U5
+{"u6",          0, 0, 506},  //U6
+{"u7",          0, 0, 507},  //U7
+{"u8",          0, 0, 508},  //U8
+{"u9",          0, 0, 509},  //U9
+{"d0",          0, 0, 600},  //D0
+{"d1",          0, 0, 601},  //D1
+{"d2",          0, 0, 602},  //D2
+{"d3",          0, 0, 603},  //D3
+{"d4",          0, 0, 604},  //D4
+{"d5",          0, 0, 605},  //D5
+{"d6",          0, 0, 606},  //D6
+{"d7",          0, 0, 607},  //D7
+{"d8",          0, 0, 608},  //D8
+{"d9",          0, 0, 609},  //D9
+
+{"ud0",         0, 0, 700},  //UserData0
+{"ud1",         0, 0, 701},  //UserData1
+{"ud2",         0, 0, 702},  //UserData2
+{"ud3",         0, 0, 703},  //UserData3
+{"ud4",         0, 0, 704},  //UserData4
+{"ud5",         0, 0, 705},  //UserData5
+{"ud6",         0, 0, 706},  //UserData6
+{"ud7",         0, 0, 707},  //UserData7
+{"ud8",         0, 0, 708},  //UserData8
+{"ud9",         0, 0, 709},  //UserData9
+
+{"prepaid",     0, 0, 'e'},  //prepaid traff
+{"create",      0, 0, 'n'},  //create
+{"delete",      0, 0, 'l'},  //delete
+
+{"note",        0, 0, 'N'},  //Note
+{"name",        0, 0, 'A'},  //nAme
+{"address",     0, 0, 'D'},  //aDdress
+{"email",       0, 0, 'L'},  //emaiL
+{"phone",       0, 0, 'P'},  //phone
+{"group",       0, 0, 'G'},  //Group
+{"ip",         0, 0, 'I'},  //IP-address of user
+
+{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
+{"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
+{"ip",         0, 0, 'I'},  //IP-address of user
+
+{0, 0, 0, 0}};
+
+//-----------------------------------------------------------------------------
+double ParseCash(const char * c, string * message)
+{
+//-c 123.45:log message
+double cash;
+char * msg;
+char * str;
+str = new char[strlen(c)];
+
+strcpy(str, c);
+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, 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.res_empty())
+    {
+    string msg;
+    Encode12str(msg, req->usrMsg);
+    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.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())
+    {
+    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.res_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.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);
+    }
+
+if (!req->disableDetailStat.res_empty())
+    {
+    sprintf(str, "<disableDetailStat value=\"%d\" />\n", req->disableDetailStat.const_data());
+    strcat(r, str);
+    }
+
+if (!req->alwaysOnline.res_empty())
+    {
+    sprintf(str, "<aonline value=\"%d\" />\n", req->alwaysOnline.const_data());
+    strcat(r, str);
+    }
+
+// IP-address of user
+if (!req->ips.res_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->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())
+    {
+    string note;
+    Encode12str(note, req->note);
+    sprintf(str, "<note value=\"%s\"/>", note.c_str());
+    strcat(r, str);
+    }
+
+if (!req->name.res_empty())
+    {
+    string name;
+    Encode12str(name, req->name);
+    sprintf(str, "<name value=\"%s\"/>", name.c_str());
+    strcat(r, str);
+    }
+
+if (!req->address.res_empty())
+    {
+    string address;
+    Encode12str(address, req->address);
+    sprintf(str, "<address value=\"%s\"/>", address.c_str());
+    strcat(r, str);
+    }
+
+if (!req->email.res_empty())
+    {
+    string email;
+    Encode12str(email, req->email);
+    sprintf(str, "<email value=\"%s\"/>", email.c_str());
+    strcat(r, str);
+    }
+
+if (!req->phone.res_empty())
+    {
+    string phone;
+    Encode12str(phone, req->phone);
+    sprintf(str, "<phone value=\"%s\"/>", phone.c_str());
+    strcat(r, str);
+    }
+
+if (!req->group.res_empty())
+    {
+    string group;
+    Encode12str(group, req->group);
+    sprintf(str, "<group value=\"%s\"/>", group.c_str());
+    strcat(r, str);
+    }
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    if (!req->ud[i].res_empty())
+        {
+        string ud;
+        Encode12str(ud, req->ud[i]);
+        sprintf(str, "<userdata%d value=\"%s\"/>", i, ud.c_str());
+        strcat(r, str);
+        }
+    }
+
+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()
+    || !req->ips.res_empty()   // IP-address of user
+
+    || !req->createUser
+    || !req->deleteUser;
+
+
+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;
+int missedOptionArg = false;
+
+const char * short_options_get = "s:p:a:w:u:crtmodieNADLPGISO";
+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 'd': //down
+            req.down = 1;
+            break;
+
+        case 'i': //passive
+            req.passive = 1;
+            break;
+
+        case 't': //tariff
+            req.tariff = " ";
+            break;
+
+        case 'e': //Prepaid Traffic
+            req.prepaidTraff = 1;
+            break;
+
+        case 'N': //Note
+            req.note = " ";
+            break;
+
+        case 'A': //nAme
+            req.name = " ";
+            break;
+
+        case 'D': //aDdress
+            req.address =" ";
+            break;
+
+        case 'L': //emaiL
+            req.email = " ";
+            break;
+
+        case 'P': //phone
+            req.phone = " ";
+            break;
+
+        case 'G': //Group
+            req.group = " ";
+            break;
+       
+       case 'I': //IP-address of user
+           req.ips = " ";
+           break;
+
+        case 'S': //Detail stat status
+            req.disableDetailStat = " ";
+            break;
+
+        case 'O': //Always online status
+            req.alwaysOnline = " ";
+            break;
+
+        case 500: //U
+        case 501:
+        case 502:
+        case 503:
+        case 504:
+        case 505:
+        case 506:
+        case 507:
+        case 508:
+        case 509:
+            //printf("U%d\n", c - 500);
+            req.u[c - 500] = 1;
+            break;
+
+        case 600: //D
+        case 601:
+        case 602:
+        case 603:
+        case 604:
+        case 605:
+        case 606:
+        case 607:
+        case 608:
+        case 609:
+            //printf("D%d\n", c - 600);
+            req.d[c - 600] = 1;
+            break;
+
+        case 700: //UserData
+        case 701:
+        case 702:
+        case 703:
+        case 704:
+        case 705:
+        case 706:
+        case 707:
+        case 708:
+        case 709:
+            //printf("UD%d\n", c - 700);
+            req.ud[c - 700] = " ";
+            break;
+
+        case '?':
+        case ':':
+            //printf ("Unknown option \n");
+            missedOptionArg = true;
+            break;
+
+        default:
+            printf ("?? getopt returned character code 0%o ??\n", c);
+        }
+    }
+
+if (optind < argc)
+    {
+    printf ("non-option ARGV-elements: ");
+    while (optind < argc)
+        printf ("%s ", argv[optind++]);
+    UsageInfo();
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+
+if (missedOptionArg || !CheckParametersGet(&req))
+    {
+    //printf("Parameter needed\n");
+    UsageInfo();
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+
+return ProcessGetUser(req.server, req.port, req.admLogin, req.admPasswd, req.login, &req);
+}
+//-----------------------------------------------------------------------------
+int 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:";
+
+int missedOptionArg = false;
+
+while (1)
+    {
+    int option_index = -1;
+
+    c = getopt_long(argc, argv, short_options_set, long_options_set, &option_index);
+
+    if (c == -1)
+        break;
+
+    switch (c)
+        {
+        case 's': //server
+            req.server = optarg;
+            break;
+
+        case 'p': //port
+            req.port = ParseServerPort(optarg);
+            //req.portReq = 1;
+            break;
+
+        case 'a': //admin
+            req.admLogin = ParseAdminLogin(optarg);
+            break;
+
+        case 'w': //admin password
+            req.admPasswd = ParsePassword(optarg);
+            break;
+
+        case 'o': //change user password
+            req.usrPasswd = ParsePassword(optarg);
+            break;
+
+        case 'u': //user
+            req.login = ParseUser(optarg);
+            break;
+
+        case 'c': //add cash
+            req.cash = ParseCash(optarg, &req.message);
+            break;
+
+        case 'v': //set cash
+            req.setCash = ParseCash(optarg, &req.message);
+            break;
+
+        case 'r': //credit
+            req.credit = ParseCredit(optarg);
+            break;
+
+        case 'd': //down
+            req.down = ParseDownPassive(optarg);
+            break;
+
+        case 'i': //passive
+            req.passive = ParseDownPassive(optarg);
+            break;
+
+        case 't': //tariff
+            req.tariff = ParseTariff(optarg, req.chgTariff);
+            break;
+
+        case 'm': //message
+            ParseAnyString(optarg, &str);
+            req.usrMsg = str;
+            isMessage = true;
+            break;
+
+        case 'e': //Prepaid Traffic
+            req.prepaidTraff = ParsePrepaidTraffic(optarg);
+            break;
+
+        case 'n': //Create User
+            req.createUser = true;
+            break;
+
+        case 'l': //Delete User
+            req.deleteUser = true;
+            break;
+
+        case 'N': //Note
+            ParseAnyString(optarg, &str);
+            req.note = str;
+            break;
+
+        case 'A': //nAme
+            ParseAnyString(optarg, &str, "koi8-r");
+            req.name = str;
+            break;
+
+        case 'D': //aDdress
+            ParseAnyString(optarg, &str);
+            req.address = str;
+            break;
+
+        case 'L': //emaiL
+            ParseAnyString(optarg, &str);
+            req.email = str;
+            //printf("EMAIL=%s\n", optarg);
+            break;
+
+        case 'P': //phone
+            ParseAnyString(optarg, &str);
+            req.phone = str;
+            break;
+
+        case 'G': //Group
+            ParseAnyString(optarg, &str);
+            req.group = str;
+            break;
+
+        case 'I': //IP-address of user
+            ParseAnyString(optarg, &str);
+            req.ips = str;
+            break;
+
+        case 'S':
+            req.disableDetailStat = ParseDownPassive(optarg);
+            break;
+
+        case 'O':
+            req.alwaysOnline = ParseDownPassive(optarg);
+            break;
+
+        case 500: //U
+        case 501:
+        case 502:
+        case 503:
+        case 504:
+        case 505:
+        case 506:
+        case 507:
+        case 508:
+        case 509:
+            //printf("U%d\n", c - 500);
+            req.u[c - 500] = ParseTraff(optarg);
+            break;
+
+        case 600: //D
+        case 601:
+        case 602:
+        case 603:
+        case 604:
+        case 605:
+        case 606:
+        case 607:
+        case 608:
+        case 609:
+            //printf("D%d\n", c - 600);
+            req.d[c - 600] = ParseTraff(optarg);
+            break;
+
+        case 700: //UserData
+        case 701:
+        case 702:
+        case 703:
+        case 704:
+        case 705:
+        case 706:
+        case 707:
+        case 708:
+        case 709:
+            ParseAnyString(optarg, &str);
+            //printf("UD%d\n", c - 700);
+            req.ud[c - 700] = str;
+            break;
+
+        case '?':
+            //printf("Missing option argument\n");
+            missedOptionArg = true;
+            break;
+
+        case ':':
+            //printf("Missing option argument\n");
+            missedOptionArg = true;
+            break;
+
+        default:
+            printf("?? getopt returned character code 0%o ??\n", c);
+        }
+    }
+
+if (optind < argc)
+    {
+    printf ("non-option ARGV-elements: ");
+    while (optind < argc)
+        printf ("%s ", argv[optind++]);
+    UsageConf();
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+
+if (missedOptionArg || !CheckParametersSet(&req))
+    {
+    //printf("Parameter needed\n");
+    UsageConf();
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+
+const int rLen = 20000;
+char rstr[rLen];
+memset(rstr, 0, rLen);
+
+CreateRequestSet(&req, rstr);
+return ProcessSetUser(req.server, req.port, req.admLogin, req.admPasswd, rstr, NULL, isMessage);
+}
+//-----------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+if (argc <= 2)
+    {
+    UsageConf();
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+
+if (strcmp(argv[1], "get") == 0)
+    {
+    //printf("get\n");
+    return mainGet(argc - 1, argv + 1);
+    }
+else if (strcmp(argv[1], "set") == 0)
+    {
+    //printf("set\n");
+    return mainSet(argc - 1, argv + 1);
+    }
+else
+    {
+    UsageConf();
+    exit(PARAMETER_PARSING_ERR_CODE);
+    }
+return UNKNOWN_ERR_CODE;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/sgconf/parser.cpp b/projects/sgconf/parser.cpp
new file mode 100644 (file)
index 0000000..20dd061
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Author: nobunaga $
+ $Revision: 1.4 $
+ $Date: 2008/05/11 08:15:07 $
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <expat.h>
+#include <string.h>
+
+#include <string>
+#include <list>
+
+#include "common.h"
+#include "netunit.h"
+#include "request.h"
+
+using namespace std;
+
+int parse_depth = 0;
+XML_Parser parser;
+//---------------------------------------------------------------------------
+int ParseAns(void * data, const char *el, const char **attr)
+{
+if (strcasecmp(attr[1], "ok") == 0)
+    {
+    return 0;
+    }
+if (strcasecmp(attr[1], "error") == 0)
+    {
+    return 1;
+    }
+if (strcasecmp(attr[1], "err") == 0)
+    {
+    return 1;
+    }
+return -1;
+}
+//---------------------------------------------------------------------------
+void StartElement(void *data, const char *el, const char **attr)
+{
+parse_depth++;
+if (parse_depth == 1)
+    {
+    if (ParseAns(data, el, attr) < 0)
+        {
+        printf("Unexpected token\n");
+        exit(UNKNOWN_ERR_CODE);
+        }
+    if (ParseAns(data, el, attr) == 1)
+        {
+        printf("User not found\n");
+        exit(USER_NOT_FOUND_ERR_CODE);
+        }
+    return;
+    }
+}
+//-----------------------------------------------------------------------------
+void EndElement(void *data, const char *el)
+{
+parse_depth--;
+}
+//---------------------------------------------------------------------------
+int ParseReply(void * data, list<string> * ans)
+{
+int done = 0;
+int len;
+
+parse_depth = 0;
+parser = XML_ParserCreate(NULL);
+
+if (!parser)
+    {
+    printf("Couldn't allocate memory for parser\n");
+    exit(UNKNOWN_ERR_CODE);
+    }
+
+XML_ParserReset(parser, NULL);
+XML_SetElementHandler(parser, StartElement, EndElement);
+
+list<string>::iterator n = ans->begin();
+while (n != ans->end())
+    {
+    len = strlen(n->c_str());
+
+    if (++n == ans->end())
+        done = 1;
+    n--;
+
+    if (XML_Parse(parser, n->c_str(), len, done) == XML_STATUS_ERROR)
+        {
+        char s[128];
+        printf(s, "Parse error at line %d:\n%s\n",
+               XML_GetCurrentLineNumber(parser),
+               XML_ErrorString(XML_GetErrorCode(parser)));
+        exit(UNKNOWN_ERR_CODE);
+        }
+
+    ++n;
+    }
+
+XML_ParserFree(parser);
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/sgconf/request.h b/projects/sgconf/request.h
new file mode 100644 (file)
index 0000000..dbd7d6d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    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 "resetable.h"
+#include "stg_const.h"
+#include "os_int.h"
+
+#define TARIFF_NOW  (0)
+#define TARIFF_DEL  (1)
+#define TARIFF_REC  (2)
+
+using namespace std;
+//-----------------------------------------------------------------------------
+struct REQUEST
+{
+
+REQUEST()
+{
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        u[i].reset();
+        d[i].reset();
+        }
+
+    for (int i = 0; i < USERDATA_NUM; i++)
+        ud[i].reset();
+
+    createUser = false;
+    deleteUser = false;
+}
+
+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;
+
+RESETABLE<string>   usrMsg;
+RESETABLE<double>   credit;
+RESETABLE<string>   usrPasswd;
+RESETABLE<bool>     down;
+RESETABLE<bool>     passive;
+RESETABLE<bool>     disableDetailStat;
+RESETABLE<bool>     alwaysOnline;
+RESETABLE<double>   prepaidTraff;
+
+RESETABLE<int64_t>  u[DIR_NUM];
+RESETABLE<int64_t>  d[DIR_NUM];
+
+RESETABLE<string>   ud[USERDATA_NUM];
+
+RESETABLE<string>   note;
+RESETABLE<string>   name;
+RESETABLE<string>   address;
+RESETABLE<string>   email;
+RESETABLE<string>   phone;
+RESETABLE<string>   group;
+RESETABLE<string>   ips; // IP-address of user
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
+
diff --git a/projects/sgconf/sg_error_codes.h b/projects/sgconf/sg_error_codes.h
new file mode 100644 (file)
index 0000000..250bd47
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *    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
new file mode 100755 (executable)
index 0000000..fbd3283
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+LD_LIBRARY_PATH=../../lib ./sgconf get -s localhost -p5555 -aadmin -w123456 $*
+
diff --git a/projects/sgconf/sgconfs b/projects/sgconf/sgconfs
new file mode 100755 (executable)
index 0000000..e27108e
--- /dev/null
@@ -0,0 +1,4 @@
+#!/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
new file mode 100644 (file)
index 0000000..8635259
--- /dev/null
@@ -0,0 +1,1084 @@
+/*
+ *    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 "request.h"
+#include "common.h"
+#include "netunit.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)];
+
+strcpy(str, c);
+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-r";
+
+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/version_sg.h b/projects/sgconf/version_sg.h
new file mode 100644 (file)
index 0000000..f9664eb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Author: faust $
+ $Revision: 1.3 $
+ $Date: 2009/08/05 09:29:35 $
+ */
+
+
+#ifndef VERSION_SG_H
+#define VERSION_SG_H
+
+#define VERSION_SG "1.08.9"
+
+#endif
+
+
diff --git a/projects/stargazer/.#Makefile.1.45 b/projects/stargazer/.#Makefile.1.45
new file mode 100644 (file)
index 0000000..a910893
--- /dev/null
@@ -0,0 +1,141 @@
+###############################################################################
+# $Id: Makefile,v 1.45 2009/03/20 15:47:10 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = stargazer
+
+SRCS = ./admin.cpp \
+       ./admins.cpp \
+       ./main.cpp \
+       ./curr_ip.cpp \
+       ./settings.cpp \
+       ./stg_timer.cpp \
+       ./tariff.cpp \
+       ./tariffs.cpp \
+       ./traffcounter.cpp \
+       ./user.cpp \
+       ./user_property.cpp \
+       ./users.cpp \
+       ./plugin_runner.cpp \
+       ./store_loader.cpp \
+       ./pidfile.cpp
+
+STGLIBS =  -lstg_logger \
+          -lstg_locker \
+           -lstg_common \
+           -lscript_executer \
+           -ldotconfpp
+
+LIBS += -lexpat
+
+ifeq ($(OS),linux)
+LIBS += $(LIB_THREAD) \
+        -ldl
+else
+LIBS += $(LIB_THREAD) \
+        -lc
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS += -Wall -W
+LDFLAGS += -Wl,-E -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-rpath-link,$(DIR_LIB) 
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs plugins install uninstall install-bin install-data
+all: libs plugins $(PROG)
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+plugins: libs 
+       $(MAKE) -C $(DIR_PLUGINS)
+
+$(PROG): $(OBJS) $(STGLIBS)
+       $(CC) $^ $(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*
+       $(MAKE) -C $(DIR_LIBSRC) clean
+       $(MAKE) -C $(DIR_PLUGINS) clean
+
+distclean: clean
+       rm -f $(DIR_MOD)/*
+       rm -f ../../Makefile.conf
+
+install: install-bin install-data
+
+install-bin:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/sbin
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) install
+       $(MAKE) -C $(DIR_PLUGINS) install
+
+install-data:
+       # Install etc
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/etc/stargazer
+       install -m $(DATA_MODE) -o $(OWNER) $(ETC_DIR)/stargazer.conf $(PREFIX)/etc/stargazer/stargazer.conf
+       install -m $(DATA_MODE) -o $(OWNER) $(ETC_DIR)/rules $(PREFIX)/etc/stargazer/rules
+       install -m $(BIN_MODE) -o $(OWNER) $(ETC_DIR)/On* $(PREFIX)/etc/stargazer/
+       
+       # Install file db
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/var/stargazer/admins
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/var/stargazer/tariffs
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/var/stargazer/users/test
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/admins/admin.adm $(PREFIX)/var/stargazer/admins/admin.adm
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/tariffs/tariff.tf $(PREFIX)/var/stargazer/tariffs/tariff.tf
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/users/test/conf $(PREFIX)/var/stargazer/users/test/conf
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/users/test/stat $(PREFIX)/var/stargazer/users/test/stat
+       
+ifeq ($(CHECK_FBCLIENT),yes)
+       # Install firebird db
+       mkdir -p $(PREFIX)/var/stargazer
+       chown $(OWNER):$(FIREBIRD_GROUP) $(PREFIX)/var/stargazer
+       chmod g+rw $(PREFIX)/var/stargazer
+       echo "connect '$(DB_ADDRESS)' user '$(DB_USER)' password '$(DB_PASSWORD)';" > .db.sql
+       echo "drop database;" >> .db.sql
+       echo "create database '$(DB_ADDRESS)' user '$(DB_USER)' password '$(DB_PASSWORD)' default character set win1251;" >> .db.sql
+       cat $(VAR_DIR)/../00-base-00.sql >> .db.sql
+       $(FIREBIRD_ISQL) -i .db.sql
+       rm -f .db.sql
+endif
+
+uninstall: uninstall-bin uninstall-data
+
+uninstall-bin:
+       rm -f $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) uninstall
+       $(MAKE) -C $(DIR_PLUGINS) uninstall
+       rm -rf $(PREFIX)/usr/lib/stg
+
+uninstall-data:
+       # Uninstall etc
+       rm -rf $(PREFIX)/etc/stargazer
+       rm -rf $(PREFIX)/var/stargazer
+
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile ../../Makefile.conf" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/stargazer/BUGS b/projects/stargazer/BUGS
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/projects/stargazer/CHANGES b/projects/stargazer/CHANGES
new file mode 100644 (file)
index 0000000..7f80179
--- /dev/null
@@ -0,0 +1,9 @@
+1. éÓÐÒÁ×ÌÅÎÁ ÏÛÉÂËÁ × ÐÌÁÇÉÎÅ ËÏÎÆÉÇÕÒÁÔÏÒÁ ÐÒÉ×ÏÄÉ×ÛÁÑ Ë ÐÁÄÅÎÉÀ ÓÅÒ×ÅÒÁ
+2. ðÅÒÅÒÁÂÏÔÁΠËÏÄ ÐÌÁÇÉÎÁ Á×ÔÏÒÉÚÁÃÉÉ inetaccess. õ×ÅÌÉÞÅÎÁ ÓËÏÒÏÓÔØ ÅÇÏ
+   ÒÁÂÏÔÙ
+3. éÓÐÒÁ×ÌÅÎÁ ÏÛÉÂËÁ, ÐÒÉ×ÏÄÉ×ÛÁÑ Ë ÓÌÉÛËÏÍ ÞÁÓÔÏÊ ÚÁÐÉÓÉ ÆÁÊÌÏ× stat É conf,
+   É ÓÏÏÔ×ÅÔÓÔ×ÅÎÎÏ Ë ×ÙÓÏËÏÊ ÚÁÇÒÕÚËÅ ÐÒÏÃÅÓÓÏÒÁ
+4. éÓÐÒÁ×ÌÅÎÁ ÏÛÉÂËÁ × ÏÂÒÁÂÏÔËÅ ÐÏÒÏÇÁ ÔÁÒÉÆÁ. ðÒÉ ÔÒÁÆÉËÅ ÂÏÌÅÅ 2 ç ÐÏÒÏÇ
+   ÐÅÒÅÓÔÁ×ÁÌ ÒÁÂÏÔÁÔØ
+5. äÏÂÁ×ÌÅÎÁ ×ÏÚÍÏÖÎÏÓÔØ ×ÙÐÏÌÎÑÔØ ÓËÒÉÐÔÙ OnConnect É OnDisconnect ÕÄÁÌÅÎÎÏ
+   (ôÏÌØËÏ ÄÌÑ ÔÅÓÔÏ×)
diff --git a/projects/stargazer/Makefile b/projects/stargazer/Makefile
new file mode 100644 (file)
index 0000000..02757ad
--- /dev/null
@@ -0,0 +1,140 @@
+###############################################################################
+# $Id: Makefile,v 1.50 2010/10/07 18:27:27 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = stargazer
+
+SRCS = ./admin.cpp \
+       ./admins.cpp \
+       ./main.cpp \
+       ./settings.cpp \
+       ./stg_timer.cpp \
+       ./tariff.cpp \
+       ./tariffs.cpp \
+       ./traffcounter.cpp \
+       ./user.cpp \
+       ./user_property.cpp \
+       ./users.cpp \
+       ./plugin_runner.cpp \
+       ./store_loader.cpp \
+       ./pidfile.cpp \
+       ./eventloop.cpp
+
+STGLIBS =  -lstg_logger \
+          -lstg_locker \
+           -lstg_common \
+           -lscript_executer \
+           -ldotconfpp
+
+LIBS += -lexpat
+
+ifeq ($(OS),linux)
+LIBS += $(LIB_THREAD) \
+        -ldl
+else
+LIBS += $(LIB_THREAD) \
+        -lc
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+LDFLAGS += -Wl,-E -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-rpath-link,$(DIR_LIB) 
+vpath %.so $(DIR_LIB)
+
+.PHONY: all clean distclean libs plugins install uninstall install-bin install-data
+all: libs plugins $(PROG)
+
+libs:
+       $(MAKE) -C $(DIR_LIBSRC)
+
+plugins: libs 
+       $(MAKE) -C $(DIR_PLUGINS)
+
+$(PROG): $(OBJS) libs
+       $(CC) $(OBJS) $(LDFLAGS) $(LIBS) $(STGLIBS) -o $(PROG)
+
+clean:
+       rm -f deps $(PROG) *.o tags *.*~ .OS
+       rm -f .OS
+       rm -f .store
+       rm -f .db.sql
+       rm -f core*
+       $(MAKE) -C $(DIR_LIBSRC) clean
+       $(MAKE) -C $(DIR_PLUGINS) clean
+
+distclean: clean
+       rm -f $(DIR_MOD)/*
+       rm -f ../../Makefile.conf
+
+install: install-bin install-data
+
+install-bin:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/sbin
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) install
+       $(MAKE) -C $(DIR_PLUGINS) install
+
+install-data:
+       # Install etc
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/etc/stargazer
+       install -m $(DATA_MODE) -o $(OWNER) $(ETC_DIR)/stargazer.conf $(PREFIX)/etc/stargazer/stargazer.conf
+       install -m $(DATA_MODE) -o $(OWNER) $(ETC_DIR)/rules $(PREFIX)/etc/stargazer/rules
+       install -m $(BIN_MODE) -o $(OWNER) $(ETC_DIR)/On* $(PREFIX)/etc/stargazer/
+       
+       # Install file db
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/var/stargazer/admins
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/var/stargazer/tariffs
+       mkdir -m $(DATA_MODE) -p $(PREFIX)/var/stargazer/users/test
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/admins/admin.adm $(PREFIX)/var/stargazer/admins/admin.adm
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/tariffs/tariff.tf $(PREFIX)/var/stargazer/tariffs/tariff.tf
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/users/test/conf $(PREFIX)/var/stargazer/users/test/conf
+       install -m $(DATA_MODE) -o $(OWNER) $(VAR_DIR)/users/test/stat $(PREFIX)/var/stargazer/users/test/stat
+       
+ifeq ($(CHECK_FBCLIENT),yes)
+       # Install firebird db
+       mkdir -p $(PREFIX)/var/stargazer
+       chown $(OWNER):$(FIREBIRD_GROUP) $(PREFIX)/var/stargazer
+       chmod g+rw $(PREFIX)/var/stargazer
+       echo "connect '$(DB_ADDRESS)' user '$(DB_USER)' password '$(DB_PASSWORD)';" > .db.sql
+       echo "drop database;" >> .db.sql
+       echo "create database '$(DB_ADDRESS)' user '$(DB_USER)' password '$(DB_PASSWORD)' default character set win1251;" >> .db.sql
+       cat $(VAR_DIR)/../00-base-00.sql >> .db.sql
+       $(FIREBIRD_ISQL) -i .db.sql
+       rm -f .db.sql
+endif
+
+uninstall: uninstall-bin uninstall-data
+
+uninstall-bin:
+       rm -f $(PREFIX)/usr/sbin/$(PROG)
+       $(MAKE) -C $(DIR_LIBSRC) uninstall
+       $(MAKE) -C $(DIR_PLUGINS) uninstall
+       rm -rf $(PREFIX)/usr/lib/stg
+
+uninstall-data:
+       # Uninstall etc
+       rm -rf $(PREFIX)/etc/stargazer
+       rm -rf $(PREFIX)/var/stargazer
+
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       $(MAKE) -C $(DIR_LIBSRC) includes
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) -MM $$file` Makefile ../../Makefile.conf" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/stargazer/README b/projects/stargazer/README
new file mode 100644 (file)
index 0000000..db298b2
--- /dev/null
@@ -0,0 +1,6 @@
+éÎÓÔÁÌÑÃÉÑ É ÚÁÐÕÓË.
+1. > ./build
+2. > make install
+3. ðÒÁ×ËÁ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÈ ÆÁÊÌÏ×
+4. > stargazer
+
diff --git a/projects/stargazer/TODO b/projects/stargazer/TODO
new file mode 100644 (file)
index 0000000..6a56eb3
--- /dev/null
@@ -0,0 +1,7 @@
+1. äÏÂÁ×ÉÔØ ÐÁÒÁÍÅÔÒÙ × Á×ÔÏÒÉÚÁÔÏÒ É ËÏÎÆÉÇÕÒÁÔÏÒ HostAllow, ...
+2. äÏÂÁ×ÉÔØ ÐÁÒÁÍÅÔÒÙ × Á×ÔÏÒÉÚÁÔÏÒ FloodControl
+3. äÏÐÉÓÁÎÉÅ ÍÏÄÕÌÅÊ
+  - VPN
+4. óÅÒ×ÉÓÙ
+5. ëÏÒÐÏÒÁÃÉÉ
+6. óÔÁÒÔÏ×ÙÅ ÓËÒÉÐÔÙ ÄÌÑ ÒÁÚÎÙÈ ïó
diff --git a/projects/stargazer/actions.h b/projects/stargazer/actions.h
new file mode 100644 (file)
index 0000000..53dde92
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef __ACTIONS_H__
+#define __ACTIONS_H__
+
+// Usage:
+//
+// ACTIONS_LIST actionsList;
+// CLASS myClass;
+// DATA1 myData1;
+// DATA2 myData2;
+//
+// actionsList.Enqueue(myClass, &CLASS::myMethod1, myData1);
+// actionsList.Enqueue(myClass, &CLASS::myMethod2, myData2);
+//
+// actionsList.InvokeAll();
+
+#include <pthread.h>
+#include <list>
+#include <functional>
+
+// Generalized actor type - a method of some class with one argument
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+struct ACTOR
+{
+typedef void (ACTIVE_CLASS::*TYPE)(DATA_TYPE);
+};
+
+// Abstract base action class for polymorphic action invocation
+class BASE_ACTION
+{
+public:
+    virtual ~BASE_ACTION() {};
+    virtual void Invoke() = 0;
+};
+
+// Concrete generalized action type - an actor with it's data and owner
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+class ACTION : public BASE_ACTION,
+               public std::unary_function<ACTIVE_CLASS &, void>
+{
+public:
+    ACTION(ACTIVE_CLASS & ac,
+           typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+           DATA_TYPE d)
+        : activeClass(ac), actor(a), data(d) {};
+    void Invoke();
+private:
+    ACTIVE_CLASS & activeClass;
+    typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE actor;
+    DATA_TYPE data;
+};
+
+// A list of an actions
+// All methods are thread-safe
+class ACTIONS_LIST : private std::list<BASE_ACTION *>
+{
+public:
+    // Just a typedef for parent class
+    typedef std::list<BASE_ACTION *> parent;
+
+    // Initialize mutex
+    ACTIONS_LIST();
+    // Delete actions and destroy mutex
+    ~ACTIONS_LIST();
+
+    parent::iterator begin();
+    parent::iterator end();
+    parent::const_iterator begin() const;
+    parent::const_iterator end() const;
+
+    bool empty() const;
+    size_t size() const;
+    void swap(ACTIONS_LIST & list);
+
+    // Add an action to list
+    template <class ACTIVE_CLASS, typename DATA_TYPE>
+    void Enqueue(ACTIVE_CLASS & ac,
+                 typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+                 DATA_TYPE d);
+    // Invoke all actions in the list
+    void InvokeAll();
+private:
+    mutable pthread_mutex_t mutex;
+};
+
+#include "actions.inl.h"
+
+#endif
diff --git a/projects/stargazer/actions.inl.h b/projects/stargazer/actions.inl.h
new file mode 100644 (file)
index 0000000..c29a63c
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __ACTIONS_INL_H__
+#define __ACTIONS_INL_H__
+
+#include <algorithm>
+
+#include "stg_locker.h"
+
+// Polymorphick action invocation
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+inline
+void ACTION<ACTIVE_CLASS, DATA_TYPE>::Invoke()
+{
+(activeClass.*actor)(data);
+}
+
+inline
+ACTIONS_LIST::ACTIONS_LIST()
+    : mutex()
+{
+pthread_mutex_init(&mutex, NULL);
+};
+
+// Delete all actions before deleting list
+inline
+ACTIONS_LIST::~ACTIONS_LIST()
+{
+
+    {
+    STG_LOCKER(&mutex, __FILE__, __LINE__);
+
+    parent::iterator it(parent::begin());
+    while (it != parent::end()) 
+        {
+        delete *it++;
+        }
+    }
+
+pthread_mutex_destroy(&mutex);
+};
+
+inline
+ACTIONS_LIST::parent::iterator ACTIONS_LIST::begin()
+{ 
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return parent::begin();
+};
+
+inline
+ACTIONS_LIST::parent::iterator ACTIONS_LIST::end()
+{ 
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return parent::end();
+};
+
+inline
+ACTIONS_LIST::parent::const_iterator ACTIONS_LIST::begin() const
+{ 
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return parent::begin();
+};
+
+inline
+ACTIONS_LIST::parent::const_iterator ACTIONS_LIST::end() const
+{ 
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return parent::end();
+};
+
+inline
+bool ACTIONS_LIST::empty() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return parent::empty();
+};
+
+inline
+size_t ACTIONS_LIST::size() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return parent::size();
+};
+
+inline
+void ACTIONS_LIST::swap(ACTIONS_LIST & list)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+parent::swap(list);
+};
+
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+inline
+void ACTIONS_LIST::Enqueue(ACTIVE_CLASS & ac,
+                           typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+                           DATA_TYPE d)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+push_back(new ACTION<ACTIVE_CLASS, DATA_TYPE>(ac, a, d));
+}
+
+inline
+void ACTIONS_LIST::InvokeAll()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+std::for_each(
+        parent::begin(),
+        parent::end(),
+        std::mem_fun(&BASE_ACTION::Invoke)
+);
+};
+
+#endif
diff --git a/projects/stargazer/admin.cpp b/projects/stargazer/admin.cpp
new file mode 100644 (file)
index 0000000..867717a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.13 $
+ $Date: 2010/10/04 20:16:09 $
+ $Author: faust $
+ */
+
+#include "admin.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+ADMIN::ADMIN()
+    : conf(),
+      ip(0),
+      WriteServLog(GetStgLogger())
+{
+}
+//-----------------------------------------------------------------------------
+ADMIN::ADMIN(const ADMIN_CONF & ac)
+    : conf(ac),
+      ip(0),
+      WriteServLog(GetStgLogger())
+{
+}
+//-----------------------------------------------------------------------------
+ADMIN::ADMIN(const PRIV & priv, const std::string & login, const std::string & password)
+    : conf(priv, login, password),
+      ip(0),
+      WriteServLog(GetStgLogger())
+{
+}
+//-----------------------------------------------------------------------------
+ADMIN & ADMIN::operator=(const ADMIN & adm)
+{
+if (&adm == this)
+    return *this;
+
+conf = adm.conf;
+ip = adm.ip;
+return *this;
+}
+//-----------------------------------------------------------------------------
+ADMIN & ADMIN::operator=(const ADMIN_CONF & ac)
+{
+conf = ac;
+return *this;
+}
+//-----------------------------------------------------------------------------
+bool ADMIN::operator==(const ADMIN & rhs) const
+{
+return conf.login == rhs.GetLogin();
+}
+//-----------------------------------------------------------------------------
+bool ADMIN::operator!=(const ADMIN & rhs) const
+{
+return conf.login != rhs.GetLogin();
+}
+//-----------------------------------------------------------------------------
+bool ADMIN::operator<(const ADMIN & rhs) const
+{
+return conf.login < rhs.GetLogin();
+}
+//-----------------------------------------------------------------------------
+bool ADMIN::operator<=(const ADMIN & rhs) const
+{
+return conf.login <= rhs.GetLogin();
+}
+//-----------------------------------------------------------------------------
+string ADMIN::GetAdminIPStr() const
+{
+return inet_ntostring(ip);
+}
+//-----------------------------------------------------------------------------
+void ADMIN::PrintAdmin() const
+{
+printfd(__FILE__, "=======================================\n");
+printfd(__FILE__, "login %s\n",     conf.login.c_str());
+printfd(__FILE__, "password %s\n",  conf.password.c_str());
+printfd(__FILE__, "ChgConf %d\n",   conf.priv.userConf);
+printfd(__FILE__, "ChgStat %d\n",   conf.priv.userStat);
+printfd(__FILE__, "ChgCash %d\n",   conf.priv.userCash);
+printfd(__FILE__, "UsrAddDel %d\n", conf.priv.userAddDel);
+printfd(__FILE__, "ChgAdmin %d\n",  conf.priv.adminChg);
+printfd(__FILE__, "ChgTariff %d\n", conf.priv.tariffChg);
+printfd(__FILE__, "=======================================\n");
+}
+//-----------------------------------------------------------------------------
+const string ADMIN::GetLogStr() const
+{
+return "Admin \'" + conf.login + "\', " + GetAdminIPStr() + ":";
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/admin.h b/projects/stargazer/admin.h
new file mode 100644 (file)
index 0000000..45979ab
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.14 $
+ $Date: 2010/10/04 20:15:43 $
+ $Author: faust $
+ */
+
+#ifndef ADMIN_H
+#define ADMIN_H
+
+#include <string>
+
+#include "os_int.h"
+#include "admin_conf.h"
+#include "stg_logger.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+class ADMIN
+{
+public:
+      ADMIN();
+      ADMIN(const ADMIN_CONF & ac);
+      ADMIN(const PRIV & priv,
+            const std::string & login,
+            const std::string & password);
+      ~ADMIN() {};
+
+      ADMIN &           operator=(const ADMIN &);
+      ADMIN &           operator=(const ADMIN_CONF &);
+      bool              operator==(const ADMIN & rhs) const;
+      bool              operator!=(const ADMIN & rhs) const;
+      bool              operator<(const ADMIN & rhs) const;
+      bool              operator<=(const ADMIN & rhs) const;
+
+      const string &    GetPassword() const { return conf.password; };
+      const string &    GetLogin() const { return conf.login; };
+      PRIV const *      GetPriv() const { return &conf.priv; };
+      uint16_t          GetPrivAsInt() const { return conf.priv.ToInt(); };
+      const ADMIN_CONF & GetConf() const { return conf; };
+      void              PrintAdmin() const;
+      uint32_t          GetAdminIP() const { return ip; };
+      string            GetAdminIPStr() const;
+      void              SetAdminIP(uint32_t ip) { ADMIN::ip = ip; };
+      const string      GetLogStr() const;
+
+private:
+      ADMIN_CONF        conf;
+      uint32_t          ip;
+      STG_LOGGER &      WriteServLog;
+};
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/projects/stargazer/admins.cpp b/projects/stargazer/admins.cpp
new file mode 100644 (file)
index 0000000..4e89c9f
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.15 $
+ $Date: 2010/10/04 20:17:12 $
+ $Author: faust $
+ */
+
+#include <cerrno>
+#include <cassert>
+#include <algorithm>
+
+#include "admins.h"
+#include "admin.h"
+#include "common.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+ADMINS::ADMINS(BASE_STORE * st)
+    : stg(0xFFFF, "@stargazer", ""),
+      noAdmin(0xFFFF, "NO-ADMIN", ""),
+      data(),
+      store(st),
+      WriteServLog(GetStgLogger()),
+      searchDescriptors(),
+      handle(0)
+{
+pthread_mutex_init(&mutex, NULL);
+ReadAdmins();
+}
+//-----------------------------------------------------------------------------
+int ADMINS::Add(const string & login, const ADMIN & admin)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->adminChg)
+    {
+    string s = admin.GetLogStr() + " Add administrator \'" + login + "\'. Access denied.";
+    strError = "Access denied.";
+    WriteServLog(s.c_str());
+    return -1;
+    }
+
+ADMIN adm(0, login, "");
+admin_iter ai(find(data.begin(), data.end(), adm));
+
+if (ai != data.end())
+    {
+    strError = "Administrator \'" + login + "\' cannot not be added. Administrator alredy exist.";
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+
+    return -1;
+    }
+
+data.push_back(adm);
+/*ADMIN_CONF ac;
+ac.login = login;*/
+if (store->AddAdmin(login) == 0 /*&& store->SaveAdmin(ac) == 0*/)
+    {
+    WriteServLog("%s Administrator \'%s\' added.",
+                 admin.GetLogStr().c_str(), login.c_str());
+    return 0;
+    }
+
+strError = "Administrator \'" + login + "\' was not added. Error: " + store->GetStrError();
+WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+int ADMINS::Del(const string & login, const ADMIN & admin)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+ADMIN adm(0, login, "");
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->adminChg)
+    {
+    string s = admin.GetLogStr() + " Delete administrator \'" + login + "\'. Access denied.";
+    strError = "Access denied.";
+    WriteServLog(s.c_str());
+    return -1;
+    }
+
+admin_iter ai(find(data.begin(), data.end(), adm));
+
+if (ai == data.end())
+    {
+    strError = "Administrator \'" + login + "\' cannot be deleted. Administrator does not exist.";
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+    return -1;
+    }
+
+map<int, const_admin_iter>::iterator si;
+si = searchDescriptors.begin();
+while (si != searchDescriptors.end())
+    {
+    if (si->second == ai)
+        (si->second)++;
+    si++;
+    }
+
+data.remove(*ai);
+if (store->DelAdmin(login) < 0)
+    {
+    strError = "Administrator \'" + login + "\' was not deleted. Error: " + store->GetStrError();
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+
+    return -1;
+    }
+
+WriteServLog("%s Administrator \'%s\' deleted.", admin.GetLogStr().c_str(), login.c_str());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ADMINS::Change(const ADMIN_CONF & ac, const ADMIN & admin)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->adminChg)
+    {
+    string s = admin.GetLogStr() + " Change administrator \'" + ac.login + "\'. Access denied.";
+    strError = "Access denied.";
+    WriteServLog(s.c_str());
+    return -1;
+    }
+
+ADMIN adm(0, ac.login, "");
+admin_iter ai(find(data.begin(), data.end(), adm));
+
+if (ai == data.end())
+    {
+    strError = "Administrator \'" + ac.login + "\' cannot be changed " + ". Administrator does not exist.";
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+    return -1;
+    }
+
+*ai = ac;
+if (store->SaveAdmin(ac))
+    {
+    WriteServLog("Cannot write admin %s.", ac.login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    return -1;
+    }
+
+WriteServLog("%s Administrator \'%s\' changed.",
+             admin.GetLogStr().c_str(), ac.login.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ADMINS::ReadAdmins()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+vector<string> adminsList;
+if (store->GetAdminsList(&adminsList) < 0)
+    {
+    WriteServLog(store->GetStrError().c_str());
+    return -1;
+    }
+
+for (unsigned int i = 0; i < adminsList.size(); i++)
+    {
+    ADMIN_CONF ac(0, adminsList[i], "");
+
+    if (store->RestoreAdmin(&ac, adminsList[i]))
+        {
+        WriteServLog(store->GetStrError().c_str());
+        return -1;
+        }
+
+    data.push_back(ADMIN(ac));
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void ADMINS::PrintAdmins() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+const_admin_iter ai(data.begin());
+while (ai != data.end())
+    {
+    ai->PrintAdmin();
+    ai++;
+    }
+}
+//-----------------------------------------------------------------------------
+bool ADMINS::FindAdmin(const string & l, ADMIN * admin) const
+{
+assert(admin != NULL && "Pointer to admin is not null");
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (data.empty())
+    {
+    printfd(__FILE__, "no admin in system!\n");
+    *admin = noAdmin;
+    return false;
+    }
+
+ADMIN adm(0, l, "");
+const_admin_iter ai(find(data.begin(), data.end(), adm));
+
+if (ai != data.end())
+    {
+    *admin = *ai;
+    return false;
+    }
+
+return true;
+}
+//-----------------------------------------------------------------------------
+bool ADMINS::AdminExists(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (data.empty())
+    {
+    printfd(__FILE__, "no admin in system!\n");
+    return true;
+    }
+
+ADMIN adm(0, login, "");
+const_admin_iter ai(find(data.begin(), data.end(), adm));
+
+if (ai != data.end())
+    return true;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool ADMINS::AdminCorrect(const string & login, const std::string & password, ADMIN * admin) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (data.empty())
+    {
+    printfd(__FILE__, "no admin in system!\n");
+    return true;
+    }
+
+ADMIN adm(0, login, "");
+const_admin_iter ai(find(data.begin(), data.end(), adm));
+
+if (ai == data.end())
+    {
+    return false;
+    }
+
+if (ai->GetPassword() != password)
+    {
+    return false;
+    }
+
+*admin = *ai;
+
+return true;
+}
+//-----------------------------------------------------------------------------
+int ADMINS::OpenSearch() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+handle++;
+searchDescriptors[handle] = data.begin();
+return handle;
+}
+//-----------------------------------------------------------------------------
+int ADMINS::SearchNext(int h, ADMIN_CONF * ac) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (searchDescriptors.find(h) == searchDescriptors.end())
+    {
+    WriteServLog("ADMINS. Incorrect search handle.");
+    return -1;
+    }
+
+if (searchDescriptors[h] == data.end())
+    return -1;
+
+ADMIN a = *searchDescriptors[h]++;
+
+*ac = a.GetConf();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ADMINS::CloseSearch(int h) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (searchDescriptors.find(h) != searchDescriptors.end())
+    {
+    searchDescriptors.erase(searchDescriptors.find(h));
+    return 0;
+    }
+
+WriteServLog("ADMINS. Incorrect search handle.");
+return -1;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/admins.h b/projects/stargazer/admins.h
new file mode 100644 (file)
index 0000000..3e04ebd
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Date: 27.10.2002
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.10 $
+ $Date: 2010/10/04 20:17:12 $
+ $Author: faust $
+ */
+
+#ifndef ADMINS_H
+#define ADMINS_H
+
+#include <pthread.h>
+#include <list>
+#include <map>
+
+#include "admin.h"
+#include "stg_locker.h"
+#include "base_store.h"
+#include "noncopyable.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+class ADMINS : private NONCOPYABLE
+{
+public:
+    ADMINS(BASE_STORE * st);
+    ~ADMINS() {};
+
+    int             Add(const string & login, const ADMIN & admin);
+    int             Del(const string & login, const ADMIN & admin);
+    int             Change(const ADMIN_CONF & ac, const ADMIN & admin);
+    void            PrintAdmins() const;
+    const ADMIN     GetSysAdmin() const { return stg; };
+    const ADMIN     GetNoAdmin() const { return noAdmin; };
+    bool            FindAdmin(const string & l, ADMIN * admin) const;
+    bool            AdminExists(const std::string & login) const;
+    bool            AdminCorrect(const std::string & login,
+                                 const std::string & password,
+                                 ADMIN * admin) const;
+    const string &  GetStrError() { return strError; };
+
+    int OpenSearch() const;
+    int SearchNext(int, ADMIN_CONF * ac) const;
+    int CloseSearch(int) const;
+
+private:
+    typedef list<ADMIN>::iterator admin_iter;
+    typedef list<ADMIN>::const_iterator const_admin_iter;
+
+    int             ReadAdmins();
+
+    ADMIN           stg;
+    ADMIN           noAdmin;
+    list<ADMIN>     data;
+    BASE_STORE *    store;
+    STG_LOGGER &    WriteServLog;
+    mutable map<int, const_admin_iter> searchDescriptors;
+    mutable unsigned int handle;
+    mutable pthread_mutex_t mutex;
+    string          strError;
+};
+//-----------------------------------------------------------------------------
+#endif
+
+
diff --git a/projects/stargazer/build b/projects/stargazer/build
new file mode 100755 (executable)
index 0000000..3d4b1f9
--- /dev/null
@@ -0,0 +1,413 @@
+    #!/bin/sh
+
+#   $Revision: 1.57 $
+#   $Author: faust $
+#   $Date: 2010/05/09 12:39:01 $
+######################################################
+
+# Installation path prefix
+
+PREFIX=""
+
+# Binaries access bits
+
+BIN_MODE=0755
+
+# Data files access bits
+
+DATA_MODE=0644
+
+# Binaries and data files owner
+
+OWNER=root
+
+# Name of the firebird's group
+# Need for chown directory with firebird db
+
+FIREBIRD_GROUP=firebird
+
+# Database address
+# Firebird must have priviledges to read/write for specified path
+
+DB_ADDRESS="localhost:/var/stargazer/stargazer.fdb"
+
+# Database user
+# This user must have priviledges to create database
+
+DB_USER="stg"
+
+# Database password
+
+DB_PASSWORD="123456"
+
+# Full path to isql utility
+# Note: Debian users have to specify path to isql-fb utility
+
+FIREBIRD_ISQL="/opt/firebird/bin/isql"
+
+OS=unknown
+sys=`uname -s`
+release=`uname -r | cut -b1`
+BUILD_DIR=`pwd`
+CONFFILE="../../Makefile.conf"
+VAR_DIR="./inst/var/stargazer"
+MIN_XMLRPCC_VERSION="1.06.27"
+XMLRPC_FEATURES="c++2 abyss-server"
+
+
+if [ -z $1 ]
+then
+    DEFS="$DEFS -DNDEBUG"
+    MAKEOPTS="-j1"
+else
+    if [ "$1" = "debug" ]
+    then
+        DEFS="$DEFS -DDEBUG"
+        MAKEOPTS="-j1"
+        CXXFLAGS="$CXXFLAGS -g3 -W -Wall"
+    else
+        DEFS="$DEFS -DNDEBUG"
+        MAKEOPTS="-j1"
+    fi
+fi
+
+CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+
+if [ "$sys" = "Linux" ]
+then
+    OS=linux
+    release=""
+    ETC_DIR="./inst/linux/etc/stargazer"
+    MAKE="make"
+fi
+
+if [ "$sys" = "FreeBSD" ]
+then
+    case $release in
+        4) OS=bsd;;
+        5) OS=bsd5;;
+        6) OS=bsd5;;
+        7) OS=bsd7;;
+        8) OS=bsd7;;
+        *) OS=unknown;;
+    esac
+    ETC_DIR="./inst/freebsd/etc/stargazer"
+    MAKE="gmake"
+fi
+
+if [ "$OS" = "unknown" ]
+then 
+    echo "#############################################################################"
+    echo "# Sorry, but stargazer currently supported by Linux, FreeBSD 4.x, 5.x, 6.x  #"
+    echo "#############################################################################"
+    exit 1
+fi
+
+echo "#############################################################################"
+echo "       Building STG 2.4 for $sys $release"
+echo "#############################################################################"
+
+STG_LIBS="stg_logger.lib 
+          stg_locker.lib
+         crypto.lib 
+         common.lib 
+         script_executer.lib 
+         conffiles.lib
+          hostallow.lib 
+         pinger.lib 
+         dotconfpp.lib"
+
+PLUGINS="authorization/ao
+         authorization/inetaccess
+         configuration/sgconfig
+         other/ping
+         other/rscript
+         other/radius
+         store/files
+         capture/cap_nf"
+
+if [ "$OS" = "linux" ]
+then
+    DEFS="$DEFS -DLINUX"
+    PLUGINS="$PLUGINS
+             capture/ether_linux
+             capture/ipq_linux"
+    SHELL="/bin/bash"
+    LIB_THREAD=-lpthread
+else
+    if [ "$OS" = "bsd" ]
+    then
+        DEFS="$DEFS -DFREE_BSD"
+        LIB_THREAD=-lc_r
+    else
+        DEFS="$DEFS -DFREE_BSD5"
+        if [ "$OS" = "bsd7" ]
+        then
+            LIB_THREAD=-lpthread
+        else
+            LIB_THREAD=-lc_r
+        fi
+    fi
+    PLUGINS="$PLUGINS
+             capture/ether_freebsd
+             capture/divert_freebsd"
+    SHELL="/usr/local/bin/bash"
+fi
+
+echo -n "Checking endianess... "
+echo "int main() { int probe = 0x00000001; return *(char *)&probe; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    echo "FAIL!"
+    echo "Endianess checking failed"
+    exit;
+else
+    ./fake
+    if [ $? = 1 ]
+    then
+        ARCH=le
+        CXXFLAGS="$CXXFLAGS -DARCH_LE"
+        echo "Little Endian"
+    else
+        ARCH=be
+        CXXFLAGS="$CXXFLAGS -DARCH_BE"
+        echo "Big Endian"
+    fi
+fi
+rm -f fake
+
+echo -n "Checking for -lexpat... "
+echo "int main() { return 0; }" > build_check.c
+gcc $CXXFLAGS $LDFLAGS build_check.c -lexpat -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_EXPAT=no
+    echo "no"
+else
+    CHECK_EXPAT=yes
+    echo "yes"
+fi
+rm -f fake
+
+echo -n "Checking for -lfbclient... "
+gcc $CXXFLAGS $LDFLAGS build_check.c -lfbclient $LIB_THREAD -o fake > /dev/null 2> /dev/null
+if [ $? != 0 ]
+then
+    CHECK_FBCLIENT=no
+    echo "no"
+else
+    CHECK_FBCLIENT=yes
+    echo "yes"
+fi
+rm -f fake
+
+echo -n "Checking for mysql_config... "
+MYSQL_VERSION=`mysql_config --version 2> /dev/null`
+if [ $? != 0 ]
+then
+    echo "no";
+    echo -n "Checking for -lmysqlclient... "
+    gcc $CXXFLAGS $LDFLAGS build_check.c -lmysqlclient_r $LIB_THREAD -o fake > /dev/null 2> /dev/null
+    if [ $? != 0 ]
+    then
+        CHECK_MYSQLCLIENT=no
+        echo "no"
+    else
+        CHECK_MYSQLCLIENT=yes
+        echo "yes"
+    fi
+    rm -f fake
+else
+    echo "yes"
+    echo -n "Checking for mysql_config --cflags... "
+    MYSQL_CFLAGS=`mysql_config --cflags 2> /dev/null`
+    if [ $? != 0 ]
+    then
+        CHECK_MYSQLCLIENT=no
+        echo "no"
+    else
+        #CXXFLAGS="$CXXFLAGS $MYSQL_CFLAGS"
+        echo "[$MYSQL_CFLAGS]"
+        echo -n "Checking for mysql_config --libs_r... "
+        MYSQL_LDFLAGS=`mysql_config --libs_r 2> /dev/null`
+        if [ $? != 0 ]
+        then
+            CHECK_MYSQLCLIENT=no
+            echo "no"
+        else
+            CHECK_MYSQLCLIENT=yes
+            #LDFLAGS="$LDFLAGS $MYSQL_LDFLAGS"
+            echo "[$MYSQL_LDFLAGS]"
+        fi
+    fi
+fi
+
+echo -n "Checking for pg_config... "
+PG_VERSION=`pg_config --version 2> /dev/null`
+if [ $? != 0 ]
+then
+    echo "no";
+    echo -n "Checking for -lpq... "
+    gcc $CXXFLAGS $LDFLAGS build_check.c -lpq $LIB_THREAD -o fake > /dev/null 2> /dev/null
+    if [ $? != 0 ]
+    then
+        CHECK_PQ=no
+        echo "no"
+    else
+        CHECK_PQ=yes
+        echo "yes"
+    fi
+    rm -f fake
+else
+    echo "yes";
+    echo -n "Checking for pg_config --includedir... "
+    PG_CFLAGS=`pg_config --includedir 2> /dev/null`
+    if [ $? != 0 ]
+    then
+        CHECK_PQ=no
+        echo "no"
+    else
+        echo "[$PG_CFLAGS]"
+        echo -n "Checking for pg_config --libdir... "
+        PG_LDFLAGS=`pg_config --libdir 2> /dev/null`
+        if [ $? != 0 ]
+        then
+            CHECK_PQ=no
+            echo "no"
+        else
+            CHECK_PQ=yes
+            echo "[$PG_LDFLAGS]"
+        fi
+    fi
+fi
+
+echo -n "Checking for xmlrpc-c-config... "
+XMLRPCC_VERSION=`xmlrpc-c-config $XMLRPC_FEATURES --version 2> /dev/null`
+if [ $? != 0 ]
+then
+    echo "no";
+    echo -n "Checking for -lxmlrpc... "
+    gcc $CXXFLAGS $LDFLAGS build_check.c -lxmlrpc $LIB_THREAD -o fake > /dev/null 2> /dev/null
+    if [ $? != 0 ]
+    then
+        CHECK_XMLRPC=no
+        echo "no"
+    else
+        CHECK_XMLRPC=yes
+        echo "yes"
+    fi
+    rm -f fake
+elif [ "$XMLRPCC_VERSION" \< "$MIN_XMLRPCC_VERSION" ]
+then
+    echo "no (need at least $MIN_XMLRPCC_VERSION, actual $XMLRPCC_VERSION)";
+    CHECK_XMLRPC=no
+else
+    echo "yes (version $XMLRPCC_VERSION)";
+    echo -n "Checking for xmlrpc-c-config --cflags... "
+    XMLRPC_CFLAGS=`xmlrpc-c-config $XMLRPC_FEATURES --cflags 2> /dev/null`
+    if [ $? != 0 ]
+    then
+        CHECK_XMLRPC=no
+        echo "no"
+    else
+        echo "[$XMLRPC_CFLAGS]"
+        echo -n "Checking for xmlrpc-c-config --libs... "
+        XMLRPC_LDFLAGS=`xmlrpc-c-config $XMLRPC_FEATURES --libs 2> /dev/null`
+        if [ $? != 0 ]
+        then
+            CHECK_XMLRPC=no
+            echo "no"
+        else
+            CHECK_XMLRPC=yes
+            echo "[$XMLRPC_LDFLAGS]"
+        fi
+    fi
+fi
+
+rm -f build_check.c
+
+if [ "$CHECK_EXPAT" != "yes" ]
+then
+    echo "-lexpat not found!"
+    exit 1
+fi
+
+if [ "$CHECK_FBCLIENT" = "yes" ]
+then
+    STG_LIBS="$STG_LIBS
+              ibpp.lib"
+    PLUGINS="$PLUGINS
+             store/firebird"
+fi
+
+if [ "$CHECK_PQ" = "yes" ]
+then
+    PLUGINS="$PLUGINS
+             store/postgresql"
+fi
+
+if [ "$CHECK_MYSQLCLIENT" = "yes" ]
+then
+    PLUGINS="$PLUGINS
+             store/mysql"
+fi
+
+if [ "$CHECK_XMLRPC" = "yes" ]
+then
+    PLUGINS="$PLUGINS
+             configuration/rpcconfig"
+fi
+
+echo "OS=$OS" > $CONFFILE
+echo "STG_TIME=yes" >> $CONFFILE
+echo "DIR_BUILD=$BUILD_DIR" >> $CONFFILE
+echo "DIR_LIB=\$(DIR_BUILD)/../../lib" >> $CONFFILE
+echo "DIR_LIBSRC=\$(DIR_BUILD)/../../stglibs" >> $CONFFILE
+echo "DIR_INCLUDE=\$(DIR_BUILD)/../../include" >> $CONFFILE
+echo "DIR_MOD=\$(DIR_BUILD)/modules" >> $CONFFILE
+echo "DIR_PLUGINS=\$(DIR_BUILD)/plugins" >> $CONFFILE
+echo "ARCH=$ARCH" >> $CONFFILE
+echo "CHECK_EXPAT=$CHECK_EXPAT" >> $CONFFILE
+echo "CHECK_FBCLIENT=$CHECK_FBCLIENT" >> $CONFFILE
+echo "CHECK_MYSQLCLIENT=$CHECK_MYSQLCLIENT" >> $CONFFILE
+echo "CHECK_PQ=$CHECK_PQ" >> $CONFFILE
+echo "CHECK_XMLRPC=$CHECK_XMLRPC" >> $CONFFILE
+echo "DEFS=$DEFS" >> $CONFFILE
+echo -n "STG_LIBS=" >> $CONFFILE
+for lib in $STG_LIBS
+do
+    echo -n "$lib " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo -n "PLUGINS=" >> $CONFFILE
+for plugin in $PLUGINS
+do
+    echo -n "$plugin " >> $CONFFILE
+done
+echo "" >> $CONFFILE
+echo "SHELL=$SHELL" >> $CONFFILE
+echo "CXXFLAGS=$CXXFLAGS" >> $CONFFILE
+echo "LDFLAGS=$LDFLAGS" >> $CONFFILE
+echo "LIB_THREAD=$LIB_THREAD" >> $CONFFILE
+echo "PREFIX=$PREFIX" >> $CONFFILE
+echo "BIN_MODE=$BIN_MODE" >> $CONFFILE
+echo "DATA_MODE=$DATA_MODE" >> $CONFFILE
+echo "OWNER=$OWNER" >> $CONFFILE
+echo "VAR_DIR=$VAR_DIR" >> $CONFFILE
+echo "ETC_DIR=$ETC_DIR" >> $CONFFILE
+echo "DB_ADDRESS=$DB_ADDRESS" >> $CONFFILE
+echo "DB_USER=$DB_USER" >> $CONFFILE
+echo "DB_PASSWORD=$DB_PASSWORD" >> $CONFFILE
+echo "FIREBIRD_ISQL=$FIREBIRD_ISQL" >> $CONFFILE
+echo "FIREBIRD_GROUP=$FIREBIRD_GROUP" >> $CONFFILE
+
+mkdir -p modules
+
+if [ "$1" != "debug" ]
+then
+    $MAKE $MAKEOPTS
+else
+    echo -e "\n\n\nDebug build. Type $MAKE explicitly"
+fi
diff --git a/projects/stargazer/devbuild b/projects/stargazer/devbuild
new file mode 100755 (executable)
index 0000000..05856b2
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+export CFLAGS=-DTRAFF_STAT_WITH_PORTS
+./build debug 
+
diff --git a/projects/stargazer/eventloop.cpp b/projects/stargazer/eventloop.cpp
new file mode 100644 (file)
index 0000000..4cd6074
--- /dev/null
@@ -0,0 +1,109 @@
+#include <cerrno>
+#include <cstring>
+
+#include "eventloop.h"
+#include "stg_locker.h"
+#include "common.h"
+
+EVENT_LOOP::EVENT_LOOP()
+    : ACTIONS_LIST()
+{
+pthread_mutex_init(&_mutex, NULL);
+pthread_cond_init(&_condition, NULL);
+}
+
+EVENT_LOOP::~EVENT_LOOP()
+{
+pthread_cond_destroy(&_condition);
+pthread_mutex_destroy(&_mutex);
+}
+
+bool EVENT_LOOP::Start()
+{
+_running = true;
+if (pthread_create(&_tid, NULL, Run, this))
+    {
+    printfd(__FILE__, "EVENT_LOOP::Start - Failed to create thread: '%s'\n", strerror(errno));
+    return true;
+    }
+return false;
+}
+
+bool EVENT_LOOP::Stop()
+{
+_running = false;
+// Wake up thread
+pthread_cond_signal(&_condition);
+// Wait until thread exit
+pthread_join(_tid, NULL);
+return false;
+}
+
+void * EVENT_LOOP::Run(void * self)
+{
+EVENT_LOOP * ev = static_cast<EVENT_LOOP *>(self);
+ev->Runner();
+return NULL;
+}
+
+void EVENT_LOOP::Runner()
+{
+_stopped = false;
+printfd(__FILE__, "EVENT_LOOP::Runner - Before start\n");
+while (_running)
+    {
+        {
+        STG_LOCKER lock(&_mutex, __FILE__, __LINE__);
+        // Check for any actions...
+        if (empty())
+            {
+            // ... and sleep until new actions added
+            printfd(__FILE__, "EVENT_LOOP::Runner - Sleeping until new actions arrived\n");
+            pthread_cond_wait(&_condition, &_mutex);
+            }
+        // Check for running after wake up
+        if (!_running)
+            {
+            // Don't process any actions if stopping
+            break;
+            }
+        }
+    // Create new empty actions list
+    ACTIONS_LIST local;
+    // Fast swap with current
+    swap(local);
+    // Invoke all current actions
+    printfd(__FILE__, "EVENT_LOOP::Runner - Invoke %d actions\n", local.size());
+    local.InvokeAll();
+    }
+printfd(__FILE__, "EVENT_LOOP::Runner - Before stop\n");
+_stopped = true;
+}
+
+namespace {
+
+pthread_mutex_t singletonMutex;
+
+}
+
+EVENT_LOOP & EVENT_LOOP_SINGLETON::GetInstance()
+{
+// Double-checking technique
+if (!_instance)
+    {
+    STG_LOCKER lock(&singletonMutex, __FILE__, __LINE__);
+    if (!_instance)
+        {
+        CreateInstance();
+        }
+    }
+return *_instance;
+}
+
+void EVENT_LOOP_SINGLETON::CreateInstance()
+{
+static EVENT_LOOP loop;
+_instance = &loop;
+}
+
+EVENT_LOOP * EVENT_LOOP_SINGLETON::_instance = NULL;
diff --git a/projects/stargazer/eventloop.h b/projects/stargazer/eventloop.h
new file mode 100644 (file)
index 0000000..e1b7f6a
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef __EVENT_LOOP_H__
+#define __EVENT_LOOP_H__
+
+#include <pthread.h>
+
+#include "noncopyable.h"
+#include "actions.h"
+
+class EVENT_LOOP : private NONCOPYABLE,
+                   private ACTIONS_LIST
+{
+    public:
+        bool Start();
+        bool Stop();
+        bool IsRunning() const { return _running; };
+
+        template <class ACTIVE_CLASS, typename DATA_TYPE>
+        void Enqueue(ACTIVE_CLASS & ac,
+                     typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+                     DATA_TYPE d);
+
+    private:
+        bool _running;
+        bool _stopped;
+        pthread_t _tid;
+        pthread_mutex_t _mutex;
+        pthread_cond_t _condition;
+
+        EVENT_LOOP();
+        virtual ~EVENT_LOOP();
+
+        static void * Run(void *);
+        void Runner();
+
+        friend class EVENT_LOOP_SINGLETON;
+};
+
+class EVENT_LOOP_SINGLETON : private NONCOPYABLE
+{
+    public:
+        static EVENT_LOOP & GetInstance();
+
+    private:
+        static EVENT_LOOP * _instance;
+        static void CreateInstance();
+
+        EVENT_LOOP_SINGLETON() {};
+        ~EVENT_LOOP_SINGLETON() {};
+};
+
+template <class ACTIVE_CLASS, typename DATA_TYPE>
+void EVENT_LOOP::Enqueue(ACTIVE_CLASS & ac,
+                         typename ACTOR<ACTIVE_CLASS, DATA_TYPE>::TYPE a,
+                         DATA_TYPE d)
+{
+STG_LOCKER lock(&_mutex, __FILE__, __LINE__);
+// Add new action
+ACTIONS_LIST::Enqueue(ac, a, d);
+// Signal about new action
+pthread_cond_signal(&_condition);
+}
+
+#endif
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/OnChange b/projects/stargazer/inst/freebsd/etc/stargazer/OnChange
new file mode 100755 (executable)
index 0000000..a927228
--- /dev/null
@@ -0,0 +1,6 @@
+login=$1
+param=$2
+oldValue=$3
+newValue=$4
+
+#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
\ No newline at end of file
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/OnConnect b/projects/stargazer/inst/freebsd/etc/stargazer/OnConnect
new file mode 100755 (executable)
index 0000000..cf4abfb
--- /dev/null
@@ -0,0 +1,22 @@
+#üÔÏÔ ÓËÒÉÐÔ ×ÙÚÙ×ÁÅÔÓÑ × ÍÏÍÅÎÔ, ËÏÇÄÁ ÐÏÌØÚÏ×ÁÔÅÌØ
+#ÕÓÐÅÛÎÏ ÐÒÏÛÅÌ Á×ÔÏÒÉÚÁÃÉÀ ÎÁ ÓÅÒ×ÅÒÅ. úÁÄÁÞÁ ÓËÒÉÐÔÁ - ÐÅÒÅÓÔÒÏÉÔØ 
+#ÆÁÊÒ×ÏÌ ÔÁË, ÞÔÏ ÂÙ ÐÏÌØÚÏ×ÁÔÅÌØ ÐÏÌÕÞÉÌ ÄÏÓÔÕРנÉÎÔÅÒÎÅÔ
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+
+#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/OnDisconnect b/projects/stargazer/inst/freebsd/etc/stargazer/OnDisconnect
new file mode 100755 (executable)
index 0000000..6f5eeee
--- /dev/null
@@ -0,0 +1,27 @@
+# üÔÏÔ ÓËÒÉÐÔ ×ÙÚÙ×ÁÅÔÓÑ × ÍÏÍÅÎÔ, ËÏÇÄÁ ÐÏÌØÚÏ×ÁÔÅÌØ
+# ÖÅÌÁÅÔ ÏÔËÌÀÞÉÔÓÑ ÏÔ ÉÎÔÅÒÎÅÔÁ ÉÌÉ ×ÙÛÅÌ ÔÁÊÍÁÕÔ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ
+# É ÓÅÒ×ÅÒ ÓÁÍ ÏÔËÌÀÞÁÅÔ ÐÏÌØÚÏ×ÁÔÅÌÑ
+# úÁÄÁÞÁ ÓËÒÉÐÔÁ ÐÏÄÏÂÎÁ ÚÁÄÁÞÅ ÓËÒÉÐÔÁ OnConnect - ÐÅÒÅÓÔÒÏÉÔØ 
+# ÆÁÊÒ×ÏÌ ÔÁË, ÞÔÏ ÂÙ ÐÏÌØÚÏ×ÁÔÅÌÀ ÚÁËÒÙÔØ ÄÏÓÔÕРנÉÎÔÅÒÎÅÔ
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$4
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
+
+
+
+
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/OnUserAdd b/projects/stargazer/inst/freebsd/etc/stargazer/OnUserAdd
new file mode 100755 (executable)
index 0000000..655b0ee
--- /dev/null
@@ -0,0 +1,12 @@
+# éÓÐÏÌØÚÏ×ÁÎÉÅ (ÎÅÉÓÐÏÌØÚÏ×ÁÎÉÅ) ÜÔÏÇÏ ÓËÒÉÐÔÁ ÄÅÌÏ ×ËÕÓÁ.
+# ïΠÎÅ ×ÙÐÏÌÎÑÅÔ ËÒÉÔÉÞÅÓËÉÈ ÆÕÎËÃÉÊ. åÇÏ ÚÁÄÁÞÁ Á×ÔÍÁÔÉÚÉÒÏ×ÁÔØ
+# ÄÅÊÓÔ×ÉÑ ÈÁÒÁËÔÅÒÎÙÅ ÐÒÉ ÄÏÂÁ×ÌÅÎÉÉ ÐÏÌØÚÏ×ÁÔÅÌÑ ÓÅÔÉ, ÎÁÐÒÉÍÅÒ ÄÏÂÁ×ÌÅËÎÉÅ 
+# ÐÏÌØÚÏ×ÁÔÅÌÀ ÐÏÞÔÙ
+
+# Login
+login=$1
+
+#echo "added user $login" >> /var/stargazer/add_del.log
+
+
+
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/OnUserDel b/projects/stargazer/inst/freebsd/etc/stargazer/OnUserDel
new file mode 100755 (executable)
index 0000000..3be6046
--- /dev/null
@@ -0,0 +1,5 @@
+# Login
+login=$1
+
+#echo "deleted user $login" >> /var/stargazer/add_del.log
+
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/rules b/projects/stargazer/inst/freebsd/etc/stargazer/rules
new file mode 100644 (file)
index 0000000..1042010
--- /dev/null
@@ -0,0 +1,3 @@
+ALL     192.168.0.0/16  DIR1
+ALL     10.0.0.0/8      DIR2
+ALL     0.0.0.0/0       DIR0
\ No newline at end of file
diff --git a/projects/stargazer/inst/freebsd/etc/stargazer/stargazer.conf b/projects/stargazer/inst/freebsd/etc/stargazer/stargazer.conf
new file mode 100644 (file)
index 0000000..5276071
--- /dev/null
@@ -0,0 +1,396 @@
+################################################################################
+#                        æÁÊÌ ÎÁÓÔÒÏÅË ÓÅÒ×ÅÒÁ stargazer                       #
+################################################################################
+
+
+
+# éÍÑ ÌÏÇ-ÆÁÊÌÁ ËÕÄÁ ÐÉÛÕÔÓÑ ÓÏÂÙÔÉÑ
+LogFile = /var/log/stargazer.log
+
+
+
+# éÍÑ PID-ÆÁÊÌÁ ËÕÄÁ ÐÉÛÅÔÓÑ ÉÄÅÎÔÉÆÉËÁÔÏÒ ÐÒÏÃÅÓÓÁ
+# ðÏ ÕÍÏÌÞÁÎÉÀ /var/run/pid
+# PIDFile = /var/run/stargazer.pid
+
+
+
+# éÍÑ ÆÁÊÌÁ × ËÏÔÏÒÏÍ ÏÐÒÅÄÅÌÑÀÔÓÑ ÐÒÁ×ÉÌÁ ÐÏÄÓÞÅÔÁ ÔÒÁÆÉËÁ
+Rules = /etc/stargazer/rules
+
+
+
+# ÷ÒÅÍÑ ÞÅÒÅÚ ËÏÔÏÒÏÅ ÐÉÛÅÔÓÑ d âä ÄÅÔÁÌØÎÁÑ ÓÔÁÔÉÓÔÉËÁ ÐÏÌØÚÏ×ÁÔÅÌÑ
+# úÎÁÞÅÎÉÑ: 1, 1/2, 1/4, 1/6.
+# 1 - ÒÁÚ × ÞÁc, 1/2 - ÒÁÚ × ÐÏÌ ÞÁÓÁ, 1/4 - ÒÁÚ × 15 ÍÉÎ, 1/6 - ÒÁÚ × 10 ÍÉÎ
+DetailStatWritePeriod=1/6
+
+
+
+# ðÅÒÉÏÄÉÞÎÏÓÔØ ÚÁÐÉÓÉ ÚÁÐÉÓÉ × âä ÉÎÆÏÒÍÁÃÉÉ Ï ÓÔÁÔÉÓÔÉËÅ ÐÏÌØÚÏ×ÁÔÅÌÑ (ÍÉÎÕÔÙ)
+# ðÒÉ ÂÏÌØÛÏÍ ËÏÌ-×Å ÐÏÌØÚÏ×ÁÔÅÌÅÊ ÜÔÕ ×ÅÌÉÞÉÎÕ ÓÔÏÉÔ Õ×ÅÌÉÞÉÔØ, Ô.Ë.
+# ÚÁÐÉÓØ × âä ÍÏÖÅÔ ÚÁÎÉÍÁÔØ ÄÌÉÔÅÌØÎÏÅ ×ÒÅÍÑ.
+# úÎÁÞÅÎÉÑ: 1...1440 (ÍÉÎÕÔÙ)
+StatWritePeriod = 10
+
+
+
+# äÅÎØ ÓÎÑÔÉÑ ÁÂÏÎÐÌÁÔÙ
+# úÎÁÞÅÎÉÑ: 0...31. 0 - ðÏÓÌÅÄÎÉÊ ÄÅÎØ ÍÅÓÑÃÁ
+DayFee = 1
+
+
+
+# áÂÏÎÐÌÁÔÁ ÓÎÉÍÁÅÔÓÑ × ÐÏÓÌÅÄÎÉÊ (yes) ÉÌÉ ÐÅÒ×ÙÊ (no) ÄÅÎØ ÕÞÅÔÎÏÇÏ ÐÅÒÉÏÄÁ.
+# üÔÏ ×ÌÉÑÅÔ ÎÁ ÔÏ, ËÁË ÂÕÄÅÔ ÓÎÑÔÁ ÁÂÏÎÐÌÁÔÁ (áð) ÐÒÉ ÐÅÒÅÈÏÄÅ ÎÁ ÎÏ×ÙÊ ÔÁÒÉÆ.
+# åÓÌÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÂÙÌ ÔÁÒÉÆ A Ó áð=100 É ÏΠÈÏÞÅÔ ÐÅÒÅÊÔÉ ÎÁ ÔÁÒÉÆ B Ó áð=200,
+# ÔÏ ÐÒÉ ÐÅÒÅÈÏÄÅ ÎÁ ÎÏ×ÙÊ ÔÁÒÉÆ ÓÏ ÓÞÅÔÁ ÐÏÌØÚÏ×ÁÔÅÌÑ ÓÎÉÍÅÔÓÑ 100, ÅÓÌÉ
+# DayFeeIsLastDay = yes É 200, ÅÓÌÉ DayFeeIsLastDay = no
+DayFeeIsLastDay = yes
+
+
+
+# äÅÎØ ÓÂÒÏÓÁ ÄÁÎÎÙÈ Ï ÔÒÁÆÉËÅ ÚÁ ÍÅÓÑàɠÄÅÎØ ÐÅÒÅÈÏÄÁ ÐÏÌØÚÏ×ÁÔÅÌÅÊ ÎÁ ÎÏ×ÙÅ ÔÁÒÉÆÙ
+# úÎÁÞÅÎÉÑ: 0...31. 0 - ðÏÓÌÅÄÎÉÊ ÄÅÎØ ÍÅÓÑÃÁ
+DayResetTraff = 1
+
+
+
+# "òÁÚÍÁÚÁÎÎÏÅ" ÓÎÑÔÉÅ ÁÂÏÎÐÌÁÔÙ. óÎÑÔÉÅ áð ÎÅ ÒÁÚ × ÍÅÓÑÃ, Á ËÁÖÄÙÊ
+# ÄÅÎØ 1/30 ÉÌÉ 1/31 ÞÁÓÔÉ áð
+# úÎÁÞÅÎÉÑ: yes, no
+SpreadFee = no
+
+
+
+# äÁÎÎÁÑ ÏÐÃÉÑ ÏÐÒÅÄÅÌÑÅÔ ÍÏÖÅÔ ÌÉ ÐÏÌØÚÏ×ÁÔÅÌØ ÐÏÌÕÞÉÔØ ÄÏÓÔÕРנÉÎÔÅÒÅÎÔ
+# ÅÓÌÉ Õ ÎÅÇÏ ÎÁ ÓÞÅÔÕ ÎÅÔ ÄÅÎÅÇ, ÎÏ ÏÓÔÁÌÓÑ ÐÒÅÄÏÐÌÁÞÅÎÎÙÊ ÔÒÁÆÉË
+# úÎÁÞÅÎÉÑ: yes, no
+FreeMbAllowInet = no
+
+
+
+# üÔÁ ÏÐÃÉÑ ÏÐÒÅÄÅÌÑÅÔ ÞÔÏ ÂÕÄÅÔ ÐÉÓÁÔØÓÑ × ÓÔÏÉÍÏÓÔØ ÔÒÁÆÉËÁ × detail_stat.
+# åÓÌÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÅÝÅ ÅÓÔØ ÐÒÅÄÏÐÌÁÞÅÎÎÙÊ ÔÒÁÆÉË É WriteFreeMbTraffCost = no,
+# ÔÏ × detail_stat ÓÔÏÉÍÏÓÔØ ÂÕÄÅÔ 0. åÓÌÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÕÖÅ ÎÅÔ
+# ÐÒÅÄÏÐÌÁÞÅÎÎÏÇÏ ÔÒÁÆÉËÁ É WriteFreeMbTraffCost = no, ÔÏ × detail_stat
+# ÂÕÄÅÔ ÚÁÐÉÓÁÎÁ ÓÔÏÉÏÓÔØ ÔÒÁÆÉËÁ. ðÒÉ WriteFreeMbTraffCost = yes ÓÔÏÉÍÏÓÔØ
+# ÔÒÁÆÉËÁ ÂÕÄÅÔ ÚÁÐÉÓÁÎÁ × ÌÀÂÏÍ ÓÌÕÞÁÅ.
+WriteFreeMbTraffCost = no
+
+
+
+# îÅÏÂÑÚÁÔÅÌØÎÙÊ ÐÁÒÁÍÅÔÒ. õËÁÚÙ×ÁÅÔ ÓÎÉÍÁÔØ ÐÏÌÎÕÀ ÁÂÏÎÐÌÁÔÕ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÄÁÖÅ
+# ÅÓÌÉ ÏΠÂÙÚ ÚÁÍÏÒÏÖÅΠÔÏÌØËÏ ÞÁÓÔØ ÕÞÅÔÎÏÇÏ ÐÅÒÉÏÄÁ.
+# ðÏ ÕÍÏÌÞÁÎÉÀ ÕÓÔÁÎÏ×ÌÅΠנno
+# FullFee=no
+
+# îÅÏÂÑÚÁÔÅÌØÎÙÊ ÐÁÒÁÍÅÔÒ ÕËÁÚÙ×ÁÀÝÉÊ ÐÏËÁÚÙ×ÁÔØ ÎÁ ÓÞÅÔÕ É ÐÏÚ×ÏÌÑÔØ 
+# ÉÓÐÏÌØÚÏ×ÁÔØ ÐÏÌØÚÏ×ÁÔÅÌÀ ÁÂÏÎÐÌÁÔÕ. ðÏ ÕÍÏÌÞÁÎÉÀ ÕÓÔÁÎÏ×ÌÅΠנyes
+# ShowFeeInCash=yes
+
+
+
+# îÁÚ×ÁÎÉÑ ÎÁÐÒÁ×ÌÅÎÉÊ. îÁÐÒÁ×ÌÅÎÉÑ ÂÅÚ ÎÁÚ×ÁÎÉÊ ÎÅ ÂÕÄÕÔ ÏÔÏÂÒÁÖÁÔØÓÑ ×
+# Á×ÔÏÒÉÚÁÔÏÒÅ É ËÏÎÆÉÇÕÒÁÔÏÒÅ. îÁÚ×ÁÎÉÑ ÓÏÓÔÏÑÝÉÅ ÉÚ ÎÅÓËÏÌØËÉÈ ÓÌÏ× ÄÏÌÖÎÙ
+# ÂÙÔØ ×ÚÑÔÙ × ËÁ×ÙÞËÉ
+<DirNames>
+    DirName0 = ìÏËÁÌØ
+    DirName1 = çÏÒÏÄ
+    DirName2 = íÉÒ
+    DirName3 =
+    DirName4 =
+    DirName5 = "ìÏËÁÌØÎÙÅ ÉÇÒÙ"
+    DirName6 =
+    DirName7 =
+    DirName8 =
+    DirName9 =
+</DirNames>
+
+
+
+# ëÏÌ-×Ï ÚÁÐÕÓËÁÅÍÙÈ ÐÒÏÃÅÓÓÏ× stg-exec.
+# üÔÉ ÐÒÏÃÅÓÓÙ ÏÔ×ÅÞÁÀÔ ÚÁ ×ÙÐÏÌÎÅÎÉÅ ÓËÒÉÐÔÏ× OnConnect, OnDisconnect, ...
+# ëÏÌ-×Ï ÐÒÏÃÅÓÓÏ× ÏÚÎÁÞÁÅÔ ÓËÏÌØËÏ ÓËÒÉÐÔÏ× ÍÏÇÕÔ ×ÙÐÏÌÎÑÔÓÑ ÏÄÎÏ×ÒÅÍÅÎÎÏ.
+# úÎÁÞÅÎÉÑ: 1...1024
+ExecutersNum = 1
+
+
+
+# Message Key ÄÌÑ stg-exec.
+# éÄÅÎÔÉÆÉËÁÔÏÒ ÏÞÅÒÅÄÉ ÓÏÏÂÝÅÎÉÊ ÄÌÑ ×ÙÐÏÌÎÑÔÅÌÑ ÓËÒÉÐÔÏ×.
+# åÇÏ ÉÚÍÅÎÅÎÉÅ ÍÏÖÅÔ ÐÏÎÁÄÏÂÉÔÓÑ ÅÓÌÉ ÅÓÔØ ÎÅÏÂÈÏÄÉÍÏÓÔØ ÚÁÐÕÓÔÉÔØ ÎÅÓËÏÌØËÏ
+# ÜËÚÅÍÐÌÑÒÏ× stg. åÓÌÉ ×Ù ÎÅ ÐÏÎÉÍÁÅÔÅ, ÞÔÏ ÜÔÏ, ÎÅ ÔÒÏÇÁÊÔÅ ÜÔÏÔ ÐÁÒÁÍÅÔÒ!
+# úÎÁÞÅÎÉÑ: 0...2^32
+# úÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ: 5555
+# ExecMsgKey = 5555
+
+
+
+# ðÕÔØ Ë ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÎÁÈÏÄÑÔÓÑ ÍÏÄÕÌÉ ÓÅÒ×ÅÒÁ
+ModulesPath = /usr/lib/stg
+
+# ïÐÒÅÄÅÌÑÅÔ ÄÉÒÅËÔÏÒÉÀ, × ËÏÔÏÒÏÊ ÂÕÄÕÔ ÎÁÈÏÄÉÔÓÑ ÆÁÊÌÙ "ÍÏÎÉÔÏÒÁ"
+# ÒÁÂÏÔÙ ÓÅÒ×ÅÒÁ. ÷ ÜÔÏÊ ÄÉÒÅËÔÏÒÉÉ ÂÕÄÕÔ ÓÏÚÄÁÎÙ ÐÕÓÔÙÅ ÆÁÊÌÙ, ×ÒÅÍÑ 
+# ÍÏÄÉÆÉËÁÃÉÉ ËÏÔÏÒÙÈ ÂÕÄÅÔ ÍÅÎÑÔØÓÑ ÐÒÉÍÅÒÎÏ ÒÁÚ × ÍÉÎÕÔÕ. åÓÌÉ ËÁËÏÊ-ÔÏ 
+# ËÏÍÐÏÎÅÎÔ ÓÅÒ×ÅÒÁ ÚÁ×ÉÓÎÅÔ, ÆÁÊÌ(Ù) ÐÅÒÅÓÔÁÎÅÔ ÏÂÎÏ×ÌÑÔÓÑ, É ÐÏ ÜÔÏÍÕ 
+# ÐÒÉÚÎÁËÕ ÍÏÖÎÏ ÏÐÒÅÄÅÌÉÔØ ÓÂÏÊ × ÒÁÂÏÔÅ ÓÅÒ×ÅÒÁ É ÐÒÉ ÎÁÄÏÂÎÏÓÔÉ 
+# ÐÅÒÅÚÁÐÕÓÔÉÔØ. åÓÌÉ ÐÁÒÁÍÅÔÒ ÎÅ ÕËÁÚÁΠÉÌÉ ÐÕÓÔÏÊ, ÍÏÎÉÔÏÒÉÎÇ ÐÒÏÉÚ×ÏÄÉÔÓÑ 
+# ÎÅ ÂÕÄÅÔ. ðÁÒÁÍÅÔÒ ÎÅ Ñ×ÌÑÅÔÓÑ ÏÂÑÚÁÔÅÌØÎÙÍ, ÐÏ ÕÍÏÌÞÁÎÉÀ ÐÕÓÔÏÊ.
+# MonitorDir=/var/stargazer/monitor
+
+################################################################################
+# Store module
+# îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ ÒÁÂÏÔÁÀÝÅÇÏ Ó âä ÓÅÒ×ÅÒÁ
+
+# ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+# ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_store_files.so
+<StoreModule store_files>
+
+    # òÁÂÏÞÁÑ ÄÉÒÅËÔÏÒÉÑ ÓÅÒ×ÅÒÁ, ÔÕÔ ÓÏÄÅÒÖÁÔÓÑ ÄÁÎÎÙÅ Ï ÔÁÒÉÆÁÈ, ÐÏÌØÚÏ×ÁÔÅÌÑÈ,
+    # ÁÄÍÉÎÉÓÔÒÁÔÏÒÁÈ É Ô.Ä.
+    WorkDir = /var/stargazer
+
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÆÁÊÌÙ ÓÔÁÔÉÓÔÉËÉ (stat) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    ConfOwner = root
+    ConfGroup = wheel
+    ConfMode = 600
+
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÆÁÊÌÙ ËÏÎÆÉÇÕÒÁÃÉÉ (conf) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    StatOwner = root
+    StatGroup = wheel
+    StatMode = 640
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÌÏÇ-ÆÁÊÌÙ (log) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    UserLogOwner = root
+    UserLogGroup = wheel
+    UserLogMode = 640
+
+    # õÄÁÌÑÔØ ÒÅÚÅÒ×ÎÙÅ ËÏÐÉÉ ÐÏÓÌÅ ÕÓÐÅÛÎÏÊ ÚÁÐÉÓÉ conf/stat
+    # úÎÁÞÅÎÉÑ: yes, no
+    # ðÏ ÕÍÏÌÞÁÎÉÀ: yes
+    # RemoveBak = yes
+
+    # ÷ÏÓÓÔÁÎÁ×ÌÉ×ÁÔØ ÆÁÊÌÙ conf/stat ÉÚ ÒÅÚÅÒ×ÎÙÈ ËÏÐÉÊ ÐÒÉ ÏÛÉÂËÅ ÞÔÅÎÉÑ
+    # úÎÁÞÅÎÉÑ: yes, no
+    # ðÏ ÕÍÏÌÞÁÎÉÀ: no
+    # ReadBak = no
+
+</StoreModule>
+
+#<StoreModule store_firebird>
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    server=localhost
+#
+#    # ðÕÔØ Ë âä ÎÁ ÓÅÒ×ÅÒÅ ÉÌÉ ÅÅ ÁÌÉÁÓ
+#    database=/var/stg/stargazer.fdb
+#
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    user=stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    password=123456
+#
+#    # õÒÏ×ÅÎØ ÉÚÏÌÑÃÉÉ ÔÒÁÎÚÁÃÉÊ (ÎÅ ÏÂÑÚÁÔÅÌØÎÏ, ÐÏ ÕÍÏÌÞÁÎÉÀ oncurrency):
+#    #  concurrency
+#    #  dirtyRead
+#    #  readCommitted
+#    #  consistency
+#    isolationLevel=concurrency
+#
+#    # äÅÊÓÔ×ÉÑ ÐÒÉ ÂÌÏËÉÒÏ×ËÁÈ (ÎÅ ÏÂÑÚÁÔÅÌØÎÏ, ÐÏ ÕÍÏÌÞÁÎÉÀ wait):
+#    #  wait
+#    #  noWait
+#    lockResolution=wait
+#</StoreModule>
+
+#<StoreModule store_postgresql>
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    server=localhost
+#
+#    # éÍÑ âä
+#    database=stargazer
+#
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    user=stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    password=123456
+#</StoreModule>
+
+#<StoreModule store_mysql>
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    dbuser = stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    rootdbpass = 123456
+#
+#    # éÍÑ âä ÎÁ ÓÅÒ×ÅÒÅ
+#    dbname = stg
+#
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    dbhost = localhost
+#</StoreModule>
+
+################################################################################
+# ðÒÏÞÉÅ ÍÏÄÕÌÉ
+
+<Modules>
+
+    # îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ Á×ÔÏÒÉÚÁÃÉÉ Always Online "mod_auth_ao.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    # ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_auth_ao.so
+    <Module auth_ao>
+    </Module>
+
+
+
+    # îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ Á×ÔÏÒÉÚÁÃÉÉ InetAccess "mod_auth_ia.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    # ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_auth_ia.so
+    <Module auth_ia>
+
+        # ðÏÒÔ ÎÁ ËÏÔÏÒÏÍ ÐÒÉÎÉÍÁÀÔÓÑ ÏÂÒÁÝÅÎÉÑ ÏÔ Á×ÔÏÒÉÚÁÔÏÒÁ
+        # úÎÁÞÅÎÉÑ: 1...65534
+        Port = 5555
+
+
+        # ÷ÒÅÍÑ ÍÅÖÄÕ ÐÏÓÙÌËÁÍÉ ÚÁÐÒÏÓÁ ÐÏÌØÚÏ×ÁÔÅÌÀ ÖÉ× ÌÉ ÏÎ
+        # É ÏÂÎÏ×ÌÅÎÉÅÍ ÄÁÎÎÙÈ ÓÔÁÔÉÓÔÉËÉ (ÓÅËÕÎÄÙ)
+        # úÎÁÞÅÎÉÑ: 5...600
+        UserDelay = 15
+
+
+        #ôÁÊÍÁÕÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ. åÓÌÉ × ÔÅÞÅÎÉÅ ÜÔÏÇÏ ×ÒÅÍÅÎÉ Á×ÔÏÒÉÚÁÔÏÒ
+        #ÎÅ ÏÔ×ÅÞÁÅÔ, ÐÏÌØÚÏ×ÁÔÅÌØ ÂÕÄÅÔ ÏÔËÌÀÞÅÎ
+        # úÎÁÞÅÎÉÑ: 15...1200
+        UserTimeout = 65
+
+
+        # üÔÏÔ ÐÁÒÁÍÅÔÒ ÏÐÒÅÄÅÌÑÅÔ ÞÔÏ ÂÕÄÅÔ ÐÅÒÅÄÁ×ÁÔØÓÑ ÐÒÏÇÒÁÍÍÅ InetAccess ÏÔ ÓÅÒ×ÅÒÁ
+        # ËÁË ÏÔÓÔÁÔÏË ÐÒÅÄÏÐÌÁÞÅÎÎÏÇÏ ÔÒÁÆÉËÁ
+        # úÎÁÞÅÎÉÑ:
+        # FreeMb = 0 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÎÕÌÅ×ÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = 1 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÐÅÒ×ÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = 2 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ×ÔÏÒÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = 3 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÔÒÅÔØÅÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # ........................
+        # FreeMb = 9 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÄÅ×ÑÔÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = cash - ËÏÌ-×Ï ÄÅÎÅÇ ÎÁ ËÏÔÏÒÙÅ ÀÚÅÒ ÍÏÖÅÔ ÂÅÓÐÌÁÔÎÏ ËÁÞÁÔØ
+        # FreeMb = none - ÎÉÞÅÇÏ ÎÅ ÐÅÒÅÄÁ×ÁÔØ
+        FreeMb = cash
+
+    </Module>
+
+
+
+    # íÏÄÕÌÉ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÎÅÓËÏÌØËÏ ÒÁÚ Ó ÒÁÚÎÙÍÉ ÐÁÒÁÍÅÔÒÁÍÉ
+    #<Module auth_ia>
+    #    Port = 7777
+    #    UserDelay = 15
+    #    UserTimeout = 65
+    #    FreeMb = 0
+    #</Module>
+
+
+
+    # îÁÓÔÒÏÊËÉ ÍÏÄÕÌÑ ËÏÎÆÉÇÕÒÁÃÉÉ SgConfig "mod_conf_sg.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    <Module conf_sg>
+
+        # ðÏÒÔ ÐÏ ËÏÔÏÒÏÍÕ ÓÅÒ×ÅÒ ×ÚÁÉÍÏÄÅÊÓÔ×ÕÅÔ Ó ËÏÎÆÉÇÕÒÁÔÏÒÏÍ
+        # úÎÁÞÅÎÉÑ: 1...65535
+        Port = 5555
+
+    </Module>
+
+
+
+    # íÏÄÕÌØ ÚÁÈ×ÁÔÁ ÔÒÁÆÉËÁ "mod_cap_bpf.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    # âÅÚ ÐÁÒÁÍÅÔÒÏ×. ôÏÌØËÏ ÉÍÑ ÍÏÄÕÌÑ.
+    <Module cap_bpf>
+        # éÎÔÅÒÆÅÊÓ(Ù) ÎÁ ËÏÔÏÒÏÍ ÎÕÖÎÏ ÐÒÏÉÚ×ÏÄÉÔØ ÐÏÄÓÞÅÔ ÔÒÁÆÉËÁ
+        iface = rl0
+        iface = rl1
+        iface = dc0
+    </Module>
+
+    # íÏÄÕÌØ ÚÁÈ×ÁÔÁ ÔÒÁÆÉËÁ "mod_cap_nf.so"
+    # ðÒÉÎÉÍÁÅÔ ÉÎÆÏÒÍÁÃÉÀ Ï ÔÒÁÆÉËÅ ÐÏ ÐÒÏÔÏËÏÌÕ NetFlow
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÅÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    <Module cap_nf>
+        # TCPPort - ÐÏÒÔ ÄÌÑ TCP-ÓÏÅÄÉÎÅÎÉÊ
+        TCPPort = 42111
+
+        # UDPPort - ÐÏÒÔ ÄÌÑ UDP-ÓÏÅÄÉÎÅÎÉÊ
+        UDPPort = 42111
+
+        # íÏÇÕÔ ÉÍÅÔØ ÓÏ×ÐÁÄÁÀÝÉÅ ÚÎÁÞÅÎÉÑ.
+        # åÓÌÉ ÐÁÒÁÍÅÔÒ ÎÅ ÕËÁÚÁΠ- ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÐÏÒÔ ÎÅ "ÐÒÏÓÌÕÛÉ×ÁÅÔÓÑ".
+    </Module>
+
+
+
+    # îÁÓÔÒÏÊËÉ ÍÏÄÕÌÑ ÐÉÎÇÕÀÝÅÇÏ ÐÏÌØÚÏ×ÁÔÅÌÅÊ "mod_ping.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    <Module ping>
+
+        # ÷ÒÅÍÑ, × ÓÅËÕÎÄÁÈ, ÍÅÖÄÕ ÐÉÎÇÁÍÉ ÏÄÎÏÇÏ É ÔÏÇÏ ÖÅ ÐÏÌØÚÏ×ÁÔÅÌÑ
+        # úÎÁÞÅÎÉÑ: 10...3600
+        PingDelay = 15
+
+    </Module>
+
+#    # îÁÓÔÒÏÊËÉ ÍÏÄÕÌÑ ÄÌÑ ÕÄÁÌÅÎÎÏÇÏ ×ÙÐÏÌÎÅÎÉÑ ÓËÒÉÐÔÏ× OnCOnnect É
+#    # OnDisconnect "mod_remote_script.so"
+#    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+#    <Module remote_script>
+#
+#        # ÷ÒÅÍÑ, × ÓÅËÕÎÄÁÈ, ÍÅÖÄÕ ÐÏÓÙÌËÁÍÉ ÐÏÄÔ×ÅÒÖÄÅÎÉÊ, ÔÏÇÏ, ÞÔÏ ÐÏÌØÚÏ×ÁÔÅÌØ
+#        # ×Ó£ ÅÝÅ ÏÎÌÁÊÎ
+#        # úÎÁÞÅÎÉÑ: 10...600
+#        SendPeriod = 15
+#
+#        # óÏÏÔ×ÅÔÓÔ×ÉÅ ÐÏÄÓÅÔÅÊ, × ËÏÔÏÒÏÊ ÎÁÈÏÄÉÔÓÑ ÐÏÌØÚÏ×ÁÔÅÌØ É
+#        # ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÅÇÏ ÒÏÕÔÅÒÁ. ðÅÒ×ÁÑ ÞÁÓÔØ ÓÔÒÏËÉ - ÐÏÄÓÌÅÔØ, ÚÁÄÁÎÎÁÑ
+#        # ËÁË IP-ÁÄÒÅÓ É ÍÁÓËÁ, ÞÅÒÅÚ ÐÒÏÂÅÌ - IP-ÁÄÒÅÓ ÒÏÕÔÅÒÁ ÎÁ ËÏÔÏÒÏÍ
+#        # ÄÏÌÖÎÙ ×ÙÐÏÌÎÑÔØÓÑ ÓËÒÉÐÔÙ
+#        # îÁÐÒÉÍÅÒ ÜÔÁ ÚÁÐÉÓØ "192.168.1.0/24 192.168.1.1" ÏÚÎÁÞÁÅÔ, ÞÔÏ ÄÌÑ
+#        # ×ÓÅÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ ÉÚ ÐÏÄÓÅÔÉ 192.168.1.0/24, ÓËÒÉÐÔÙ ÂÕÄÕÔ
+#        # ×ÙÐÏÌÎÑÔØÓÑ ÎÁ ÒÏÕÔÅÒÅ Ó ÁÄÒÅÓÏÍ 192.168.1.1
+#        # Subnet0...Subnet100
+#        Subnet0 = 192.168.1.0/24 192.168.1.7
+#        Subnet1 = 192.168.2.0/24 192.168.2.5
+#        Subnet2 = 192.168.3.0/24 192.168.2.5
+#        Subnet3 = 192.168.4.0/24 192.168.2.5
+#
+#        # ðÁÒÏÌØ ÄÌÑ ÛÉÆÒÏ×ÁÎÉÑ ÐÁËÅÔÏ× ÍÅÖÄÕ stg-ÓÅÒ×ÅÒÏÍ É ÓÅÒ×ÅÒÏÍ,
+#        # ×ÙÐÏÌÎÑÀÝÉÍ ÓËÒÉÐÔÙ
+#        Password = 123456
+#
+#        # üÔÏÔ ÐÁÒÁÍÅÔÒ ÏÐÒÅÄÅÌÑÅÔ ËÁËÉÅ ÐÁÒÁÍÅÔÒÙ ÐÏÌØÚÏ×ÁÔÅÌÑ ÐÅÒÅÄÁÀÔÓÑ
+#        # ÎÁ ÕÄÁÌÅÎÎÙÊ ÓÅÒ×ÅÒ
+#        # Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName, NextTariff, Address,
+#        # Note, Group, Email, RealName, Credit, EnabledDirs, Userdata0...Userdata9
+#        UserParams=Cash Tariff EnabledDirs
+#
+#        # ðÏÒÔ ÐÏ ËÏÔÏÒÏÍÕ ÓÅÒ×ÅÒ ÏÔÓÙÌÁÅÔ ÓÏÏÂÝÅÎÉÑ ÎÁ ÒÏÕÔÅÒ
+#        # úÎÁÞÅÎÉÑ: 1...65535
+#        Port = 9999
+#
+#    </Module>
+
+#    <Module radius>
+#        Password = 123456
+#        ServerIP = 127.0.0.1
+#        Port = 6666
+#        AuthServices = Login-User
+#        AcctServices = Framed-User
+#    </Module>
+
+</Modules>
+################################################################################
+
diff --git a/projects/stargazer/inst/linux/etc/init.d/stargazer.gentoo.2007 b/projects/stargazer/inst/linux/etc/init.d/stargazer.gentoo.2007
new file mode 100755 (executable)
index 0000000..daef60b
--- /dev/null
@@ -0,0 +1,31 @@
+#!/sbin/runscript
+
+opts="reload"
+
+DAEMON=/usr/sbin/stargazer
+STARGAZER_OPTS=""
+PIDFILE=/var/run/stargazer.pid
+
+depend() {
+       need net
+}
+
+start() {
+       ebegin "Starting stargazer"
+       start-stop-daemon --start --quiet --exec ${DAEMON} -- ${STARGAZER_OPTS}
+       eend $?
+}
+
+stop() {
+       ebegin "Stopping stargazer"
+       start-stop-daemon --stop --quiet --pidfile ${PIDFILE} --retry=INT/60/KILL/5
+       rm -f ${PIDFILE}
+       eend $?
+}
+
+reload() {
+       ebegin "Reloading stargazer rules"
+       start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE
+       return 0
+       eend $?
+}
diff --git a/projects/stargazer/inst/linux/etc/init.d/stargazer.suse.9.3 b/projects/stargazer/inst/linux/etc/init.d/stargazer.suse.9.3
new file mode 100755 (executable)
index 0000000..49a50da
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/bash
+#
+# processname: stargazer
+# config: /etc/stargazer/stargazer.conf
+# pidfile: /var/run/stargazer.pid
+
+# Source function library.
+. /etc/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Source stargazer configureation.
+DAEMON=yes
+QUEUE=1h
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+[ -f /sbin/stargazer ] || exit 0
+
+RETVAL=0
+prog="stargazer"
+
+start() {
+       # Start daemons.
+
+       echo -n $"Starting $prog: "
+       /etc/stargazer/first 2> /dev/null
+       daemon /sbin/stargazer
+       RETVAL=$?
+       /etc/stargazer/last 2> /dev/null
+       echo
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/stargazer
+       return $RETVAL
+}
+
+stop() {
+       # Stop daemons.
+       echo -n $"Shutting down $prog: "
+       killproc stargazer
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/stargazer
+       return $RETVAL
+}
+
+# See how we were called.
+case "$1" in
+  start)
+       start
+       ;;
+  stop)
+       stop
+       ;;
+  restart|reload)
+       stop
+       start
+       RETVAL=$?
+       ;;
+  status)
+       status stargazer
+       RETVAL=$?
+       ;;
+  *)
+       echo $"Usage: $0 {start|stop|restart|status}"
+       exit 1
+esac
+
+exit $RETVAL
diff --git a/projects/stargazer/inst/linux/etc/init.d/stargazer.ubuntu.7.10 b/projects/stargazer/inst/linux/etc/init.d/stargazer.ubuntu.7.10
new file mode 100755 (executable)
index 0000000..a5ed971
--- /dev/null
@@ -0,0 +1,152 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          stargazer
+# Required-Start:    $local_fs $remote_fs
+# Required-Stop:     $local_fs $remote_fs
+# Default-Start:     2 3 4 5
+# Default-Stop:      S 0 1 6
+# Short-Description: Stargazer initscript
+# Description:       This file should be used to start and stop stargazer daemon
+### END INIT INFO
+
+# Author: Boris Mikhailenko <stg34@stg.dp.ua>
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/usr/sbin:/usr/bin:/sbin:/bin
+DESC="Billing system"
+NAME=stargazer
+DAEMON=/usr/sbin/$NAME
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+[ -f /etc/default/rcS ] && . /etc/default/rcS
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+       # Return
+       #   0 if daemon has been started
+       #   1 if daemon was already running
+       #   2 if daemon could not be started
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
+               || return 1
+               
+       # ps x | grep $DAEMON | grep -v grep | cut -f1 -d" " > $PIDFILE
+               
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
+               $DAEMON_ARGS \
+               || return 2
+       
+       # ps x | grep $DAEMON | grep -v grep | cut -f1 -d" " > $PIDFILE
+       # Add code here, if necessary, that waits for the process to be ready
+       # to handle requests from services started subsequently which depend
+       # on this one.  As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+       # Return
+       #   0 if daemon has been stopped
+       #   1 if daemon was already stopped
+       #   2 if daemon could not be stopped
+       #   other if a failure occurred
+       start-stop-daemon --stop --quiet --retry=INT/60/KILL/5 --pidfile $PIDFILE --name $NAME
+       RETVAL="$?"
+       [ "$RETVAL" = 2 ] && return 2
+       # Wait for children to finish too if this is a daemon that forks
+       # and if the daemon is only ever run from this initscript.
+       # If the above conditions are not satisfied then add some other code
+       # that waits for the process to drop all resources that could be
+       # needed by services started subsequently.  A last resort is to
+       # sleep for some time.
+       start-stop-daemon --stop --quiet --oknodo --retry=0/60/KILL/5 --exec $DAEMON
+       [ "$?" = 2 ] && return 2
+       # Many daemons don't delete their pidfiles when they exit.
+       rm -f $PIDFILE
+       return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+       # If the daemon can reload its configuration without
+       # restarting (for example, when it is sent a SIGHUP),
+       # then implement that here.
+       start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
+       return 0
+}
+
+case "$1" in
+  start)
+       [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+       do_start
+       case "$?" in
+               0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+               2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+       esac
+       ;;
+  stop)
+       [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+       do_stop
+       case "$?" in
+               0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+               2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+       esac
+       ;;
+  reload)
+       # If do_reload() is not implemented then leave this commented out
+       # and leave 'force-reload' as an alias for 'restart'.
+       log_daemon_msg "Reloading $DESC" "$NAME"
+       do_reload
+       log_end_msg $?
+       ;;
+  restart)
+       #
+       # If the "reload" option is implemented then remove the
+       # 'force-reload' alias
+       #
+       log_daemon_msg "Restarting $DESC" "$NAME"
+       do_stop
+       case "$?" in
+         0|1)
+               do_start
+               case "$?" in
+                       0) log_end_msg 0 ;;
+                       1) log_end_msg 1 ;; # Old process is still running
+                       *) log_end_msg 1 ;; # Failed to start
+               esac
+               ;;
+         *)
+               # Failed to stop
+               log_end_msg 1
+               ;;
+       esac
+       ;;
+  *)
+       #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+       echo "Usage: $SCRIPTNAME {start|stop|restart|reload}" >&2
+       exit 3
+       ;;
+esac
+
+:
diff --git a/projects/stargazer/inst/linux/etc/stargazer/OnChange b/projects/stargazer/inst/linux/etc/stargazer/OnChange
new file mode 100755 (executable)
index 0000000..a927228
--- /dev/null
@@ -0,0 +1,6 @@
+login=$1
+param=$2
+oldValue=$3
+newValue=$4
+
+#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
\ No newline at end of file
diff --git a/projects/stargazer/inst/linux/etc/stargazer/OnConnect b/projects/stargazer/inst/linux/etc/stargazer/OnConnect
new file mode 100755 (executable)
index 0000000..f3899d6
--- /dev/null
@@ -0,0 +1,22 @@
+#Этот скрипт вызывается в момент, когда пользователь
+#успешно прошел авторизацию на сервере. Задача скрипта - перестроить 
+#файрвол так, что бы пользователь получил доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+
+#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
diff --git a/projects/stargazer/inst/linux/etc/stargazer/OnDisconnect b/projects/stargazer/inst/linux/etc/stargazer/OnDisconnect
new file mode 100755 (executable)
index 0000000..c29a011
--- /dev/null
@@ -0,0 +1,27 @@
+# Этот скрипт вызывается в момент, когда пользователь
+# желает отключится от интернета или вышел таймаут у пользователя
+# и сервер сам отключает пользователя
+# Задача скрипта подобна задаче скрипта OnConnect - перестроить 
+# файрвол так, что бы пользователю закрыть доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$4
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
+
+
+
+
diff --git a/projects/stargazer/inst/linux/etc/stargazer/OnUserAdd b/projects/stargazer/inst/linux/etc/stargazer/OnUserAdd
new file mode 100755 (executable)
index 0000000..a3ee3a9
--- /dev/null
@@ -0,0 +1,12 @@
+# Использование (неиспользование) этого скрипта дело вкуса.
+# Он не выполняет критических функций. Его задача автматизировать
+# действия характерные при добавлении пользователя сети, например добавлекние 
+# пользователю почты
+
+# Login
+login=$1
+
+#echo "added user $login" >> /var/stargazer/add_del.log
+
+
+
diff --git a/projects/stargazer/inst/linux/etc/stargazer/OnUserDel b/projects/stargazer/inst/linux/etc/stargazer/OnUserDel
new file mode 100755 (executable)
index 0000000..3be6046
--- /dev/null
@@ -0,0 +1,5 @@
+# Login
+login=$1
+
+#echo "deleted user $login" >> /var/stargazer/add_del.log
+
diff --git a/projects/stargazer/inst/linux/etc/stargazer/rules b/projects/stargazer/inst/linux/etc/stargazer/rules
new file mode 100644 (file)
index 0000000..3fb4828
--- /dev/null
@@ -0,0 +1,3 @@
+ALL     192.168.0.0/16  DIR1 
+ALL     10.0.0.0/8      DIR2
+ALL     0.0.0.0/0       DIR0
\ No newline at end of file
diff --git a/projects/stargazer/inst/linux/etc/stargazer/stargazer.conf b/projects/stargazer/inst/linux/etc/stargazer/stargazer.conf
new file mode 100644 (file)
index 0000000..52e70e9
--- /dev/null
@@ -0,0 +1,394 @@
+################################################################################
+#                        æÁÊÌ ÎÁÓÔÒÏÅË ÓÅÒ×ÅÒÁ stargazer                       #
+################################################################################
+
+
+
+# éÍÑ ÌÏÇ-ÆÁÊÌÁ ËÕÄÁ ÐÉÛÕÔÓÑ ÓÏÂÙÔÉÑ
+LogFile = /var/log/stargazer.log
+
+
+
+# éÍÑ PID-ÆÁÊÌÁ ËÕÄÁ ÐÉÛÅÔÓÑ ÉÄÅÎÔÉÆÉËÁÔÏÒ ÐÒÏÃÅÓÓÁ
+# ðÏ ÕÍÏÌÞÁÎÉÀ /var/run/pid
+# PIDFile = /var/run/stargazer.pid
+
+
+
+# éÍÑ ÆÁÊÌÁ × ËÏÔÏÒÏÍ ÏÐÒÅÄÅÌÑÀÔÓÑ ÐÒÁ×ÉÌÁ ÐÏÄÓÞÅÔÁ ÔÒÁÆÉËÁ
+Rules = /etc/stargazer/rules
+
+
+
+# ÷ÒÅÍÑ ÞÅÒÅÚ ËÏÔÏÒÏÅ ÐÉÛÅÔÓÑ d âä ÄÅÔÁÌØÎÁÑ ÓÔÁÔÉÓÔÉËÁ ÐÏÌØÚÏ×ÁÔÅÌÑ
+# úÎÁÞÅÎÉÑ: 1, 1/2, 1/4, 1/6.
+# 1 - ÒÁÚ × ÞÁc, 1/2 - ÒÁÚ × ÐÏÌ ÞÁÓÁ, 1/4 - ÒÁÚ × 15 ÍÉÎ, 1/6 - ÒÁÚ × 10 ÍÉÎ
+DetailStatWritePeriod=1/6
+
+
+
+# ðÅÒÉÏÄÉÞÎÏÓÔØ ÚÁÐÉÓÉ ÚÁÐÉÓÉ × âä ÉÎÆÏÒÍÁÃÉÉ Ï ÓÔÁÔÉÓÔÉËÅ ÐÏÌØÚÏ×ÁÔÅÌÑ (ÍÉÎÕÔÙ)
+# ðÒÉ ÂÏÌØÛÏÍ ËÏÌ-×Å ÐÏÌØÚÏ×ÁÔÅÌÅÊ ÜÔÕ ×ÅÌÉÞÉÎÕ ÓÔÏÉÔ Õ×ÅÌÉÞÉÔØ, Ô.Ë.
+# ÚÁÐÉÓØ × âä ÍÏÖÅÔ ÚÁÎÉÍÁÔØ ÄÌÉÔÅÌØÎÏÅ ×ÒÅÍÑ.
+# úÎÁÞÅÎÉÑ: 1...1440 (ÍÉÎÕÔÙ)
+StatWritePeriod = 10
+
+
+
+# äÅÎØ ÓÎÑÔÉÑ ÁÂÏÎÐÌÁÔÙ
+# úÎÁÞÅÎÉÑ: 0...31. 0 - ðÏÓÌÅÄÎÉÊ ÄÅÎØ ÍÅÓÑÃÁ
+DayFee = 1
+
+
+
+# áÂÏÎÐÌÁÔÁ ÓÎÉÍÁÅÔÓÑ × ÐÏÓÌÅÄÎÉÊ (yes) ÉÌÉ ÐÅÒ×ÙÊ (no) ÄÅÎØ ÕÞÅÔÎÏÇÏ ÐÅÒÉÏÄÁ.
+# üÔÏ ×ÌÉÑÅÔ ÎÁ ÔÏ, ËÁË ÂÕÄÅÔ ÓÎÑÔÁ ÁÂÏÎÐÌÁÔÁ (áð) ÐÒÉ ÐÅÒÅÈÏÄÅ ÎÁ ÎÏ×ÙÊ ÔÁÒÉÆ.
+# åÓÌÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÂÙÌ ÔÁÒÉÆ A Ó áð=100 É ÏΠÈÏÞÅÔ ÐÅÒÅÊÔÉ ÎÁ ÔÁÒÉÆ B Ó áð=200,
+# ÔÏ ÐÒÉ ÐÅÒÅÈÏÄÅ ÎÁ ÎÏ×ÙÊ ÔÁÒÉÆ ÓÏ ÓÞÅÔÁ ÐÏÌØÚÏ×ÁÔÅÌÑ ÓÎÉÍÅÔÓÑ 100, ÅÓÌÉ
+# DayFeeIsLastDay = yes É 200, ÅÓÌÉ DayFeeIsLastDay = no
+DayFeeIsLastDay = yes
+
+
+
+# äÅÎØ ÓÂÒÏÓÁ ÄÁÎÎÙÈ Ï ÔÒÁÆÉËÅ ÚÁ ÍÅÓÑàɠÄÅÎØ ÐÅÒÅÈÏÄÁ ÐÏÌØÚÏ×ÁÔÅÌÅÊ ÎÁ ÎÏ×ÙÅ ÔÁÒÉÆÙ
+# úÎÁÞÅÎÉÑ: 0...31. 0 - ðÏÓÌÅÄÎÉÊ ÄÅÎØ ÍÅÓÑÃÁ
+DayResetTraff = 1
+
+
+
+# "òÁÚÍÁÚÁÎÎÏÅ" ÓÎÑÔÉÅ ÁÂÏÎÐÌÁÔÙ. óÎÑÔÉÅ áð ÎÅ ÒÁÚ × ÍÅÓÑÃ, Á ËÁÖÄÙÊ
+# ÄÅÎØ 1/30 ÉÌÉ 1/31 ÞÁÓÔÉ áð
+# úÎÁÞÅÎÉÑ: yes, no
+SpreadFee = no
+
+
+
+# äÁÎÎÁÑ ÏÐÃÉÑ ÏÐÒÅÄÅÌÑÅÔ ÍÏÖÅÔ ÌÉ ÐÏÌØÚÏ×ÁÔÅÌØ ÐÏÌÕÞÉÔØ ÄÏÓÔÕРנÉÎÔÅÒÅÎÔ
+# ÅÓÌÉ Õ ÎÅÇÏ ÎÁ ÓÞÅÔÕ ÎÅÔ ÄÅÎÅÇ, ÎÏ ÏÓÔÁÌÓÑ ÐÒÅÄÏÐÌÁÞÅÎÎÙÊ ÔÒÁÆÉË
+# úÎÁÞÅÎÉÑ: yes, no
+FreeMbAllowInet = no
+
+
+
+# üÔÁ ÏÐÃÉÑ ÏÐÒÅÄÅÌÑÅÔ ÞÔÏ ÂÕÄÅÔ ÐÉÓÁÔØÓÑ × ÓÔÏÉÍÏÓÔØ ÔÒÁÆÉËÁ × detail_stat.
+# åÓÌÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÅÝÅ ÅÓÔØ ÐÒÅÄÏÐÌÁÞÅÎÎÙÊ ÔÒÁÆÉË É WriteFreeMbTraffCost = no,
+# ÔÏ × detail_stat ÓÔÏÉÍÏÓÔØ ÂÕÄÅÔ 0. åÓÌÉ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÕÖÅ ÎÅÔ
+# ÐÒÅÄÏÐÌÁÞÅÎÎÏÇÏ ÔÒÁÆÉËÁ É WriteFreeMbTraffCost = no, ÔÏ × detail_stat
+# ÂÕÄÅÔ ÚÁÐÉÓÁÎÁ ÓÔÏÉÏÓÔØ ÔÒÁÆÉËÁ. ðÒÉ WriteFreeMbTraffCost = yes ÓÔÏÉÍÏÓÔØ
+# ÔÒÁÆÉËÁ ÂÕÄÅÔ ÚÁÐÉÓÁÎÁ × ÌÀÂÏÍ ÓÌÕÞÁÅ.
+WriteFreeMbTraffCost = no
+
+
+
+# îÅÏÂÑÚÁÔÅÌØÎÙÊ ÐÁÒÁÍÅÔÒ. õËÁÚÙ×ÁÅÔ ÓÎÉÍÁÔØ ÐÏÌÎÕÀ ÁÂÏÎÐÌÁÔÕ Õ ÐÏÌØÚÏ×ÁÔÅÌÑ ÄÁÖÅ
+# ÅÓÌÉ ÏΠÂÙÚ ÚÁÍÏÒÏÖÅΠÔÏÌØËÏ ÞÁÓÔØ ÕÞÅÔÎÏÇÏ ÐÅÒÉÏÄÁ.
+# ðÏ ÕÍÏÌÞÁÎÉÀ ÕÓÔÁÎÏ×ÌÅΠנno
+# FullFee=no
+
+# îÅÏÂÑÚÁÔÅÌØÎÙÊ ÐÁÒÁÍÅÔÒ ÕËÁÚÙ×ÁÀÝÉÊ ÐÏËÁÚÙ×ÁÔØ ÎÁ ÓÞÅÔÕ É ÐÏÚ×ÏÌÑÔØ 
+# ÉÓÐÏÌØÚÏ×ÁÔØ ÐÏÌØÚÏ×ÁÔÅÌÀ ÁÂÏÎÐÌÁÔÕ. ðÏ ÕÍÏÌÞÁÎÉÀ ÕÓÔÁÎÏ×ÌÅΠנyes
+# ShowFeeInCash=yes
+
+
+
+# îÁÚ×ÁÎÉÑ ÎÁÐÒÁ×ÌÅÎÉÊ. îÁÐÒÁ×ÌÅÎÉÑ ÂÅÚ ÎÁÚ×ÁÎÉÊ ÎÅ ÂÕÄÕÔ ÏÔÏÂÒÁÖÁÔØÓÑ ×
+# Á×ÔÏÒÉÚÁÔÏÒÅ É ËÏÎÆÉÇÕÒÁÔÏÒÅ. îÁÚ×ÁÎÉÑ ÓÏÓÔÏÑÝÉÅ ÉÚ ÎÅÓËÏÌØËÉÈ ÓÌÏ× ÄÏÌÖÎÙ
+# ÂÙÔØ ×ÚÑÔÙ × ËÁ×ÙÞËÉ
+<DirNames>
+    DirName0 = ìÏËÁÌØ
+    DirName1 = çÏÒÏÄ
+    DirName2 = íÉÒ
+    DirName3 =
+    DirName4 =
+    DirName5 = "ìÏËÁÌØÎÙÅ ÉÇÒÙ"
+    DirName6 =
+    DirName7 =
+    DirName8 =
+    DirName9 =
+</DirNames>
+
+
+
+# ëÏÌ-×Ï ÚÁÐÕÓËÁÅÍÙÈ ÐÒÏÃÅÓÓÏ× stg-exec.
+# üÔÉ ÐÒÏÃÅÓÓÙ ÏÔ×ÅÞÁÀÔ ÚÁ ×ÙÐÏÌÎÅÎÉÅ ÓËÒÉÐÔÏ× OnConnect, OnDisconnect, ...
+# ëÏÌ-×Ï ÐÒÏÃÅÓÓÏ× ÏÚÎÁÞÁÅÔ ÓËÏÌØËÏ ÓËÒÉÐÔÏ× ÍÏÇÕÔ ×ÙÐÏÌÎÑÔÓÑ ÏÄÎÏ×ÒÅÍÅÎÎÏ.
+# úÎÁÞÅÎÉÑ: 1...1024
+ExecutersNum = 1
+
+
+
+# Message Key ÄÌÑ stg-exec.
+# éÄÅÎÔÉÆÉËÁÔÏÒ ÏÞÅÒÅÄÉ ÓÏÏÂÝÅÎÉÊ ÄÌÑ ×ÙÐÏÌÎÑÔÅÌÑ ÓËÒÉÐÔÏ×.
+# åÇÏ ÉÚÍÅÎÅÎÉÅ ÍÏÖÅÔ ÐÏÎÁÄÏÂÉÔÓÑ ÅÓÌÉ ÅÓÔØ ÎÅÏÂÈÏÄÉÍÏÓÔØ ÚÁÐÕÓÔÉÔØ ÎÅÓËÏÌØËÏ
+# ÜËÚÅÍÐÌÑÒÏ× stg. åÓÌÉ ×Ù ÎÅ ÐÏÎÉÍÁÅÔÅ, ÞÔÏ ÜÔÏ, ÎÅ ÔÒÏÇÁÊÔÅ ÜÔÏÔ ÐÁÒÁÍÅÔÒ!
+# úÎÁÞÅÎÉÑ: 0...2^32
+# úÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ: 5555
+# ExecMsgKey = 5555
+
+
+
+# ðÕÔØ Ë ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÎÁÈÏÄÑÔÓÑ ÍÏÄÕÌÉ ÓÅÒ×ÅÒÁ
+ModulesPath = /usr/lib/stg
+
+# ïÐÒÅÄÅÌÑÅÔ ÄÉÒÅËÔÏÒÉÀ, × ËÏÔÏÒÏÊ ÂÕÄÕÔ ÎÁÈÏÄÉÔÓÑ ÆÁÊÌÙ "ÍÏÎÉÔÏÒÁ"
+# ÒÁÂÏÔÙ ÓÅÒ×ÅÒÁ. ÷ ÜÔÏÊ ÄÉÒÅËÔÏÒÉÉ ÂÕÄÕÔ ÓÏÚÄÁÎÙ ÐÕÓÔÙÅ ÆÁÊÌÙ, ×ÒÅÍÑ 
+# ÍÏÄÉÆÉËÁÃÉÉ ËÏÔÏÒÙÈ ÂÕÄÅÔ ÍÅÎÑÔØÓÑ ÐÒÉÍÅÒÎÏ ÒÁÚ × ÍÉÎÕÔÕ. åÓÌÉ ËÁËÏÊ-ÔÏ 
+# ËÏÍÐÏÎÅÎÔ ÓÅÒ×ÅÒÁ ÚÁ×ÉÓÎÅÔ, ÆÁÊÌ(Ù) ÐÅÒÅÓÔÁÎÅÔ ÏÂÎÏ×ÌÑÔÓÑ, É ÐÏ ÜÔÏÍÕ 
+# ÐÒÉÚÎÁËÕ ÍÏÖÎÏ ÏÐÒÅÄÅÌÉÔØ ÓÂÏÊ × ÒÁÂÏÔÅ ÓÅÒ×ÅÒÁ É ÐÒÉ ÎÁÄÏÂÎÏÓÔÉ 
+# ÐÅÒÅÚÁÐÕÓÔÉÔØ. åÓÌÉ ÐÁÒÁÍÅÔÒ ÎÅ ÕËÁÚÁΠÉÌÉ ÐÕÓÔÏÊ, ÍÏÎÉÔÏÒÉÎÇ ÐÒÏÉÚ×ÏÄÉÔÓÑ 
+# ÎÅ ÂÕÄÅÔ. ðÁÒÁÍÅÔÒ ÎÅ Ñ×ÌÑÅÔÓÑ ÏÂÑÚÁÔÅÌØÎÙÍ, ÐÏ ÕÍÏÌÞÁÎÉÀ ÐÕÓÔÏÊ.
+# MonitorDir=/var/stargazer/monitor
+
+
+################################################################################
+# Store module
+# îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ ÒÁÂÏÔÁÀÝÅÇÏ Ó âä ÓÅÒ×ÅÒÁ
+
+# ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+# ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_store_files.so
+<StoreModule store_files>
+
+    # òÁÂÏÞÁÑ ÄÉÒÅËÔÏÒÉÑ ÓÅÒ×ÅÒÁ, ÔÕÔ ÓÏÄÅÒÖÁÔÓÑ ÄÁÎÎÙÅ Ï ÔÁÒÉÆÁÈ, ÐÏÌØÚÏ×ÁÔÅÌÑÈ,
+    # ÁÄÍÉÎÉÓÔÒÁÔÏÒÁÈ É Ô.Ä.
+    WorkDir = /var/stargazer
+
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÆÁÊÌÙ ÓÔÁÔÉÓÔÉËÉ (stat) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    ConfOwner = root
+    ConfGroup = root
+    ConfMode = 600
+
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÆÁÊÌÙ ËÏÎÆÉÇÕÒÁÃÉÉ (conf) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    StatOwner = root
+    StatGroup = root
+    StatMode = 640
+
+    # ÷ÌÁÄÅÌÅÃ, ÇÒÕÐÐÁ É ÐÒÁ×Á ÄÏÓÔÕÐÁ ÎÁ ÌÏÇ-ÆÁÊÌÙ (log) ÐÏÌØÚÏ×ÁÔÅÌÑ
+    UserLogOwner = root
+    UserLogGroup = root
+    UserLogMode = 640
+
+    # õÄÁÌÑÔØ ÒÅÚÅÒ×ÎÙÅ ËÏÐÉÉ ÐÏÓÌÅ ÕÓÐÅÛÎÏÊ ÚÁÐÉÓÉ conf/stat
+    # úÎÁÞÅÎÉÑ: yes, no
+    # ðÏ ÕÍÏÌÞÁÎÉÀ: yes
+    # RemoveBak = yes
+
+    # ÷ÏÓÓÔÁÎÁ×ÌÉ×ÁÔØ ÆÁÊÌÙ conf/stat ÉÚ ÒÅÚÅÒ×ÎÙÈ ËÏÐÉÊ ÐÒÉ ÏÛÉÂËÅ ÞÔÅÎÉÑ
+    # úÎÁÞÅÎÉÑ: yes, no
+    # ðÏ ÕÍÏÌÞÁÎÉÀ: no
+    # ReadBak = no
+
+</StoreModule>
+
+#<StoreModule store_firebird>
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    server=localhost
+#
+#    # ðÕÔØ Ë âä ÎÁ ÓÅÒ×ÅÒÅ ÉÌÉ ÅÅ ÁÌÉÁÓ
+#    database=/var/stg/stargazer.fdb
+#
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    user=stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    password=123456
+#
+#    # õÒÏ×ÅÎØ ÉÚÏÌÑÃÉÉ ÔÒÁÎÚÁÃÉÊ (ÎÅ ÏÂÑÚÁÔÅÌØÎÏ, ÐÏ ÕÍÏÌÞÁÎÉÀ oncurrency):
+#    #  concurrency
+#    #  dirtyRead
+#    #  readCommitted
+#    #  consistency
+#    isolationLevel=concurrency
+#
+#    # äÅÊÓÔ×ÉÑ ÐÒÉ ÂÌÏËÉÒÏ×ËÁÈ (ÎÅ ÏÂÑÚÁÔÅÌØÎÏ, ÐÏ ÕÍÏÌÞÁÎÉÀ wait):
+#    #  wait
+#    #  noWait
+#    lockResolution=wait
+#</StoreModule>
+
+#<StoreModule store_postgresql>
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    server=localhost
+#
+#    # éÍÑ âä
+#    database=stargazer
+#
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    user=stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    password=123456
+#</StoreModule>
+
+#<StoreModule store_mysql>
+#    # éÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    dbuser = stg
+#
+#    # ðÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ âä
+#    rootdbpass = 123456
+#
+#    # éÍÑ âä ÎÁ ÓÅÒ×ÅÒÅ
+#    dbname = stg
+#
+#    # áÄÒÅÓ ÓÅÒ×ÅÒÁ âä
+#    dbhost = localhost
+#</StoreModule>
+
+################################################################################
+# ðÒÏÞÉÅ ÍÏÄÕÌÉ
+
+<Modules>
+
+    # îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ Á×ÔÏÒÉÚÁÃÉÉ Always Online "mod_auth_ao.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    # ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_auth_ao.so
+    <Module auth_ao>
+    </Module>
+
+
+
+    # îÁÓÔÒÏÊËÉ ÐÌÁÇÉÎÁ Á×ÔÏÒÉÚÁÃÉÉ InetAccess "mod_auth_ia.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    # ô.Å. ÐÏÌÎÏÅ ÉÍÑ ÍÏÄÕÌÑ mod_auth_ia.so
+    <Module auth_ia>
+
+        # ðÏÒÔ ÎÁ ËÏÔÏÒÏÍ ÐÒÉÎÉÍÁÀÔÓÑ ÏÂÒÁÝÅÎÉÑ ÏÔ Á×ÔÏÒÉÚÁÔÏÒÁ
+        # úÎÁÞÅÎÉÑ: 1...65534
+        Port = 5555
+
+
+        # ÷ÒÅÍÑ ÍÅÖÄÕ ÐÏÓÙÌËÁÍÉ ÚÁÐÒÏÓÁ ÐÏÌØÚÏ×ÁÔÅÌÀ ÖÉ× ÌÉ ÏÎ
+        # É ÏÂÎÏ×ÌÅÎÉÅÍ ÄÁÎÎÙÈ ÓÔÁÔÉÓÔÉËÉ (ÓÅËÕÎÄÙ)
+        # úÎÁÞÅÎÉÑ: 5...600
+        UserDelay = 15
+
+
+        #ôÁÊÍÁÕÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ. åÓÌÉ × ÔÅÞÅÎÉÅ ÜÔÏÇÏ ×ÒÅÍÅÎÉ Á×ÔÏÒÉÚÁÔÏÒ
+        #ÎÅ ÏÔ×ÅÞÁÅÔ, ÐÏÌØÚÏ×ÁÔÅÌØ ÂÕÄÅÔ ÏÔËÌÀÞÅÎ
+        # úÎÁÞÅÎÉÑ: 15...1200
+        UserTimeout = 65
+
+
+        # üÔÏÔ ÐÁÒÁÍÅÔÒ ÏÐÒÅÄÅÌÑÅÔ ÞÔÏ ÂÕÄÅÔ ÐÅÒÅÄÁ×ÁÔØÓÑ ÐÒÏÇÒÁÍÍÅ InetAccess ÏÔ ÓÅÒ×ÅÒÁ
+        # ËÁË ÏÔÓÔÁÔÏË ÐÒÅÄÏÐÌÁÞÅÎÎÏÇÏ ÔÒÁÆÉËÁ
+        # úÎÁÞÅÎÉÑ:
+        # FreeMb = 0 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÎÕÌÅ×ÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = 1 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÐÅÒ×ÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = 2 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ×ÔÏÒÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = 3 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÔÒÅÔØÅÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # ........................
+        # FreeMb = 9 - ËÏÌ-×Ï ÂÅÓÐÌÁÔÎÙÈ ÍÅÇÁÂÁÊÔ × ÐÒÅÓÞÅÔÅ ÎÁ ÃÅÎÕ ÄÅ×ÑÔÏÇÏ ÎÁÐÒÁ×ÌÅÎÉÑ
+        # FreeMb = cash - ËÏÌ-×Ï ÄÅÎÅÇ ÎÁ ËÏÔÏÒÙÅ ÀÚÅÒ ÍÏÖÅÔ ÂÅÓÐÌÁÔÎÏ ËÁÞÁÔØ
+        # FreeMb = none - ÎÉÞÅÇÏ ÎÅ ÐÅÒÅÄÁ×ÁÔØ
+        FreeMb = cash
+
+    </Module>
+
+
+
+    # íÏÄÕÌÉ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÎÅÓËÏÌØËÏ ÒÁÚ Ó ÒÁÚÎÙÍÉ ÐÁÒÁÍÅÔÒÁÍÉ
+    #<Module auth_ia>
+    #    Port = 7777
+    #    UserDelay = 15
+    #    UserTimeout = 65
+    #    FreeMb = 0
+    #</Module>
+
+
+
+    # îÁÓÔÒÏÊËÉ ÍÏÄÕÌÑ ËÏÎÆÉÇÕÒÁÃÉÉ SgConfig "mod_conf_sg.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    <Module conf_sg>
+
+        # ðÏÒÔ ÐÏ ËÏÔÏÒÏÍÕ ÓÅÒ×ÅÒ ×ÚÁÉÍÏÄÅÊÓÔ×ÕÅÔ Ó ËÏÎÆÉÇÕÒÁÔÏÒÏÍ
+        # úÎÁÞÅÎÉÑ: 1...65535
+        Port = 5555
+
+    </Module>
+
+
+
+    # íÏÄÕÌØ ÚÁÈ×ÁÔÁ ÔÒÁÆÉËÁ "mod_cap_ether.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÅÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    # âÅÚ ÐÁÒÁÍÅÔÒÏ×. ôÏÌØËÏ ÉÍÑ ÍÏÄÕÌÑ.
+    <Module cap_ether>
+        # íÏÄÕÌØ ÂÅÚ ÐÁÒÁÍÅÔÒÏ×
+    </Module>
+
+    # íÏÄÕÌØ ÚÁÈ×ÁÔÁ ÔÒÁÆÉËÁ "mod_cap_nf.so"
+    # ðÒÉÎÉÍÁÅÔ ÉÎÆÏÒÍÁÃÉÀ Ï ÔÒÁÆÉËÅ ÐÏ ÐÒÏÔÏËÏÌÕ NetFlow
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÅÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    <Module cap_nf>
+        # TCPPort - ÐÏÒÔ ÄÌÑ TCP-ÓÏÅÄÉÎÅÎÉÊ
+        TCPPort = 42111
+
+        # UDPPort - ÐÏÒÔ ÄÌÑ UDP-ÓÏÅÄÉÎÅÎÉÊ
+        UDPPort = 42111
+
+        # íÏÇÕÔ ÉÍÅÔØ ÓÏ×ÐÁÄÁÀÝÉÅ ÚÎÁÞÅÎÉÑ.
+        # åÓÌÉ ÐÁÒÁÍÅÔÒ ÎÅ ÕËÁÚÁΠ- ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÐÏÒÔ ÎÅ "ÐÒÏÓÌÕÛÉ×ÁÅÔÓÑ".
+    </Module>
+
+
+
+    # îÁÓÔÒÏÊËÉ ÍÏÄÕÌÑ ÐÉÎÇÕÀÝÅÇÏ ÐÏÌØÚÏ×ÁÔÅÌÅÊ "mod_ping.so"
+    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+    <Module ping>
+
+        # ÷ÒÅÍÑ, × ÓÅËÕÎÄÁÈ, ÍÅÖÄÕ ÐÉÎÇÁÍÉ ÏÄÎÏÇÏ É ÔÏÇÏ ÖÅ ÐÏÌØÚÏ×ÁÔÅÌÑ
+        # úÎÁÞÅÎÉÑ: 10...3600
+        PingDelay = 15
+
+    </Module>
+
+#    # îÁÓÔÒÏÊËÉ ÍÏÄÕÌÑ ÄÌÑ ÕÄÁÌÅÎÎÏÇÏ ×ÙÐÏÌÎÅÎÉÑ ÓËÒÉÐÔÏ× OnConnect É
+#    # OnDisconnect "mod_remote_script.so"
+#    # ÷ÔÏÒÏÊ ÐÁÒÁÍÅÔÒ - ÜÔÏ ÉÍÑ ÍÏÄÕÌÑ ÂÅÚ mod_ × ÎÁÞÁÌÅ É .so × ËÏÎÃÅ
+#    <Module remote_script>
+#
+#        # ÷ÒÅÍÑ, × ÓÅËÕÎÄÁÈ, ÍÅÖÄÕ ÐÏÓÙÌËÁÍÉ ÐÏÄÔ×ÅÒÖÄÅÎÉÊ, ÔÏÇÏ, ÞÔÏ ÐÏÌØÚÏ×ÁÔÅÌØ
+#        # ×Ó£ ÅÝÅ ÏÎÌÁÊÎ
+#        # úÎÁÞÅÎÉÑ: 10...600
+#        SendPeriod = 15
+#
+#        # óÏÏÔ×ÅÔÓÔ×ÉÅ ÐÏÄÓÅÔÅÊ, × ËÏÔÏÒÏÊ ÎÁÈÏÄÉÔÓÑ ÐÏÌØÚÏ×ÁÔÅÌØ É
+#        # ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÅÇÏ ÒÏÕÔÅÒÁ. ðÅÒ×ÁÑ ÞÁÓÔØ ÓÔÒÏËÉ - ÐÏÄÓÅÔØ, ÚÁÄÁÎÎÁÑ
+#        # ËÁË IP-ÁÄÒÅÓ É ÍÁÓËÁ, ÞÅÒÅÚ ÐÒÏÂÅÌ - IP-ÁÄÒÅÓ ÒÏÕÔÅÒÁ ÎÁ ËÏÔÏÒÏÍ
+#        # ÄÏÌÖÎÙ ×ÙÐÏÌÎÑÔØÓÑ ÓËÒÉÐÔÙ
+#        # îÁÐÒÉÍÅÒ ÜÔÁ ÚÁÐÉÓØ "192.168.1.0/24 192.168.1.1" ÏÚÎÁÞÁÅÔ, ÞÔÏ ÄÌÑ
+#        # ×ÓÅÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ ÉÚ ÐÏÄÓÅÔÉ 192.168.1.0/24, ÓËÒÉÐÔÙ ÂÕÄÕÔ
+#        # ×ÙÐÏÌÎÑÔØÓÑ ÎÁ ÒÏÕÔÅÒÅ Ó ÁÄÒÅÓÏÍ 192.168.1.1
+#        # Subnet0...Subnet100
+#        Subnet0 = 192.168.1.0/24 192.168.1.7
+#        Subnet1 = 192.168.2.0/24 192.168.2.5
+#        Subnet2 = 192.168.3.0/24 192.168.2.5
+#        Subnet3 = 192.168.4.0/24 192.168.2.5
+#
+#        # ðÁÒÏÌØ ÄÌÑ ÛÉÆÒÏ×ÁÎÉÑ ÐÁËÅÔÏ× ÍÅÖÄÕ stg-ÓÅÒ×ÅÒÏÍ É ÓÅÒ×ÅÒÏÍ,
+#        # ×ÙÐÏÌÎÑÀÝÉÍ ÓËÒÉÐÔÙ
+#        Password = 123456
+#
+#        # üÔÏÔ ÐÁÒÁÍÅÔÒ ÏÐÒÅÄÅÌÑÅÔ ËÁËÉÅ ÐÁÒÁÍÅÔÒÙ ÐÏÌØÚÏ×ÁÔÅÌÑ ÐÅÒÅÄÁÀÔÓÑ
+#        # ÎÁ ÕÄÁÌÅÎÎÙÊ ÓÅÒ×ÅÒ
+#        # Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName, NextTariff, Address,
+#        # Note, Group, Email, RealName, Credit, EnabledDirs, Userdata0...Userdata9
+#        UserParams=Cash Tariff EnabledDirs
+#
+#        # ðÏÒÔ ÐÏ ËÏÔÏÒÏÍÕ ÓÅÒ×ÅÒ ÏÔÓÙÌÁÅÔ ÓÏÏÂÝÅÎÉÑ ÎÁ ÒÏÕÔÅÒ
+#        # úÎÁÞÅÎÉÑ: 1...65535
+#        Port = 9999
+#
+#    </Module>
+
+#    <Module radius>
+#        Password = 123456
+#        ServerIP = 127.0.0.1
+#        Port = 6666
+#        AuthServices = Login-User
+#        AcctServices = Framed-User
+#    </Module>
+
+</Modules>
+################################################################################
+
diff --git a/projects/stargazer/inst/var/00-alter-01.postgresql.sql b/projects/stargazer/inst/var/00-alter-01.postgresql.sql
new file mode 100644 (file)
index 0000000..7fd8111
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  DB migration from v00 to v01 (postgres)
+ */
+
+ALTER TABLE tb_sessions_log ADD free_mb dm_money;
+ALTER TABLE tb_sessions_log ADD reason TEXT;
+
+DROP FUNCTION sp_add_session_log_entry ( dm_name, timestamp without time zone, dm_session_event_type, inet, dm_money);
+
+CREATE FUNCTION sp_add_session_log_entry(_login dm_name,
+                                         _event_time TIMESTAMP,
+                                         _event_type dm_session_event_type,
+                                         _ip INET,
+                                         _cash dm_money,
+                                         _free_mb dm_money,
+                                         _reason TEXT)
+RETURNS INTEGER
+AS $$
+DECLARE
+    _pk_user INTEGER;
+    _pk_session_log INTEGER;
+BEGIN
+    SELECT pk_user INTO _pk_user
+        FROM tb_users
+        WHERE name = _login;
+    IF _pk_user IS NULL THEN
+        RAISE EXCEPTION 'User % not found', _login;
+        RETURN -1;
+    END IF;
+    
+    INSERT INTO tb_sessions_log
+        (fk_user,
+         event_time,
+         event_type,
+         ip,
+         cash,
+         free_mb,
+         reason)
+    VALUES
+        (_pk_user,
+         _event_time,
+         _event_type,
+         _ip,
+         _cash,
+         _free_mb,
+         _reason);
+
+    SELECT CURRVAL('tb_sessions_log_pk_session_log_seq') INTO _pk_session_log;
+
+    RETURN _pk_session_log;
+END;
+$$ LANGUAGE plpgsql;
+
+UPDATE tb_info SET version = 6;
diff --git a/projects/stargazer/inst/var/00-alter-01.sql b/projects/stargazer/inst/var/00-alter-01.sql
new file mode 100644 (file)
index 0000000..f76ae5f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  DB migration from v00 to v01 (firebird)
+ */
+
+alter table tb_users add disabled_detail_stat dm_bool;
+
+drop procedure sp_add_user;
+
+set term !! ;
+create procedure sp_add_user(name varchar(32), dirs integer)                             
+as  
+declare variable pk_user integer;
+declare variable pk_stat integer;                                                        
+begin                                                                                    
+    pk_user = gen_id(gn_pk_user, 1);                                                     
+    insert into tb_users(pk_user, fk_tariff, fk_tariff_change, fk_corporation, address, always_online, credit, credit_expire, disabled, disabled_detail_stat, email, grp, note, passive, passwd, phone, name, real_name) values (:pk_user, NULL, NULL, NULL, '', 0, 0, 'now', 0, 0, '', '_', '', 0, '', '', :name, '');
+    pk_stat = gen_id(gn_pk_stat, 1);                                                     
+    insert into tb_stats values (:pk_stat, :pk_user, 0, 0, 'now', 0, 'now', 0, 'now');   
+    while (dirs > 0) do
+    begin
+        insert into tb_stats_traffic (fk_stat, dir_num, upload, download) values (:pk_stat, :dirs - 1, 0, 0);
+        dirs = dirs - 1;
+    end
+end!!
+set term ; !!
diff --git a/projects/stargazer/inst/var/00-base-00.postgresql.sql b/projects/stargazer/inst/var/00-base-00.postgresql.sql
new file mode 100644 (file)
index 0000000..5ec01be
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ *    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
+ */
+
+/*
+ *****************************************************************************
+ *
+ * Скрипт генерации структуры базы для хранения данных Stargazer-a
+ *
+ * Примечание.
+ *      * dm_permission_flag. Представляет собой битовую маску - rw.
+ *          r - чтение, w - изменение параметра.
+ *          0 - дествие запрещено, 1 - действие разрешено
+ *
+ *      * dm_traff_type. Число определяющее тип подсчета трафика:
+ *          0 - up - считается по upload
+ *          1 - down - считается по download
+ *          2 - max - считается по максимальному среди upload/download
+ *          3 - up+down - считается по сумме upload и download
+ *
+ *      * dm_session_event_type. Указывает тип записи в логе о сессии.
+ *        'c' - connect, 'd' - disconnect.
+ *
+ *      * При занесении IP адресса в БД выполнять приведение к
+ *        знаковуму целому!!!
+ *
+ *****************************************************************************
+ */
+
+/*
+ *  $Revision: 1.12 $
+ *  $Date: 2009/08/20 14:58:43 $
+ */
+
+
+/*
+ *****************************************************************************
+ * -= Создание типов и доменов =-
+ *****************************************************************************
+ */
+
+CREATE DOMAIN dm_name AS VARCHAR(32) NOT NULL;
+CREATE DOMAIN dm_password AS VARCHAR(64) NOT NULL;
+CREATE DOMAIN dm_permission_flag AS SMALLINT NOT NULL
+    CHECK ( value BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_money AS NUMERIC(12, 4) NOT NULL DEFAULT 0;
+CREATE DOMAIN dm_traff_type AS SMALLINT NOT NULL
+    CHECK ( value BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_day AS SMALLINT NOT NULL
+    CHECK ( value BETWEEN 0 AND 31 )
+    DEFAULT 0;
+CREATE DOMAIN dm_session_event_type AS CHAR(1) NOT NULL
+    CHECK ( value = 'c' OR value = 'd' );
+
+/*
+ *****************************************************************************
+ * -= Создание таблиц =-
+ *****************************************************************************
+ */
+
+CREATE TABLE tb_info
+(
+    version INTEGER NOT NULL
+);
+
+CREATE TABLE tb_admins
+(
+    pk_admin SERIAL PRIMARY KEY,
+    login dm_name UNIQUE,
+    passwd dm_password NOT NULL,
+    chg_conf dm_permission_flag,
+    chg_password dm_permission_flag,
+    chg_stat dm_permission_flag,
+    chg_cash dm_permission_flag,
+    usr_add_del dm_permission_flag,
+    chg_tariff dm_permission_flag,
+    chg_admin dm_permission_flag,
+    chg_service dm_permission_flag,
+    chg_corporation dm_permission_flag
+);
+
+CREATE TABLE tb_tariffs
+(
+    pk_tariff SERIAL PRIMARY KEY,
+    name dm_name UNIQUE,
+    fee dm_money,
+    free dm_money,
+    passive_cost dm_money,
+    traff_type dm_traff_type
+);
+
+CREATE TABLE tb_tariffs_params
+(
+    pk_tariff_param SERIAL PRIMARY KEY,
+    fk_tariff INTEGER NOT NULL,
+    dir_num SMALLINT NOT NULL,
+    price_day_a dm_money,
+    price_day_b dm_money,
+    price_night_a dm_money,
+    price_night_b dm_money,
+    threshold INTEGER NOT NULL,
+    time_day_begins TIME NOT NULL,
+    time_day_ends TIME NOT NULL,
+
+    FOREIGN KEY (fk_tariff)
+        REFERENCES tb_tariffs (pk_tariff)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_corporations
+(
+    pk_corporation SERIAL PRIMARY KEY,
+    name dm_name UNIQUE,
+    cash dm_money
+);
+
+CREATE TABLE tb_users
+(
+    pk_user SERIAL PRIMARY KEY,
+    fk_tariff INTEGER,
+    fk_tariff_change INTEGER,
+    fk_corporation INTEGER,
+    address VARCHAR(256) NOT NULL,
+    always_online BOOLEAN NOT NULL,
+    credit dm_money,
+    credit_expire TIMESTAMP NOT NULL,
+    disabled BOOLEAN NOT NULL,
+    disabled_detail_stat BOOLEAN NOT NULL,
+    email VARCHAR(256) NOT NULL,
+    grp dm_name,
+    note TEXT NOT NULL,
+    passive BOOLEAN NOT NULL,
+    passwd dm_password,
+    phone VARCHAR(256) NOT NULL,
+    name dm_name UNIQUE,
+    real_name VARCHAR(256) NOT NULL,
+    cash dm_money,
+    free_mb dm_money,
+    last_activity_time TIMESTAMP NOT NULL,
+    last_cash_add dm_money,
+    last_cash_add_time TIMESTAMP NOT NULL,
+    passive_time INTEGER NOT NULL,
+
+    FOREIGN KEY (fk_tariff)
+        REFERENCES tb_tariffs (pk_tariff)
+        ON DELETE CASCADE,
+    FOREIGN KEY (fk_tariff_change)
+        REFERENCES tb_tariffs (pk_tariff)
+        ON DELETE CASCADE,
+    FOREIGN KEY (fk_corporation)
+        REFERENCES tb_corporations (pk_corporation)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_detail_stats
+(
+    pk_detail_stat BIGSERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    dir_num SMALLINT NOT NULL,
+    ip INET NOT NULL,
+    download BIGINT NOT NULL,
+    upload BIGINT NOT NULL,
+    cost dm_money,
+    from_time TIMESTAMP NOT NULL,
+    till_time TIMESTAMP NOT NULL,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_services
+(
+    pk_service SERIAL PRIMARY KEY,
+    name dm_name UNIQUE,
+    comment TEXT NOT NULL,
+    cost dm_money,
+    pay_day dm_day
+);
+
+CREATE TABLE tb_users_services
+(
+    pk_user_service SERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    fk_service INTEGER NOT NULL,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE,
+    FOREIGN KEY (fk_service)
+        REFERENCES tb_services (pk_service)
+);
+
+CREATE TABLE tb_messages
+(
+    pk_message SERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    ver SMALLINT NOT NULL,
+    msg_type SMALLINT NOT NULL,
+    last_send_time TIMESTAMP NOT NULL,
+    creation_time TIMESTAMP NOT NULL,
+    show_time INTEGER NOT NULL,
+    repeat SMALLINT NOT NULL,
+    repeat_period INTEGER NOT NULL,
+    msg_text TEXT NOT NULL,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_stats_traffic
+(
+    pk_stat_traffic BIGSERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    stats_date DATE NOT NULL,
+    dir_num SMALLINT NOT NULL,
+    download BIGINT NOT NULL,
+    upload BIGINT NOT NULL,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE,
+    UNIQUE (fk_user, stats_date, dir_num)
+);
+
+CREATE TABLE tb_users_data
+(
+    pk_user_data SERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    num SMALLINT NOT NULL,
+    data VARCHAR(256) NOT NULL,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_allowed_ip
+(
+    pk_allowed_ip SERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    ip INET NOT NULL,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_sessions_log
+(
+    pk_session_log SERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    event_time TIMESTAMP NOT NULL,
+    event_type dm_session_event_type,
+    ip INET NOT NULL,
+    cash dm_money,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_sessions_data
+(
+    pk_session_data SERIAL PRIMARY KEY,
+    fk_session_log INTEGER NOT NULL,
+    dir_num SMALLINT NOT NULL,
+    session_upload BIGINT NOT NULL,
+    session_download BIGINT NOT NULL,
+    month_upload BIGINT NOT NULL,
+    month_download BIGINT NOT NULL,
+
+    FOREIGN KEY (fk_session_log)
+        REFERENCES tb_sessions_log (pk_session_log)
+        ON DELETE CASCADE
+);
+
+CREATE TABLE tb_parameters
+(
+    pk_parameter SERIAL PRIMARY KEY,
+    name dm_name UNIQUE
+);
+
+CREATE TABLE tb_params_log
+(
+    pk_param_log SERIAL PRIMARY KEY,
+    fk_user INTEGER NOT NULL,
+    fk_parameter INTEGER NOT NULL,
+    fk_admin INTEGER NOT NULL,
+    ip INET NOT NULL,
+    event_time TIMESTAMP NOT NULL,
+    from_val VARCHAR(256),
+    to_val VARCHAR(256),
+    comment TEXT,
+
+    FOREIGN KEY (fk_user)
+        REFERENCES tb_users (pk_user)
+        ON DELETE CASCADE,
+    FOREIGN KEY (fk_parameter)
+        REFERENCES tb_parameters (pk_parameter),
+    FOREIGN KEY (fk_admin)
+        REFERENCES tb_admins (pk_admin)
+        ON DELETE CASCADE
+);
+
+/*
+ *****************************************************************************
+ * -= Создание хранимых процедур =-
+ *****************************************************************************
+ */
+
+CREATE FUNCTION sp_add_message(_login dm_name,
+                               _ver SMALLINT,
+                               _msg_type SMALLINT,
+                               _last_send_time TIMESTAMP,
+                               _creation_time TIMESTAMP,
+                               _show_time INTEGER,
+                               _repeat SMALLINT,
+                               _repeat_period INTEGER,
+                               _msg_text TEXT)
+RETURNS INTEGER
+AS $$
+DECLARE
+    _pk_user INTEGER;
+BEGIN
+    SELECT pk_user INTO _pk_user
+        FROM tb_users
+        WHERE name = _login;
+    IF _pk_user IS NULL THEN
+        RAISE EXCEPTION 'User % not found', _login;
+        RETURN -1;
+    END IF;
+    INSERT INTO tb_messages
+        (fk_user,
+         ver,
+         msg_type,
+         last_send_time,
+         creation_time,
+         show_time,
+         repeat,
+         repeat_period,
+         msg_text)
+    VALUES
+        (_pk_user,
+         _ver,
+         _msg_type,
+         _last_send_time,
+         _creation_time,
+         _show_time,
+         _repeat,
+         _repeat_period,
+         _msg_text);
+    RETURN CURRVAL('tb_messages_pk_message_seq');
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_tariff(_name dm_name, _dirs INTEGER)
+RETURNS INTEGER
+AS $$
+DECLARE
+    pk_tariff INTEGER;
+BEGIN
+    INSERT INTO tb_tariffs
+        (name,
+         fee,
+         free,
+         passive_cost,
+         traff_type)
+    VALUES
+        (_name,
+         0, 0, 0, 0);
+    SELECT CURRVAL('tb_tariffs_pk_tariff_seq') INTO pk_tariff;
+    FOR i IN 1.._dirs LOOP
+        INSERT INTO tb_tariffs_params
+            (fk_tariff,
+             dir_num,
+             price_day_a,
+             price_day_b,
+             price_night_a,
+             price_night_b,
+             threshold,
+             time_day_begins,
+             time_day_ends)
+        VALUES
+            (pk_tariff,
+             i - 1,
+             0, 0, 0, 0, 0,
+             CAST('1970-01-01 00:00:00+00' AS TIMESTAMP),
+             CAST('1970-01-01 00:00:00+00' AS TIMESTAMP));
+    END LOOP;
+    RETURN pk_tariff;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_user(_name dm_name)
+RETURNS INTEGER
+AS $$
+DECLARE
+    pk_user INTEGER;
+BEGIN
+    INSERT INTO tb_users
+        (fk_tariff,
+         fk_tariff_change,
+         fk_corporation,
+         address,
+         always_online,
+         credit,
+         credit_expire,
+         disabled,
+         disabled_detail_stat,
+         email,
+         grp,
+         note,
+         passive,
+         passwd,
+         phone,
+         name,
+         real_name,
+         cash,
+         free_mb,
+         last_activity_time,
+         last_cash_add,
+         last_cash_add_time,
+         passive_time)
+    VALUES
+        (NULL, NULL, NULL, '', FALSE, 0, CAST('now' AS TIMESTAMP),
+         FALSE, FALSE, '', '', '', FALSE, '', '', _name, '', 0, 0,
+         CAST('now' AS TIMESTAMP), 0, CAST('now' AS TIMESTAMP), 0);
+    SELECT CURRVAL('tb_users_pk_user_seq') INTO pk_user;
+    RETURN pk_user;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_stats_traffic (_login dm_name,
+                                      _stats_date DATE,
+                                      _dir_num SMALLINT,
+                                      _upload BIGINT,
+                                      _download BIGINT)
+RETURNS INTEGER
+AS $$
+DECLARE
+    _pk_user INTEGER;
+BEGIN
+    SELECT pk_user INTO _pk_user
+        FROM tb_users
+        WHERE name = _login;
+
+    IF _pk_user IS NULL THEN
+        RAISE EXCEPTION 'User % not found', _login;
+        RETURN -1;
+    END IF;
+
+    UPDATE tb_stats_traffic SET
+        upload = _upload,
+        download = _download
+    WHERE fk_user = _pk_user AND
+          dir_num = _dir_num AND
+          stats_date = _stats_date;
+
+    IF NOT FOUND THEN
+        INSERT INTO tb_stats_traffic
+            (fk_user,
+             dir_num,
+             stats_date,
+             upload,
+             download)
+        VALUES
+            (_pk_user,
+             _dir_num,
+             _stats_date,
+             _upload,
+             _download);
+    END IF;
+
+    RETURN 1;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_set_user_data (_pk_user INTEGER,
+                                  _num SMALLINT,
+                                  _data VARCHAR(256))
+RETURNS INTEGER
+AS $$
+BEGIN
+    UPDATE tb_users_data SET
+        data = _data
+    WHERE fk_user = _pk_user AND num = _num;
+
+    IF NOT FOUND THEN
+        INSERT INTO tb_users_data
+            (fk_user,
+             num,
+             data)
+        VALUES
+            (_pk_user,
+             _num,
+             _data);
+    END IF;
+
+    RETURN 1;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_param_log_entry(_login dm_name,
+                                       _admin_login dm_name,
+                                       _ip INET,
+                                       _param_name dm_name,
+                                       _event_time TIMESTAMP,
+                                       _from VARCHAR(256),
+                                       _to VARCHAR(256),
+                                       _comment TEXT)
+RETURNS INTEGER
+AS $$
+DECLARE
+    _pk_user INTEGER;
+    _pk_admin INTEGER;
+    _pk_param INTEGER;
+BEGIN
+    SELECT pk_user INTO _pk_user
+        FROM tb_users
+        WHERE name = _login;
+    IF _pk_user IS NULL THEN
+        RAISE EXCEPTION 'User % not found', _login;
+        RETURN -1;
+    END IF;
+
+    SELECT pk_admin INTO _pk_admin
+        FROM tb_admins
+        WHERE login = _admin_login;
+    IF _pk_admin IS NULL THEN
+        RAISE EXCEPTION 'Admin % not found', _admin_login;
+        RETURN -1;
+    END IF;
+
+    SELECT pk_parameter INTO _pk_param
+        FROM tb_parameters
+        WHERE name = _param_name;
+
+    IF NOT FOUND THEN
+        INSERT INTO tb_parameters (name) VALUES (_param_name);
+        SELECT CURRVAL('tb_parameters_pk_parameter_seq') INTO _pk_param;
+    END IF;
+
+    INSERT INTO tb_params_log
+        (fk_user,
+         fk_parameter,
+         fk_admin,
+         ip,
+         event_time,
+         from_val,
+         to_val,
+         comment)
+    VALUES
+        (_pk_user,
+         _pk_param,
+         _pk_admin,
+         _ip,
+         _event_time,
+         _from,
+         _to,
+         _comment);
+
+    RETURN 1;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION sp_add_session_log_entry(_login dm_name,
+                                         _event_time TIMESTAMP,
+                                         _event_type dm_session_event_type,
+                                         _ip INET,
+                                         _cash dm_money)
+RETURNS INTEGER
+AS $$
+DECLARE
+    _pk_user INTEGER;
+    _pk_session_log INTEGER;
+BEGIN
+    SELECT pk_user INTO _pk_user
+        FROM tb_users
+        WHERE name = _login;
+    IF _pk_user IS NULL THEN
+        RAISE EXCEPTION 'User % not found', _login;
+        RETURN -1;
+    END IF;
+    
+    INSERT INTO tb_sessions_log
+        (fk_user,
+         event_time,
+         event_type,
+         ip,
+         cash)
+    VALUES
+        (_pk_user,
+         _event_time,
+         _event_type,
+         _ip,
+         _cash);
+
+    SELECT CURRVAL('tb_sessions_log_pk_session_log_seq') INTO _pk_session_log;
+
+    RETURN _pk_session_log;
+END;
+$$ LANGUAGE plpgsql;
+
+/*
+ *****************************************************************************
+ * -= Создание администратора =-
+ *
+ * Двоичные права доступа пока не поддерживаются, по этому используются флаги
+ *****************************************************************************
+ */
+INSERT INTO tb_admins
+    (login, passwd,
+     chg_conf, chg_password, chg_stat,
+     chg_cash, usr_add_del, chg_tariff,
+     chg_admin, chg_service, chg_corporation)
+VALUES
+    ('admin',
+     'geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmk',
+     1, 1, 1, 1, 1, 1, 1, 1, 1);
+
+INSERT INTO tb_info
+    (version)
+VALUES
+    (5);
diff --git a/projects/stargazer/inst/var/00-base-00.sql b/projects/stargazer/inst/var/00-base-00.sql
new file mode 100644 (file)
index 0000000..4047bc1
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ *    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
+ */
+
+/*
+ *****************************************************************************
+ *
+ * Скрипт генерации структуры базы для хранения данных Stargazer-a
+ *
+ * $Id: 00-base-00.sql,v 1.7 2010/01/06 14:41:13 faust Exp $
+ *
+ * Примечание.
+ *      * dm_permission_flag. Представляет собой битовую маску - rw.
+ *          r - чтение, w - изменение параметра.
+ *          0 - дествие запрещено, 1 - действие разрешено
+ *
+ *      * dm_traff_type. Число определяющее тип подсчета трафика:
+ *          0 - up - считается по upload
+ *          1 - down - считается по download
+ *          2 - max - считается по максимальному среди upload/download
+ *          3 - up+down - считается по сумме upload и download
+ *        Как альтернативу этому полю можно сделать еще одну таблицу - типов
+ *        подсчета трафика. И в этом поле хранить ссылку на эту таблицу.
+ *        Вопрос только "А надо ли это?"
+ *
+ *      * dm_ip. IP адресс в виде четырех байтового целого числа со знаком.
+ *        Выполнять приведение к знаковуму целому при занесении IP в БД!!!
+ *
+ *      * dm_period. Задает периодичность показа сообщения пользователю.
+ *        Период задается целым числом (int16). Если значение равно 0 то
+ *        сообщение показывается только при подключении пользователя.
+ *        Также этот домен определяет промежуток времени в течении которого
+ *        сообщение показывается пользователю.
+ *
+ *      * dm_session_event_type. Указывает тип записи в логе о сессии.
+ *        'c' - connect, 'd' - disconnect.
+ *
+ *****************************************************************************
+ */
+
+/*
+ * CONNECT 'localhost:/var/stg/stargazer.fdb' USER 'stg' PASSWORD '123456';
+ * DROP DATABASE;
+ *
+ * CREATE DATABASE 'localhost:/var/stg/stargazer.fdb' USER 'stg' PASSWORD '123456' DEFAULT CHARACTER SET UTF8;
+ */
+
+
+/*
+ *****************************************************************************
+ * -= Создание ДОМЕНОВ =-
+ *****************************************************************************
+ */
+
+CREATE DOMAIN dm_id AS INTEGER NOT NULL;
+CREATE DOMAIN dm_null_id AS INTEGER;
+CREATE DOMAIN dm_login AS VARCHAR(32) NOT NULL;
+CREATE DOMAIN dm_tariff_name AS VARCHAR(32) NOT NULL;
+CREATE DOMAIN dm_group_name AS VARCHAR(32);
+CREATE DOMAIN dm_corporation_name AS VARCHAR(32);
+CREATE DOMAIN dm_parameter_name AS VARCHAR(32);
+
+CREATE DOMAIN dm_password AS VARCHAR(64) NOT NULL;
+/* bitmask - rw => Read, Write */
+CREATE DOMAIN dm_permission_flag AS SMALLINT NOT NULL
+    CHECK ( VALUE BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_money AS NUMERIC(10,6) NOT NULL;
+/* (0, 1, 2, 3) => (up, down, max, up+down) */
+CREATE DOMAIN dm_traff_type AS SMALLINT NOT NULL
+    CHECK ( VALUE BETWEEN 0 AND 3 );
+CREATE DOMAIN dm_dir_num AS SMALLINT NOT NULL;
+CREATE DOMAIN dm_num AS SMALLINT NOT NULL;
+CREATE DOMAIN dm_traffic_mb AS INTEGER NOT NULL;
+CREATE DOMAIN dm_traffic_byte AS BIGINT NOT NULL;
+CREATE DOMAIN dm_time AS TIME NOT NULL;
+CREATE DOMAIN dm_moment AS TIMESTAMP NOT NULL;
+CREATE DOMAIN dm_credit_moment AS TIMESTAMP;
+CREATE DOMAIN dm_ip AS INTEGER NOT NULL;
+CREATE DOMAIN dm_mask AS INTEGER NOT NULL;
+CREATE DOMAIN dm_user_address AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_bool AS CHAR(1) NOT NULL
+    CHECK ( VALUE IN ('0', '1', 't', 'f', 'T', 'F') );
+CREATE DOMAIN dm_email AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_note AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_phone AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_user_name AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_service_comment AS VARCHAR(256) DEFAULT '';
+CREATE DOMAIN dm_service_name AS VARCHAR(32) DEFAULT '';
+/* TODO: why 0-31? Which is default? */
+CREATE DOMAIN dm_pay_day AS SMALLINT NOT NULL
+    CHECK ( VALUE BETWEEN 0 AND 31 );
+CREATE DOMAIN dm_period AS INTEGER NOT NULL;
+CREATE DOMAIN dm_counter AS SMALLINT NOT NULL;
+/* Is it needded? */
+CREATE DOMAIN dm_message_ver AS INTEGER NOT NULL;
+CREATE DOMAIN dm_message_type AS INTEGER NOT NULL;
+/*----------------*/
+CREATE DOMAIN dm_message AS VARCHAR(256) NOT NULL;
+CREATE DOMAIN dm_user_data AS VARCHAR(256) NOT NULL;
+CREATE DOMAIN dm_session_event_type AS CHAR(1) NOT NULL
+    CHECK ( VALUE IN ('c', 'd') );
+CREATE DOMAIN dm_char_value AS VARCHAR(64) NOT NULL;
+CREATE DOMAIN dm_date AS DATE NOT NULL;
+
+
+
+/*
+ *****************************************************************************
+ * -= Создание ТАБЛИЦ =-
+ *****************************************************************************
+ */
+
+CREATE TABLE tb_admins
+(
+    pk_admin dm_id PRIMARY KEY,
+    login dm_login UNIQUE,
+    passwd dm_password,
+    chg_conf dm_permission_flag,
+    chg_password dm_permission_flag,
+    chg_stat dm_permission_flag,
+    chg_cash dm_permission_flag,
+    usr_add_del dm_permission_flag,
+    chg_tariff dm_permission_flag,
+    chg_admin dm_permission_flag,
+    chg_service dm_permission_flag,
+    chg_corporation dm_permission_flag
+);
+
+CREATE TABLE tb_tariffs
+(
+    pk_tariff dm_id PRIMARY KEY,
+    name dm_tariff_name UNIQUE,
+    fee dm_money,
+    free dm_money,
+    passive_cost dm_money,
+    traff_type dm_traff_type
+);
+
+CREATE TABLE tb_tariffs_params
+(
+    pk_tariff_param dm_id PRIMARY KEY,
+    fk_tariff dm_id,
+    dir_num dm_dir_num,
+    price_day_a dm_money,
+    price_day_b dm_money,
+    price_night_a dm_money,
+    price_night_b dm_money,
+    threshold dm_traffic_mb,
+    time_day_begins dm_time,
+    time_day_ends dm_time,
+
+    FOREIGN KEY (fk_tariff) REFERENCES tb_tariffs (pk_tariff)
+);
+
+CREATE TABLE tb_corporations
+(
+    pk_corporation dm_id PRIMARY KEY,
+    name dm_corporation_name UNIQUE,
+    cash dm_money
+);
+
+CREATE TABLE tb_users
+(
+    pk_user dm_id PRIMARY KEY,
+    fk_tariff dm_null_id,
+    fk_tariff_change dm_null_id,
+    fk_corporation dm_null_id,
+    address dm_user_address,
+    always_online dm_bool,
+    credit dm_money,
+    credit_expire dm_credit_moment,
+    disabled dm_bool,
+    disabled_detail_stat dm_bool,
+    email dm_email,
+    grp dm_group_name,
+    note dm_note,
+    passive dm_bool,
+    passwd dm_password,
+    phone dm_phone,
+    name dm_login UNIQUE,
+    real_name dm_user_name,
+
+    FOREIGN KEY (fk_tariff) REFERENCES tb_tariffs (pk_tariff),
+    FOREIGN KEY (fk_tariff_change) REFERENCES tb_tariffs (pk_tariff),
+    FOREIGN KEY (fk_corporation) REFERENCES tb_corporations (pk_corporation)
+);
+
+CREATE TABLE tb_detail_stats
+(
+    pk_detail_stat dm_id PRIMARY KEY,
+    fk_user dm_id,
+    dir_num dm_dir_num,
+    ip dm_ip,
+    download dm_traffic_byte,
+    upload dm_traffic_byte,
+    cost dm_money,
+    from_time dm_moment,
+    till_time dm_moment,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_services
+(
+    pk_service dm_id PRIMARY KEY,
+    name dm_service_name UNIQUE,
+    comment dm_service_comment,
+    cost dm_money,
+    pay_day dm_pay_day
+);
+
+CREATE TABLE tb_users_services
+(
+    pk_user_service dm_id PRIMARY KEY,
+    fk_user dm_id,
+    fk_service dm_id,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user),
+    FOREIGN KEY (fk_service) REFERENCES tb_services (pk_service)
+);
+
+CREATE TABLE tb_messages
+(
+    pk_message dm_id PRIMARY KEY,
+    fk_user dm_id,
+    ver dm_message_ver,
+    msg_type dm_message_type,
+    last_send_time dm_period,
+    creation_time dm_period,
+    show_time dm_period,
+    repeat dm_counter,
+    repeat_period dm_period,
+    msg_text dm_message,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_stats
+(
+    pk_stat dm_id PRIMARY KEY,
+    fk_user dm_id,
+    cash dm_money,
+    free_mb dm_money,
+    last_activity_time dm_moment,
+    last_cash_add dm_money,
+    last_cash_add_time dm_moment,
+    passive_time dm_period,
+    stats_date dm_date,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_stats_traffic
+(
+    pk_stat_traffic dm_id PRIMARY KEY,
+    fk_stat dm_id,
+    dir_num dm_dir_num,
+    download dm_traffic_byte,
+    upload dm_traffic_byte,
+
+    FOREIGN KEY (fk_stat) REFERENCES tb_stats (pk_stat)
+);
+
+CREATE TABLE tb_users_data
+(
+    pk_user_data dm_id PRIMARY KEY,
+    fk_user dm_id,
+    num dm_num, /* data_id dm_id renamed */
+    data dm_user_data,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_allowed_ip
+(
+    pk_allowed_ip dm_id PRIMARY KEY,
+    fk_user dm_id,
+    ip dm_ip,
+    mask dm_mask,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_sessions_log
+(
+    pk_session_log dm_id PRIMARY KEY,
+    fk_user dm_id,
+    event_time dm_moment,
+    event_type dm_session_event_type,
+    ip dm_ip,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user)
+);
+
+CREATE TABLE tb_sessions_data
+(
+    pk_session_data dm_id PRIMARY KEY,
+    fk_session_log dm_id,
+    dir_num dm_dir_num,
+    session_upload dm_traffic_byte,
+    session_download dm_traffic_byte,
+    month_upload dm_traffic_byte,
+    month_download dm_traffic_byte,
+
+    FOREIGN KEY (fk_session_log) REFERENCES tb_sessions_log (pk_session_log)
+);
+
+CREATE TABLE tb_parameters
+(
+    pk_parameter dm_id PRIMARY KEY,
+    name dm_parameter_name UNIQUE
+);
+
+CREATE TABLE tb_params_log
+(
+    pk_param_log dm_id PRIMARY KEY,
+    fk_user dm_id,
+    fk_parameter dm_id,
+    event_time dm_moment,
+    from_val dm_char_value,
+    to_val dm_char_value,
+    comment dm_service_comment,
+
+    FOREIGN KEY (fk_user) REFERENCES tb_users (pk_user),
+    FOREIGN KEY (fk_parameter) REFERENCES tb_parameters (pk_parameter)
+);
+
+
+/*
+ *****************************************************************************
+ * -= Создание ИНДЕКСОВ =-
+ *****************************************************************************
+ */
+
+
+
+/*
+ *****************************************************************************
+ * -= Создание ГЕНЕРАТОРОВ =-
+ *****************************************************************************
+ */
+
+CREATE  GENERATOR gn_pk_admin;
+SET     GENERATOR gn_pk_admin           TO 0;
+CREATE  GENERATOR gn_pk_tariff;
+SET     GENERATOR gn_pk_tariff          TO 0;
+CREATE  GENERATOR gn_pk_tariff_param;
+SET     GENERATOR gn_pk_tariff_param    TO 0;
+CREATE  GENERATOR gn_pk_corporation;
+SET     GENERATOR gn_pk_corporation     TO 0;
+CREATE  GENERATOR gn_pk_user;
+SET     GENERATOR gn_pk_user            TO 0;
+CREATE  GENERATOR gn_pk_detail_stat;
+SET     GENERATOR gn_pk_detail_stat     TO 0;
+CREATE  GENERATOR gn_pk_service;
+SET     GENERATOR gn_pk_service         TO 0;
+CREATE  GENERATOR gn_pk_user_service;
+SET     GENERATOR gn_pk_user_service    TO 0;
+CREATE  GENERATOR gn_pk_message;
+SET     GENERATOR gn_pk_message         TO 0;
+CREATE  GENERATOR gn_pk_stat;
+SET     GENERATOR gn_pk_stat            TO 0;
+CREATE  GENERATOR gn_pk_stat_traffic;
+SET     GENERATOR gn_pk_stat_traffic    TO 0;
+CREATE  GENERATOR gn_pk_user_data;
+SET     GENERATOR gn_pk_user_data       TO 0;
+CREATE  GENERATOR gn_pk_allowed_ip;
+SET     GENERATOR gn_pk_allowed_ip      TO 0;
+CREATE  GENERATOR gn_pk_session;
+SET     GENERATOR gn_pk_session         TO 0;
+CREATE  GENERATOR gn_pk_session_log;
+SET     GENERATOR gn_pk_session_log     TO 0;
+CREATE  GENERATOR gn_pk_session_data;
+SET     GENERATOR gn_pk_session_data    TO 0;
+CREATE  GENERATOR gn_pk_parameter;
+SET     GENERATOR gn_pk_parameter       TO 0;
+CREATE  GENERATOR gn_pk_param_log;
+SET     GENERATOR gn_pk_param_log       TO 0;
+
+
+/*
+ *****************************************************************************
+ * -= Создание ТРИГГЕРОВ =-
+ *****************************************************************************
+ */
+
+SET TERM !! ;
+CREATE TRIGGER tr_admin_bi FOR tb_admins
+ACTIVE BEFORE INSERT POSITION 0
+AS
+BEGIN
+    IF (new.pk_admin IS NULL)
+    THEN new.pk_admin = GEN_ID(gn_pk_admin, 1);
+END !!
+SET TERM ; !!
+
+/*set term !! ;
+create trigger tr_tariff_bi for tb_tariffs active
+before insert position 0
+as
+begin
+    if (new.pk_tariff is null)
+    then new.pk_tariff = gen_id(gn_pk_tariff, 1);
+end !!
+set term ; !!*/
+
+set term !! ;
+create trigger tr_tariff_param_bi for tb_tariffs_params active
+before insert position 0
+as
+begin
+    if (new.pk_tariff_param is null)
+    then new.pk_tariff_param = gen_id(gn_pk_tariff_param, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_corporation_bi for tb_corporations active
+before insert position 0
+as
+begin
+    if (new.pk_corporation is null)
+    then new.pk_corporation = gen_id(gn_pk_corporation, 1);
+end !!
+set term ; !!
+
+/*set term !! ;
+create trigger tr_user_bi for tb_users active
+before insert position 0
+as
+begin
+    if (new.pk_user is null)
+    then new.pk_user = gen_id(gn_pk_user, 1);
+end !!
+set term ; !!*/
+
+set term !! ;
+create trigger tr_detail_stat_bi for tb_detail_stats active
+before insert position 0
+as
+begin
+    if (new.pk_detail_stat is null)
+    then new.pk_detail_stat = gen_id(gn_pk_detail_stat, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_service_bi for tb_services active
+before insert position 0
+as
+begin
+    if (new.pk_service is null)
+    then new.pk_service = gen_id(gn_pk_service, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_user_service_bi for tb_users_services active
+before insert position 0
+as
+begin
+    if (new.pk_user_service is null)
+    then new.pk_user_service = gen_id(gn_pk_user_service, 1);
+end !!
+set term ; !!
+
+/*set term !! ;
+create trigger tr_message_bi for tb_messages active
+before insert position 0
+as
+begin
+    if (new.pk_message is null)
+    then new.pk_message = gen_id(gn_pk_message, 1);
+end !!
+set term ; !!*/
+
+/*set term !! ;
+create trigger tr_stat_bi for tb_stats active
+before insert position 0
+as
+begin
+    if (new.pk_stat is null)
+    then new.pk_stat = gen_id(gn_pk_stat, 1);
+end !!
+set term ; !!*/
+
+set term !! ;
+create trigger tr_stat_traffic_bi for tb_stats_traffic active
+before insert position 0
+as
+begin
+    if (new.pk_stat_traffic is null)
+    then new.pk_stat_traffic = gen_id(gn_pk_stat_traffic, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_user_data_bi for tb_users_data active
+before insert position 0
+as
+begin
+    if (new.pk_user_data is null)
+    then new.pk_user_data = gen_id(gn_pk_user_data, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_allowed_ip_bi for tb_allowed_ip active
+before insert position 0
+as
+begin
+    if (new.pk_allowed_ip is null)
+    then new.pk_allowed_ip = gen_id(gn_pk_allowed_ip, 1);
+end !!
+set term ; !!
+
+/*set term !! ;
+create trigger tr_session_log_bi for tb_sessions_log active
+before insert position 0
+as
+begin
+    if (new.pk_session_log is null)
+    then new.pk_session_log = gen_id(gn_pk_session_log, 1);
+end !!
+set term ; !!*/
+
+set term !! ;
+create trigger tr_session_data_bi for tb_sessions_data active
+before insert position 0
+as
+begin
+    if (new.pk_session_data is null)
+    then new.pk_session_data = gen_id(gn_pk_session_data, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_parameter_bi for tb_parameters active
+before insert position 0
+as
+begin
+    if (new.pk_parameter is null)
+    then new.pk_parameter = gen_id(gn_pk_parameter, 1);
+end !!
+set term ; !!
+
+set term !! ;
+create trigger tr_param_log_bi for tb_params_log active
+before insert position 0
+as
+begin
+    if (new.pk_param_log is null)
+    then new.pk_param_log = gen_id(gn_pk_param_log, 1);
+end !!
+set term ; !!
+
+/*
+ *****************************************************************************
+ * -= Создание stored procedure =-
+ *****************************************************************************
+ */
+
+/*
+ * Add a message returning it's ID
+ */
+set term !! ;
+create procedure sp_add_message(pk_message integer, login varchar(32), ver integer, msg_type integer, last_send_time integer, creation_time integer, show_time integer, repeat integer, repeat_period integer, msg_text varchar(256))
+returns(res integer)
+as  
+begin
+    if (:pk_message is null) then
+    begin
+       pk_message = gen_id(gn_pk_message, 1);
+       insert into tb_messages values (:pk_message,
+                                       (select pk_user from tb_users where name = :login),
+                                       :ver,
+                                       :msg_type,
+                                       :last_send_time,
+                                       :creation_time, 
+                                       :show_time,
+                                       :repeat,
+                                       :repeat_period,
+                                       :msg_text);
+    end
+    else
+    begin
+       update tb_messages set fk_user = (select pk_user from tb_users where name = :login),
+                              ver = :ver,
+                              msg_type = :msg_type,
+                              last_send_time = :last_send_time,
+                              creation_time = :creation_time,
+                              show_time = :show_time,
+                              repeat = :repeat_period,
+                              repeat_period = :repeat_period,
+                              msg_text = :msg_text
+                          where pk_message = :pk_message;
+    end
+    res = :pk_message;
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_delete_service(name varchar(32))
+as
+declare variable pk_service integer;
+begin
+    select pk_service from tb_services where name = :name into pk_service;
+    if (pk_service is  not null) then
+    begin
+       delete from tb_users_services where fk_service = :pk_service;
+       delete from tb_services where pk_service = :pk_service;
+    end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_add_tariff(name varchar(32), dirs integer)
+as
+declare variable pk_tariff integer;
+begin
+    pk_tariff = gen_id(gn_pk_tariff, 1);
+    insert into tb_tariffs (pk_tariff, name, fee, free, passive_cost, traff_type) values (:pk_tariff, :name, 0, 0, 0, 0);
+    while (dirs > 0) do
+    begin
+        insert into tb_tariffs_params (fk_tariff, dir_num, price_day_a, 
+                                       price_day_b, price_night_a, price_night_b, 
+                                       threshold, time_day_begins, time_day_ends)
+                   values (:pk_tariff, :dirs - 1, 0, 0, 0, 0, 0, '0:0', '0:0');
+       dirs = dirs - 1;
+    end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_delete_tariff(name varchar(32))
+as
+declare variable pk_tariff integer;
+begin
+    select pk_tariff from tb_tariffs where name = :name into pk_tariff;
+    if (pk_tariff is not null) then
+    begin
+       delete from tb_tariffs_params where fk_tariff = :pk_tariff;
+       delete from tb_tariffs where pk_tariff = :pk_tariff;
+    end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_add_user(name varchar(32), dirs integer)
+as
+declare variable pk_user integer;
+declare variable pk_stat integer;
+begin
+    pk_user = gen_id(gn_pk_user, 1);
+    insert into tb_users(pk_user, fk_tariff, fk_tariff_change, fk_corporation, address, always_online, credit, credit_expire, disabled, disabled_detail_stat, email, grp, note, passive, passwd, phone, name, real_name) values (:pk_user, NULL, NULL, NULL, '', 0, 0, 'now', 0, 0, '', '_', '', 0, '', '', :name, '');
+    pk_stat = gen_id(gn_pk_stat, 1);
+    insert into tb_stats values (:pk_stat, :pk_user, 0, 0, 'now', 0, 'now', 0, 'now');
+    while (dirs > 0) do
+    begin
+       insert into tb_stats_traffic (fk_stat, dir_num, upload, download) values (:pk_stat, :dirs - 1, 0, 0);
+       dirs = dirs - 1;
+    end
+end!!
+set term ; !!
+
+set term !! ;
+create procedure sp_delete_user(name varchar(32))
+as
+declare variable pk_user integer;
+begin
+    select pk_user from tb_users where name = :name into pk_user;
+    if (pk_user is not null) then
+    begin
+       delete from tb_users_services where fk_user = :pk_user;
+       delete from tb_params_log where fk_user = :pk_user;
+       delete from tb_detail_stats where fk_user = :pk_user;
+       delete from tb_stats_traffic where fk_stat in (select pk_stat from tb_stats where fk_user = :pk_user);
+       delete from tb_stats where fk_user = :pk_user;
+       delete from tb_sessions_data where fk_session_log in (select pk_session_log from tb_sessions_log where fk_user = :pk_user);
+       delete from tb_sessions_log where fk_user = :pk_user;
+       delete from tb_allowed_ip where fk_user = :pk_user;
+       delete from tb_users_data where fk_user = :pk_user;
+       delete from tb_messages where fk_user = :pk_user;
+       delete from tb_users where pk_user = :pk_user;
+    end
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_append_session_log(name varchar(32), event_time timestamp, event_type char(1), ip integer)
+returns(pk_session_log integer)
+as
+begin
+    pk_session_log = gen_id(gn_pk_session_log, 1);
+    insert into tb_sessions_log (pk_session_log, fk_user, event_time, event_type, ip) values (:pk_session_log, (select pk_user from tb_users where name = :name), :event_time, :event_type, :ip);
+end !!
+set term ; !!
+
+set term !! ;
+create procedure sp_add_stat(name varchar(32), cash numeric(10,6), free_mb numeric(10,6), last_activity_time timestamp, last_cash_add numeric(10,6), last_cash_add_time timestamp, passive_time integer, stats_date date)
+returns(pk_stat integer)
+as
+begin
+    pk_stat = gen_id(gn_pk_stat, 1);
+    insert into tb_stats (pk_stat, fk_user, cash, free_mb, last_activity_time, last_cash_add, last_cash_add_time, passive_time, stats_date) values (:pk_stat, (select pk_user from tb_users where name = :name), :cash, :free_mb, :last_activity_time, :last_cash_add, :last_cash_add_time, :passive_time, :stats_date);
+end !!
+set term ; !!
+
+/*
+ *****************************************************************************
+ * -= Создание администратора =-
+ *****************************************************************************
+ */
+
+insert into tb_admins values(0, 'admin', 'geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmk', 1, 1, 1, 1, 1, 1, 1, 1, 1);
+
+/* EOF */
+
diff --git a/projects/stargazer/inst/var/00-mysql-01.sql b/projects/stargazer/inst/var/00-mysql-01.sql
new file mode 100644 (file)
index 0000000..253738a
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ *  DB migration from v00 to v01 (mysql)
+ */
+
+ALTER TABLE users ADD DisabledDetailStat INT(3) DEFAULT 0;
diff --git a/projects/stargazer/inst/var/base.dia b/projects/stargazer/inst/var/base.dia
new file mode 100644 (file)
index 0000000..a3d09fa
Binary files /dev/null and b/projects/stargazer/inst/var/base.dia differ
diff --git a/projects/stargazer/inst/var/stargazer/admins/admin.adm b/projects/stargazer/inst/var/stargazer/admins/admin.adm
new file mode 100644 (file)
index 0000000..bfc6cde
--- /dev/null
@@ -0,0 +1,8 @@
+password=geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa
+ChgConf=1
+ChgPassword=1
+ChgStat=1
+ChgCash=1
+UsrAddDel=1
+ChgTariff=1
+ChgAdmin=1
diff --git a/projects/stargazer/inst/var/stargazer/tariffs/tariff.tf b/projects/stargazer/inst/var/stargazer/tariffs/tariff.tf
new file mode 100644 (file)
index 0000000..8eb1deb
--- /dev/null
@@ -0,0 +1,84 @@
+Fee=10.000000
+Free=0
+NoDiscount0=1
+NoDiscount1=1
+NoDiscount2=1
+NoDiscount3=1
+NoDiscount4=1
+NoDiscount5=1
+NoDiscount6=1
+NoDiscount7=1
+NoDiscount8=1
+NoDiscount9=1
+PassiveCost=0.000000
+PriceDayA0=0.000000
+PriceDayA1=0.750000
+PriceDayA2=0.000000
+PriceDayA3=0.000000
+PriceDayA4=0.000000
+PriceDayA5=0.000000
+PriceDayA6=0.000000
+PriceDayA7=0.000000
+PriceDayA8=0.000000
+PriceDayA9=0.000000
+PriceDayB0=0.000000
+PriceDayB1=0.750000
+PriceDayB2=0.000000
+PriceDayB3=0.000000
+PriceDayB4=0.000000
+PriceDayB5=0.000000
+PriceDayB6=0.000000
+PriceDayB7=0.000000
+PriceDayB8=0.000000
+PriceDayB9=0.000000
+PriceNightA0=1.000000
+PriceNightA1=0.000000
+PriceNightA2=0.000000
+PriceNightA3=0.000000
+PriceNightA4=0.000000
+PriceNightA5=0.000000
+PriceNightA6=0.000000
+PriceNightA7=0.000000
+PriceNightA8=0.000000
+PriceNightA9=0.000000
+PriceNightB0=1.000000
+PriceNightB1=0.000000
+PriceNightB2=0.000000
+PriceNightB3=0.000000
+PriceNightB4=0.000000
+PriceNightB5=0.000000
+PriceNightB6=0.000000
+PriceNightB7=0.000000
+PriceNightB8=0.000000
+PriceNightB9=0.000000
+SinglePrice0=1
+SinglePrice1=1
+SinglePrice2=0
+SinglePrice3=0
+SinglePrice4=0
+SinglePrice5=0
+SinglePrice6=0
+SinglePrice7=0
+SinglePrice8=0
+SinglePrice9=0
+Threshold0=0
+Threshold1=0
+Threshold2=0
+Threshold3=0
+Threshold4=0
+Threshold5=0
+Threshold6=0
+Threshold7=0
+Threshold8=0
+Threshold9=0
+Time0=0:0-0:0
+Time1=0:0-0:0
+Time2=0:0-0:0
+Time3=0:0-0:0
+Time4=0:0-0:0
+Time5=0:0-0:0
+Time6=0:0-0:0
+Time7=0:0-0:0
+Time8=0:0-0:0
+Time9=0:0-0:0
+TraffType=up+down
diff --git a/projects/stargazer/inst/var/stargazer/users/test/conf b/projects/stargazer/inst/var/stargazer/users/test/conf
new file mode 100644 (file)
index 0000000..16fff5e
--- /dev/null
@@ -0,0 +1,19 @@
+Address=
+AlwaysOnline=0
+CreationTime=1123487395
+Credit=0.000000
+CreditExpire=0
+Down=0
+Email=
+Group=
+Iface=eth1
+IP=192.168.1.1
+Note=
+Passive=0
+Password=123456
+Phone=
+RealName=
+Tariff=tariff
+TariffChange=
+Userdata0=
+Userdata1=
diff --git a/projects/stargazer/inst/var/stargazer/users/test/stat b/projects/stargazer/inst/var/stargazer/users/test/stat
new file mode 100644 (file)
index 0000000..8aa33e0
--- /dev/null
@@ -0,0 +1,26 @@
+Cash=10.000000
+D0=0
+D1=0
+D2=0
+D3=0
+D4=0
+D5=0
+D6=0
+D7=0
+D8=0
+D9=0
+FreeMb=0.000000
+LastActivityTime=0
+LastCashAdd=0
+LastCashAddTime=0
+PassiveTime=0
+U0=0
+U1=0
+U2=0
+U3=0
+U4=0
+U5=0
+U6=0
+U7=0
+U8=0
+U9=0
diff --git a/projects/stargazer/main.cpp b/projects/stargazer/main.cpp
new file mode 100644 (file)
index 0000000..7c9945b
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.124 $
+ $Date: 2010/10/04 20:19:12 $
+ $Author: faust $
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <fstream>
+#include <vector>
+#include <set>
+#include <list>
+
+#include "settings.h"
+#include "user.h"
+#include "users.h"
+#include "admins.h"
+#include "common.h"
+#include "traffcounter.h"
+#include "base_plugin.h"
+#include "stg_logger.h"
+#include "stg_timer.h"
+#include "plugin_runner.h"
+#include "script_executer.h"
+#include "conffiles.h"
+#include "version.h"
+#include "store_loader.h"
+#include "pidfile.h"
+#include "eventloop.h"
+
+using namespace std;
+uint32_t        eip;
+
+#ifdef DEBUG
+    #define MAIN_DEBUG (1)
+    #define NO_DAEMON  (1)
+#endif
+
+#define START_FILE "/._ST_ART_ED_"
+
+static bool needRulesReloading = false;
+static bool childExited = false;
+//static pid_t executerPid;
+set<pid_t> executersPid;
+static pid_t stgChildPid;
+
+#include "pinger.h"
+
+//-----------------------------------------------------------------------------
+bool StartModCmp(const PLUGIN_RUNNER & lhs, const PLUGIN_RUNNER & rhs)
+{
+return lhs.GetStartPosition() < rhs.GetStartPosition();
+}
+//-----------------------------------------------------------------------------
+bool StopModCmp(const PLUGIN_RUNNER & lhs, const PLUGIN_RUNNER & rhs)
+{
+return lhs.GetStopPosition() > rhs.GetStopPosition();
+}
+//-----------------------------------------------------------------------------
+class STG_STOPPER
+{
+public:
+    STG_STOPPER() { nonstop = true; }
+    bool    GetStatus() { return nonstop; };
+    #ifdef NO_DAEMON
+    void    Stop(const char * __file__, int __line__)
+    #else
+    void    Stop(const char *, int)
+    #endif
+        {
+        #ifdef NO_DAEMON
+        printfd(__FILE__, "Stg stopped at %s:%d\n", __file__, __line__);
+        #endif
+        nonstop = false;
+        }
+private:
+    bool nonstop;
+};
+//-----------------------------------------------------------------------------
+STG_STOPPER nonstop;
+//-----------------------------------------------------------------------------
+static void StartTimer()
+{
+STG_LOGGER & WriteServLog = GetStgLogger();
+
+if (RunStgTimer())
+    {
+    WriteServLog("Cannot start timer. Fatal.");
+    //printfd(__FILE__, "Cannot start timer. Fatal.\n");
+    exit(1);
+    }
+else
+    {
+    WriteServLog("Timer thread started successfully.");
+    //printfd(__FILE__, "Timer thread started successfully.\n");
+    }
+}
+//-----------------------------------------------------------------------------
+void CatchPROF(int)
+{
+/*STG_LOGGER & WriteServLog = GetStgLogger();
+WriteServLog("CatchPROF");*/
+}
+//-----------------------------------------------------------------------------
+void CatchUSR1(int)
+{
+
+}
+//-----------------------------------------------------------------------------
+void CatchTERM(int sig)
+{
+/*
+ *Function Name:CatchINT
+ *Parameters: sig_num - ÎÏÍÅÒ ÓÉÇÎÁÌÁ
+ *Description: ïÂÒÁÂÏÔÞÉË ÓÉÇÎÁÌÁ INT
+ *Returns: îÉÞÅÇÏ
+ */
+STG_LOGGER & WriteServLog = GetStgLogger();
+WriteServLog("Shutting down... %d", sig);
+
+//nonstop = false;
+nonstop.Stop(__FILE__, __LINE__);
+
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+}
+//-----------------------------------------------------------------------------
+void CatchPIPE(int)
+{
+STG_LOGGER & WriteServLog = GetStgLogger();
+WriteServLog("Broken pipe!");
+}
+//-----------------------------------------------------------------------------
+void CatchHUP(int)
+{
+needRulesReloading = true;
+}
+//-----------------------------------------------------------------------------
+void CatchCHLD(int)
+{
+int status;
+pid_t childPid;
+childPid = waitpid(-1, &status, WNOHANG);
+
+set<pid_t>::iterator pid;
+pid = executersPid.find(childPid);
+if (pid != executersPid.end())
+    {
+    executersPid.erase(pid);
+    if (executersPid.empty() && nonstop.GetStatus())
+        {
+        nonstop.Stop(__FILE__, __LINE__);
+        }
+    }
+if (childPid == stgChildPid)
+    {
+    childExited = true;
+    }
+}
+//-----------------------------------------------------------------------------
+void CatchSEGV(int, siginfo_t *, void *)
+{
+/*char fileName[50];
+sprintf(fileName, "/tmp/stg_segv.%d", getpid());
+FILE * f = fopen(fileName, "wt");
+if (f)
+    {
+    fprintf(f, "\nSignal info:\n~~~~~~~~~~~~\n");
+    fprintf(f, "numb:\t %d (%d)\n", sinfo->si_signo, sig);
+    fprintf(f, "errn:\t %d\n", sinfo->si_errno);
+    fprintf(f, "code:\t %d ", sinfo->si_code);
+
+    switch (sinfo->si_code)
+        {
+        case SEGV_MAPERR:
+            fprintf(f, "(SEGV_MAPERR - address not mapped to object)\n");
+            break;
+
+        case SEGV_ACCERR:
+            fprintf(f, "(SEGV_ACCERR - invalid permissions for mapped object)\n");
+            break;
+
+        default:
+            fprintf(f, "???\n");
+        }
+
+    fprintf(f, "addr:\t 0x%.8X\n",
+        (unsigned int)sinfo->si_addr);
+
+    Dl_info dlinfo;
+    //asm("movl %eip, eip");
+    if (dladdr((void*)CatchCHLD, &dlinfo))
+        {
+        fprintf(f, "SEGV point: %s %s\n", dlinfo.dli_fname, dlinfo.dli_sname);
+        }
+    else
+        {
+        fprintf(f, "Cannot find SEGV point\n");
+        }
+
+    fclose(f);
+    }
+
+struct sigaction segv_action, segv_action_old;
+
+segv_action.sa_handler = SIG_DFL;
+segv_action.sa_sigaction = NULL;
+segv_action.sa_flags = SA_SIGINFO;
+segv_action.sa_restorer = NULL;
+
+sigaction(SIGSEGV, &segv_action, &segv_action_old);*/
+}
+//-----------------------------------------------------------------------------
+static void SetSignalHandlers()
+{
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+///////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+///////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR1);
+newsa.sa_handler = CatchUSR1;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR1, &newsa, &oldsa);
+///////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = CatchTERM;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+/*///////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGPROF);
+newsa.sa_handler = CatchPROF;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGPROF, &newsa, &oldsa);*/
+//////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGPIPE);
+newsa.sa_handler = CatchPIPE;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGPIPE, &newsa, &oldsa);
+//////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGHUP);
+newsa.sa_handler = CatchHUP;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGHUP, &newsa, &oldsa);
+//////
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGCHLD);
+newsa.sa_handler = CatchCHLD;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGCHLD, &newsa, &oldsa);
+
+/*newsa.sa_handler = NULL;
+newsa.sa_sigaction = CatchSEGV;
+newsa.sa_flags = SA_SIGINFO;
+newsa.sa_restorer = NULL;
+sigaction(SIGSEGV, &newsa, &oldsa);*/
+
+return;
+}
+//-----------------------------------------------------------------------------
+int StartScriptExecuter(char * procName, int msgKey, int * msgID, SETTINGS * settings)
+{
+STG_LOGGER & WriteServLog = GetStgLogger();
+
+if (*msgID == -11)   // If msgID == -11 - first call. Create queue
+    {
+    for (int i = 0; i < 2; i++)
+        {
+        //WriteServLog("Creating queue with key=%d ...", msgKey);
+        *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
+
+        if (*msgID == -1)
+            {
+            *msgID = msgget(msgKey, 0);
+            if (*msgID == -1)
+                {
+                WriteServLog("Message queue not created.");
+                return -1;
+                }
+            else
+                {
+                msgctl(*msgID, IPC_RMID, NULL);
+                //printfd(__FILE__, "Queue removed!");
+                }
+            }
+        else
+            {
+            WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
+            break;
+            }
+        }
+    }
+
+pid_t executerPid = fork();
+
+switch (executerPid)
+    {
+    case -1:    // ìÁÖÁ
+        WriteServLog("Fork error!");
+        return -1;
+
+    case 0:     // ðÏÔÏÍÏË
+        //close(0);
+        //close(1);
+        //close(2);
+        //setsid();
+        delete settings;
+        Executer(msgKey, *msgID, executerPid, procName);
+        return 1;
+
+    default:    // ïÓÎÏ×ÎÏÊ ÐÒÏÃÅÓÓ
+        if (executersPid.empty()) {
+            Executer(msgKey, *msgID, executerPid, NULL);
+        }
+        executersPid.insert(executerPid);
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+#ifndef NO_DAEMON
+int ForkAndWait(const string & confDir)
+#else
+int ForkAndWait(const string &)
+#endif
+{
+#ifndef NO_DAEMON
+stgChildPid = fork();
+string startFile = confDir + START_FILE;
+unlink(startFile.c_str());
+
+switch (stgChildPid)
+    {
+    case -1:    // ìÁÖÁ
+        return -1;
+        break;
+
+    case 0:     // ðÏÔÏÍÏË
+        //close(0);
+        close(1);
+        close(2);
+        setsid();
+        break;
+
+    default:    // ïÓÎÏ×ÎÏÊ ÐÒÏÃÅÓÓ
+        for (int i = 0; i < 120 * 5; i++)
+            {
+            if (access(startFile.c_str(), F_OK) == 0)
+                {
+                //printf("Fork successfull. Exit.\n");
+                unlink(startFile.c_str());
+                exit(0);
+                }
+
+            if (childExited)
+                {
+                unlink(startFile.c_str());
+                exit(1);
+                }
+            usleep(200000);
+            }
+        unlink(startFile.c_str());
+        exit(1);
+        break;
+    }
+#endif
+return 0;
+}
+//-----------------------------------------------------------------------------
+void KillExecuters()
+{
+set<pid_t>::iterator pid;
+pid = executersPid.begin();
+while (pid != executersPid.end())
+    {
+    printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
+    kill(*pid, SIGUSR1);
+    ++pid;
+    }
+}
+//-----------------------------------------------------------------------------
+int main(int argc, char * argv[])
+{
+
+/*
+  Initialization order:
+  - Logger
+  - Stg timer
+  - Settings
+  - Plugins
+  - Plugins settings
+  - Read Admins
+  - Read Tariffs
+  - Read Users
+  - Start Users
+  - Start Traffcounter
+  - Start Plugins
+  - Start pinger
+  - Set signal nandlers
+  - Fork and exit
+ * */
+
+SETTINGS * settings = NULL;
+BASE_STORE * dataStore = NULL;
+TARIFFS * tariffs = NULL;
+ADMINS * admins = NULL;
+USERS * users = NULL;
+TRAFFCOUNTER * traffCnt = NULL;
+int msgID = -11;
+
+    {
+    STG_LOGGER & WriteServLog = GetStgLogger();
+    WriteServLog.SetLogFileName("/var/log/stargazer.log");
+    }
+
+vector<MODULE_SETTINGS> modSettings;
+list<PLUGIN_RUNNER> modules;
+
+list<PLUGIN_RUNNER>::iterator modIter;
+
+if (getuid())
+    {
+    printf("You must be root. Exit.\n");
+    exit(1);
+    }
+
+if (argc == 2)
+    settings = new SETTINGS(argv[1]);
+else
+    settings = new SETTINGS();
+
+if (settings->ReadSettings())
+    {
+    //printfd(__FILE__, "ReadSettings error.\n");
+    STG_LOGGER & WriteServLog = GetStgLogger();
+
+    if (settings->GetLogFileName() != "")
+        WriteServLog.SetLogFileName(settings->GetLogFileName());
+
+    WriteServLog("ReadSettings error. %s", settings->GetStrError().c_str());
+    exit(1);
+    }
+
+#ifndef NO_DAEMON
+string startFile(settings->GetConfDir() + START_FILE);
+#endif
+
+//SetSignalHandlers();
+if (ForkAndWait(settings->GetConfDir()) < 0)
+    {
+    STG_LOGGER & WriteServLog = GetStgLogger();
+    WriteServLog("Fork error!");
+    exit(1);
+    }
+
+STG_LOGGER & WriteServLog = GetStgLogger();
+WriteServLog.SetLogFileName(settings->GetLogFileName());
+WriteServLog("Stg v. %s", SERVER_VERSION);
+
+for (int i = 0; i < settings->GetExecutersNum(); i++)
+    {
+    int ret = StartScriptExecuter(argv[0], settings->GetExecMsgKey(), &msgID, settings);
+    if (ret < 0)
+        {
+        STG_LOGGER & WriteServLog = GetStgLogger();
+        WriteServLog("Start Script Executer error!");
+        //goto exitLbl;
+        return 1;
+        }
+    if (ret == 1)
+        {
+        // Stopping child
+        return 0;
+        }
+    }
+
+PIDFile pidFile(settings->GetPIDFileName());
+
+StartTimer();
+WaitTimer();
+if (!IsStgTimerRunning())
+    {
+    printfd(__FILE__, "Timer thread not started in 1 sec!\n");
+    WriteServLog("Timer thread not started in 1 sec!");
+    }
+
+EVENT_LOOP & loop(EVENT_LOOP_SINGLETON::GetInstance());
+
+STORE_LOADER storeLoader(*settings);
+if (storeLoader.Load())
+    {
+    WriteServLog("Storage plugin: '%s'", storeLoader.GetStrError().c_str());
+    goto exitLblNotStarted;
+    }
+
+if (loop.Start())
+    {
+    WriteServLog("Event loop not started.");
+    goto exitLblNotStarted;
+    }
+
+dataStore = storeLoader.GetStore();
+WriteServLog("Storage plugin: %s. Loading successfull.", dataStore->GetVersion().c_str());
+
+tariffs = new TARIFFS(dataStore);
+admins = new ADMINS(dataStore);
+users = new USERS(settings, dataStore, tariffs, admins->GetSysAdmin());
+traffCnt = new TRAFFCOUNTER(users, tariffs, settings->GetRulesFileName());
+traffCnt->SetMonitorDir(settings->GetMonitorDir());
+//tariffs->SetUsers(users);
+
+modSettings = settings->GetModulesSettings();
+
+for (unsigned i = 0; i < modSettings.size(); i++)
+    {
+    string modulePath = settings->GetModulesPath();
+    modulePath += "/mod_";
+    modulePath += modSettings[i].moduleName;
+    modulePath += ".so";
+    printfd(__FILE__, "Module: %s\n", modulePath.c_str());
+    modules.push_back(
+        PLUGIN_RUNNER(modulePath,
+                      modSettings[i],
+                      admins,
+                      tariffs,
+                      users,
+                      traffCnt,
+                      dataStore,
+                      settings)
+        );
+    }
+
+modIter = modules.begin();
+
+while (modIter != modules.end())
+    {
+    //Loading modules
+    if (modIter->Load())
+        {
+        WriteServLog("Error: %s",
+                     modIter->GetStrError().c_str());
+        goto exitLblNotStarted;
+        }
+    ++modIter;
+    }
+
+//Start section
+if (users->Start())
+    {
+    goto exitLblNotStarted;
+    }
+WriteServLog("Users started successfully.");
+
+if (traffCnt->Start())
+    {
+    goto exitLblNotStarted;
+    }
+WriteServLog("Traffcounter started successfully.");
+
+//Sort by start order
+modules.sort(StartModCmp);
+modIter = modules.begin();
+
+while (modIter != modules.end())
+    {
+    if (modIter->Start())
+        {
+        WriteServLog("Error: %s",
+                     modIter->GetStrError().c_str());
+        //printfd(__FILE__, "Error: %s\n", capRunner.GetStrError().c_str());
+        goto exitLbl;
+        }
+    WriteServLog("Module: \'%s\'. Start successfull. %d", modIter->GetPlugin()->GetVersion().c_str(),
+        modIter->GetPlugin()->GetStartPosition());
+    ++modIter;
+    }
+SetSignalHandlers();
+
+srandom(stgTime);
+
+/*
+ * Note that an implementation in which nice returns the new nice value
+ * can legitimately return -1.   To  reliably  detect  an  error,  set
+ * errno to 0 before the call, and check its value when nice returns -1.
+ *
+ *
+ * (c) man 2 nice
+ */
+errno = 0;
+if (nice(-19) && errno) {
+    printfd(__FILE__, "nice failed: '%s'\n", strerror(errno));
+    WriteServLog("nice failed: '%s'", strerror(errno));
+}
+
+WriteServLog("Stg started successfully.");
+WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+#ifndef NO_DAEMON
+creat(startFile.c_str(), S_IRUSR);
+#endif
+
+//*a_kill_it = 0;
+
+while (nonstop.GetStatus())
+    {
+    if (needRulesReloading)
+        {
+        needRulesReloading = false;
+        traffCnt->Reload();
+
+        modIter = modules.begin();
+        for (; modIter != modules.end(); ++modIter)
+            {
+            if (modIter->Reload())
+                {
+                WriteServLog("Error reloading %s ('%s')", modIter->GetPlugin()->GetVersion().c_str(),
+                                                          modIter->GetStrError().c_str());
+                printfd(__FILE__, "Error reloading %s ('%s')\n", modIter->GetPlugin()->GetVersion().c_str(),
+                                                                 modIter->GetStrError().c_str());
+                }
+            }
+        }
+    stgUsleep(100000);
+    }
+
+exitLbl:
+
+WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
+
+//Sort by start order
+modules.sort(StopModCmp);
+modIter = modules.begin();
+while (modIter != modules.end())
+    {
+    std::string name = modIter->GetFileName();
+    printfd(__FILE__, "Stopping module '%s'\n", name.c_str());
+    if (modIter->Stop())
+        {
+        WriteServLog("Module \'%s\': Error: %s",
+                     modIter->GetPlugin()->GetVersion().c_str(),
+                     modIter->GetStrError().c_str());
+        printfd(__FILE__, "Failed to stop module '%s'\n", name.c_str());
+        //printfd(__FILE__, "Error: %s\n", capRunner.GetStrError().c_str());
+        //goto exitLbl;
+        }
+    WriteServLog("Module: \'%s\'. Stop successfull.", modIter->GetPlugin()->GetVersion().c_str());
+    ++modIter;
+    }
+
+if (loop.Stop())
+    {
+    WriteServLog("Event loop not stopped.");
+    }
+
+exitLblNotStarted:
+
+/*modIter = modules.begin();
+while (modIter != modules.end())
+    {
+    std::string name = modIter->GetFileName();
+    printfd(__FILE__, "Unloading module '%s'\n", name.c_str());
+    if (modIter->Unload())
+        {
+        WriteServLog("Module \'%s\': Error: %s",
+                     name.c_str(),
+                     modIter->GetStrError().c_str());
+        printfd(__FILE__, "Failed to unload module '%s'\n", name.c_str());
+        }
+    ++modIter;
+    }*/
+
+if (traffCnt)
+    {
+    traffCnt->Stop();
+    WriteServLog("Traffcounter: Stop successfull.");
+    }
+
+if (users)
+    {
+    users->Stop();
+    WriteServLog("Users: Stop successfull.");
+    }
+
+sleep(1);
+int res = msgctl(msgID, IPC_RMID, NULL);
+if (res)
+    WriteServLog("Queue was not removed. id=%d", msgID);
+else
+    WriteServLog("Queue removed successfully.");
+
+/*struct sigaction newsa, oldsa;
+sigset_t sigmask;
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGCHLD);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGCHLD, &newsa, &oldsa);*/
+
+KillExecuters();
+
+StopStgTimer();
+WriteServLog("StgTimer: Stop successfull.");
+
+WriteServLog("Stg stopped successfully.");
+sleep(1);
+WriteServLog("---------------------------------------------");
+
+delete traffCnt;
+delete users;
+delete admins;
+delete tariffs;
+delete settings;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/pidfile.cpp b/projects/stargazer/pidfile.cpp
new file mode 100644 (file)
index 0000000..0f47a25
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2009/06/09 09:07:32 $
+ $Author: faust $
+ */
+
+/*
+ *  An implementation of RAII pid-file writer
+ */
+
+#include <fstream>
+#include <unistd.h>
+
+#include "pidfile.h"
+
+PIDFile::PIDFile(const std::string & fn)
+    : fileName(fn)
+{
+if (fileName != "")
+    {
+    std::ofstream pf(fileName.c_str());
+    pf << getpid() << std::endl;
+    pf.close();
+    }
+}
+
+PIDFile::~PIDFile()
+{
+if (fileName != "")
+    {
+    unlink(fileName.c_str());
+    }
+}
diff --git a/projects/stargazer/pidfile.h b/projects/stargazer/pidfile.h
new file mode 100644 (file)
index 0000000..47fbefd
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Header file for RAII pid-file writer
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2009/06/09 09:07:32 $
+ $Author: faust $
+ */
+
+#ifndef __PID_FILE_H__
+#define __PID_FILE_H__
+
+#include <string>
+
+class PIDFile {
+public:
+    PIDFile(const std::string & fn);
+    ~PIDFile();
+private:
+    std::string fileName;
+};
+
+#endif
diff --git a/projects/stargazer/plugin_runner.cpp b/projects/stargazer/plugin_runner.cpp
new file mode 100644 (file)
index 0000000..180713c
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.17 $
+ $Date: 2010/09/13 05:52:46 $
+ $Author: faust $
+ */
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "plugin_runner.h"
+#include "common.h"
+#include "conffiles.h"
+
+//-----------------------------------------------------------------------------
+PLUGIN_RUNNER::PLUGIN_RUNNER(const string & pFileName,
+                             const MODULE_SETTINGS & ms,
+                             ADMINS * a,
+                             TARIFFS * t,
+                             USERS * u,
+                             TRAFFCOUNTER * tc,
+                             BASE_STORE * st,
+                             const SETTINGS * s)
+    : pluginFileName(pFileName),
+      pluginSettingFileName(),
+      plugin(NULL),
+      isPluginLoaded(false),
+      errorStr(),
+      libHandle(NULL),
+      isRunning(false),
+      admins(a),
+      tariffs(t),
+      users(u),
+      store(st),
+      traffCnt(tc),
+      stgSettings(s),
+      modSettings(ms)
+{
+}
+//-----------------------------------------------------------------------------
+PLUGIN_RUNNER::PLUGIN_RUNNER(const PLUGIN_RUNNER & rvalue)
+    : pluginFileName(rvalue.pluginFileName),
+      pluginSettingFileName(rvalue.pluginSettingFileName),
+      plugin(rvalue.plugin),
+      isPluginLoaded(rvalue.isPluginLoaded),
+      errorStr(rvalue.errorStr),
+      libHandle(rvalue.libHandle),
+      isRunning(rvalue.isRunning),
+      admins(rvalue.admins),
+      tariffs(rvalue.tariffs),
+      users(rvalue.users),
+      store(rvalue.store),
+      traffCnt(rvalue.traffCnt),
+      stgSettings(rvalue.stgSettings),
+      modSettings(rvalue.modSettings)
+{
+}
+//-----------------------------------------------------------------------------
+PLUGIN_RUNNER & PLUGIN_RUNNER::operator=(const PLUGIN_RUNNER & rvalue)
+{
+pluginFileName = rvalue.pluginFileName;
+pluginSettingFileName = rvalue.pluginSettingFileName;
+plugin = rvalue.plugin;
+isPluginLoaded = rvalue.isPluginLoaded;
+errorStr = rvalue.errorStr;
+libHandle = rvalue.libHandle;
+isRunning = rvalue.isRunning;
+admins = rvalue.admins;
+tariffs = rvalue.tariffs;
+users = rvalue.users;
+store = rvalue.store;
+traffCnt = rvalue.traffCnt;
+stgSettings = rvalue.stgSettings;
+modSettings = rvalue.modSettings;
+
+return *this;
+}
+//-----------------------------------------------------------------------------
+PLUGIN_RUNNER::~PLUGIN_RUNNER()
+{
+if (isPluginLoaded)
+    {
+    Unload();
+    }
+
+isPluginLoaded = 0;
+}
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * PLUGIN_RUNNER::GetPlugin()
+{
+return plugin;
+}
+//-----------------------------------------------------------------------------
+int PLUGIN_RUNNER::Start()
+{
+if (!isPluginLoaded)
+    if (Load())
+        return -1;
+
+plugin->SetTariffs(tariffs);
+plugin->SetAdmins(admins);
+plugin->SetUsers(users);
+plugin->SetTraffcounter(traffCnt);
+plugin->SetStore(store);
+plugin->SetStgSettings(stgSettings);
+
+if (plugin->Start())
+    {
+    errorStr = plugin->GetStrError();
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PLUGIN_RUNNER::Stop()
+{
+plugin->Stop();
+
+//if (Unload())
+//    return -1;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PLUGIN_RUNNER::Reload()
+{
+int res = plugin->Reload();
+errorStr = plugin->GetStrError();
+return res;
+}
+//-----------------------------------------------------------------------------
+bool PLUGIN_RUNNER::IsRunning()
+{
+if (!isPluginLoaded)
+    return false;
+return plugin->IsRunning();
+}
+//-----------------------------------------------------------------------------
+int PLUGIN_RUNNER::Load()
+{
+if (!pluginFileName.size())
+    {
+    errorStr = "Plugin loading failed. No plugin";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+libHandle = dlopen(pluginFileName.c_str(), RTLD_NOW);
+
+if (!libHandle)
+    {
+    errorStr = string("Plugin loading failed. ") + dlerror();
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+BASE_PLUGIN * (*GetPlugin)();
+GetPlugin = (BASE_PLUGIN * (*)())dlsym(libHandle, "GetPlugin");
+if (!GetPlugin)
+    {
+    errorStr = string("GetPlugin() not found. ") + dlerror();
+    return -1;
+    }
+plugin = GetPlugin();
+isPluginLoaded++;
+
+if (!plugin)
+    {
+    errorStr = "Plugin was not created!";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+plugin->SetSettings(modSettings);
+printfd(__FILE__, "Plugin %s parsesettings\n", plugin->GetVersion().c_str());
+if (plugin->ParseSettings())
+    {
+    errorStr = "Plugin \'" + plugin->GetVersion() + "\' error: " + plugin->GetStrError();
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PLUGIN_RUNNER::Unload()
+{
+if (isPluginLoaded)
+    {
+    if (dlclose(libHandle))
+        {
+        errorStr = dlerror();
+        printfd(__FILE__, "Error unloading plugin '%s': '%s'", pluginFileName.c_str(), dlerror());
+        return -1;
+        }
+    isPluginLoaded--;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & PLUGIN_RUNNER::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+uint16_t PLUGIN_RUNNER::GetStartPosition() const
+{
+return plugin->GetStartPosition();
+}
+//-----------------------------------------------------------------------------
+uint16_t PLUGIN_RUNNER::GetStopPosition() const
+{
+return plugin->GetStopPosition();
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugin_runner.h b/projects/stargazer/plugin_runner.h
new file mode 100644 (file)
index 0000000..2889300
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.13 $
+ $Date: 2010/03/04 12:22:41 $
+ $Author: faust $
+ */
+
+#ifndef PLUGIN_RUNNER_H
+#define PLUGIN_RUNNER_H
+#include <pthread.h>
+#include <string>
+
+#include "base_plugin.h"
+#include "base_settings.h"
+#include "traffcounter.h"
+#include "tariffs.h"
+#include "admins.h"
+#include "users.h"
+
+using namespace std;
+//-----------------------------------------------------------------------------
+class PLUGIN_RUNNER
+{
+public:
+    PLUGIN_RUNNER(const string & pluginFileName,
+                  const MODULE_SETTINGS & ms,
+                  ADMINS * admins,
+                  TARIFFS * tariffs,
+                  USERS * users,
+                  TRAFFCOUNTER * tc,
+                  BASE_STORE * store,
+                  const SETTINGS * s);
+    PLUGIN_RUNNER(const PLUGIN_RUNNER & rvalue);
+    ~PLUGIN_RUNNER();
+
+    PLUGIN_RUNNER & operator=(const PLUGIN_RUNNER & rvalue);
+
+    int             Start();
+    int             Stop();
+    int             Reload();
+    int             Restart();
+    bool            IsRunning();
+
+    const string &  GetStrError() const;
+    BASE_PLUGIN *   GetPlugin();
+    const string & GetFileName() const { return pluginFileName; };
+
+    int             Load();
+    int             Unload();
+
+    uint16_t        GetStartPosition() const;
+    uint16_t        GetStopPosition() const;
+
+private:
+    string          pluginFileName;
+    string          pluginSettingFileName;
+
+    BASE_PLUGIN *   plugin;
+    int             isPluginLoaded;
+    string          errorStr;
+
+    void *          libHandle;
+    bool            isRunning;
+
+    ADMINS *        admins;
+    TARIFFS *       tariffs;
+    USERS *         users;
+    BASE_STORE *    store;
+    TRAFFCOUNTER *  traffCnt;
+    const SETTINGS * stgSettings;
+    MODULE_SETTINGS modSettings;
+};
+//-----------------------------------------------------------------------------
+#endif //PLUGIN_RUNNER_H
+
+
diff --git a/projects/stargazer/plugins/Makefile b/projects/stargazer/plugins/Makefile
new file mode 100644 (file)
index 0000000..2163957
--- /dev/null
@@ -0,0 +1,20 @@
+###############################################################################
+# $Id: Makefile,v 1.1 2007/09/26 13:55:45 faust Exp $
+###############################################################################
+
+include ../../../Makefile.conf
+
+.PHONY: clean install uninstall
+.PHONY: all $(PLUGINS)
+
+all: $(PLUGINS)
+
+$(PLUGINS):
+       $(MAKE) $(MAKECMDGOALS) -C $@
+
+clean: all
+
+install: all
+
+uninstall: all
+
diff --git a/projects/stargazer/plugins/Makefile.in b/projects/stargazer/plugins/Makefile.in
new file mode 100644 (file)
index 0000000..90411bd
--- /dev/null
@@ -0,0 +1,43 @@
+###############################################################################
+# $Id: Makefile.in,v 1.11 2009/03/03 15:49:35 faust Exp $
+###############################################################################
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+LN = ln
+
+CXXFLAGS += -fPIC
+LDFLAGS += -shared -L$(DIR_LIB) -Wl,-rpath,$(PREFIX)/usr/lib/stg
+
+vpath %.so $(DIR_LIB)
+
+all: $(PROG)
+
+$(PROG): $(OBJS) $(STGLIBS)
+       $(CC) $^ $(LDFLAGS) $(LIBS) -o $(PROG)
+       $(LN) -fs "`pwd`/$(PROG)" $(DIR_MOD)/$(PROG)
+
+clean:
+       rm -f deps $(PROG) *.o tags *.*~
+
+install:
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/lib/stg
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/lib/stg/$(PROG)
+
+uninstall:
+       rm -f $(PREFIX)/usr/lib/stg/$(PROG)
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+
+deps:  $(SRCS) ../../../../../Makefile.conf
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(DEFS) $(SEARCH_DIRS) -MM $$file` Makefile ../../../../../Makefile.conf" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
diff --git a/projects/stargazer/plugins/authorization/ao/Makefile b/projects/stargazer/plugins/authorization/ao/Makefile
new file mode 100644 (file)
index 0000000..a47cea2
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.10 2008/12/04 15:41:03 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_auth_ao.so
+
+SRCS = ./ao.cpp
+
+STGLIBS = -lstg_common
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/authorization/ao/ao.cpp b/projects/stargazer/plugins/authorization/ao/ao.cpp
new file mode 100644 (file)
index 0000000..4463160
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+$Revision: 1.30 $
+$Date: 2010/03/04 12:29:06 $
+$Author: faust $
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "ao.h"
+#include "../../../user.h"
+#include "../../../eventloop.h"
+
+class AO_CREATOR
+{
+private:
+    AUTH_AO * ao;
+
+public:
+    AO_CREATOR()
+        : ao(new AUTH_AO())
+        {
+        };
+    ~AO_CREATOR()
+        {
+        delete ao;
+        };
+
+    AUTH_AO * GetPlugin()
+        {
+        return ao;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+AO_CREATOR aoc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// ëÌÁÓÓ ÄÌÑ ÐÏÉÓËÁ ÀÚÅÒÁ × ÓÐÉÓËÅ ÎÏÔÉÆÉËÁÔÏÒÏ×
+template <typename varType>
+class IS_CONTAINS_USER: public binary_function<varType, user_iter, bool>
+{
+public:
+    bool operator()(varType notifier, user_iter user) const
+        {
+        return notifier.GetUser() == user;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return aoc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string AUTH_AO::GetVersion() const
+{
+return "Always Online authorizator v.1.0";
+}
+//-----------------------------------------------------------------------------
+AUTH_AO::AUTH_AO()
+{
+isRunning = false;
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::SetUsers(USERS * u)
+{
+users = u;
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::ParseSettings()
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & AUTH_AO::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::Start()
+{
+GetUsers();
+
+list<user_iter>::iterator users_iter;
+
+onAddUserNotifier.SetAuthorizator(this);
+onDelUserNotifier.SetAuthorizator(this);
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+users_iter = usersList.begin();
+while (users_iter != usersList.end())
+    {
+    UpdateUserAuthorization(*users_iter);
+    ++users_iter;
+    }
+isRunning = true;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::Stop()
+{
+if (!isRunning)
+    return 0;
+
+users->DelNotifierUserAdd(&onAddUserNotifier);
+users->DelNotifierUserDel(&onDelUserNotifier);
+
+list<user_iter>::iterator users_iter;
+users_iter = usersList.begin();
+while (users_iter != usersList.end())
+    {
+    Unauthorize(*users_iter);
+    UnSetUserNotifiers(*users_iter);
+    ++users_iter;
+    }
+isRunning = false;
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool AUTH_AO::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+uint16_t AUTH_AO::GetStartPosition() const
+{
+return 70;
+}
+//-----------------------------------------------------------------------------
+uint16_t AUTH_AO::GetStopPosition() const
+{
+return 70;
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::SetUserNotifiers(user_iter u)
+{
+// ---------- AlwaysOnline -------------------
+CHG_BEFORE_NOTIFIER<int> BeforeChgAONotifier;
+CHG_AFTER_NOTIFIER<int>  AfterChgAONotifier;
+
+BeforeChgAONotifier.SetAuthorizator(this);
+BeforeChgAONotifier.SetUser(u);
+BeforeChgAONotifierList.push_front(BeforeChgAONotifier);
+
+AfterChgAONotifier.SetAuthorizator(this);
+AfterChgAONotifier.SetUser(u);
+AfterChgAONotifierList.push_front(AfterChgAONotifier);
+
+u->property.alwaysOnline.AddBeforeNotifier(&(*BeforeChgAONotifierList.begin()));
+u->property.alwaysOnline.AddAfterNotifier(&(*AfterChgAONotifierList.begin()));
+// ---------- AlwaysOnline end ---------------
+
+// ---------- IP -------------------
+CHG_BEFORE_NOTIFIER<USER_IPS> BeforeChgIPNotifier;
+CHG_AFTER_NOTIFIER<USER_IPS>  AfterChgIPNotifier;
+
+BeforeChgIPNotifier.SetAuthorizator(this);
+BeforeChgIPNotifier.SetUser(u);
+BeforeChgIPNotifierList.push_front(BeforeChgIPNotifier);
+
+AfterChgIPNotifier.SetAuthorizator(this);
+AfterChgIPNotifier.SetUser(u);
+AfterChgIPNotifierList.push_front(AfterChgIPNotifier);
+
+u->property.ips.AddBeforeNotifier(&(*BeforeChgIPNotifierList.begin()));
+u->property.ips.AddAfterNotifier(&(*AfterChgIPNotifierList.begin()));
+// ---------- IP end ---------------
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::UnSetUserNotifiers(user_iter u)
+{
+// ---      AlwaysOnline        ---
+IS_CONTAINS_USER<CHG_BEFORE_NOTIFIER<int> > IsContainsUserAOB;
+IS_CONTAINS_USER<CHG_AFTER_NOTIFIER<int> > IsContainsUserAOA;
+
+list<CHG_BEFORE_NOTIFIER<int> >::iterator aoBIter;
+list<CHG_AFTER_NOTIFIER<int> >::iterator  aoAIter;
+
+aoBIter = find_if(BeforeChgAONotifierList.begin(),
+                  BeforeChgAONotifierList.end(),
+                  bind2nd(IsContainsUserAOB, u));
+
+if (aoBIter != BeforeChgAONotifierList.end())
+    {
+    aoBIter->GetUser()->property.alwaysOnline.DelBeforeNotifier(&(*aoBIter));
+    BeforeChgAONotifierList.erase(aoBIter);
+    }
+
+aoAIter = find_if(AfterChgAONotifierList.begin(),
+                  AfterChgAONotifierList.end(),
+                  bind2nd(IsContainsUserAOA, u));
+
+if (aoAIter != AfterChgAONotifierList.end())
+    {
+    aoAIter->GetUser()->property.alwaysOnline.DelAfterNotifier(&(*aoAIter));
+    AfterChgAONotifierList.erase(aoAIter);
+    }
+// ---      AlwaysOnline end    ---
+
+// ---          IP              ---
+IS_CONTAINS_USER<CHG_BEFORE_NOTIFIER<USER_IPS> > IsContainsUserIPB;
+IS_CONTAINS_USER<CHG_AFTER_NOTIFIER<USER_IPS> >  IsContainsUserIPA;
+
+list<CHG_BEFORE_NOTIFIER<USER_IPS> >::iterator ipBIter;
+list<CHG_AFTER_NOTIFIER<USER_IPS> >::iterator  ipAIter;
+
+ipBIter = find_if(BeforeChgIPNotifierList.begin(),
+                  BeforeChgIPNotifierList.end(),
+                  bind2nd(IsContainsUserIPB, u));
+
+if (ipBIter != BeforeChgIPNotifierList.end())
+    {
+    ipBIter->GetUser()->property.ips.DelBeforeNotifier(&(*ipBIter));
+    BeforeChgIPNotifierList.erase(ipBIter);
+    }
+
+ipAIter = find_if(AfterChgIPNotifierList.begin(),
+                  AfterChgIPNotifierList.end(),
+                  bind2nd(IsContainsUserIPA, u));
+
+if (ipAIter != AfterChgIPNotifierList.end())
+    {
+    ipAIter->GetUser()->property.ips.DelAfterNotifier(&(*ipAIter));
+    AfterChgIPNotifierList.erase(ipAIter);
+    }
+// ---          IP end          ---
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::GetUsers()
+{
+user_iter u;
+int h = users->OpenSearch();
+if (!h)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    return;
+    }
+
+while (1)
+    {
+    if (users->SearchNext(h, &u))
+        {
+        break;
+        }
+    usersList.push_back(u);
+    SetUserNotifiers(u);
+    }
+
+users->CloseSearch(h);
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::Unauthorize(user_iter u) const
+{
+u->Unauthorize(this);
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::UpdateUserAuthorization(user_iter u) const
+{
+if (u->property.alwaysOnline)
+    {
+    USER_IPS ips = u->property.ips;
+    if (ips.OnlyOneIP())
+        {
+        if (u->Authorize(ips[0].ip, "", 0xFFffFFff, this) == 0)
+            {
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::AddUser(user_iter u)
+{
+SetUserNotifiers(u);
+usersList.push_back(u);
+UpdateUserAuthorization(u);
+}
+//-----------------------------------------------------------------------------
+void AUTH_AO::DelUser(user_iter u)
+{
+Unauthorize(u);
+UnSetUserNotifiers(u);
+
+list<user_iter>::iterator users_iter;
+users_iter = usersList.begin();
+
+while (users_iter != usersList.end())
+    {
+    if (u == *users_iter)
+        {
+        usersList.erase(users_iter);
+        break;
+        }
+    ++users_iter;
+    }
+}
+//-----------------------------------------------------------------------------
+int AUTH_AO::SendMessage(const STG_MSG &, uint32_t) const
+{
+errorStr = "Authorization modele \'AlwaysOnline\' does not support sending messages";
+return -1;
+}
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void CHG_BEFORE_NOTIFIER<varParamType>::Notify(const varParamType &, const varParamType &)
+{
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(*auth, &AUTH_AO::Unauthorize, user);
+}
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void CHG_AFTER_NOTIFIER<varParamType>::Notify(const varParamType &, const varParamType &)
+{
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(*auth, &AUTH_AO::UpdateUserAuthorization, user);
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/authorization/ao/ao.h b/projects/stargazer/plugins/authorization/ao/ao.h
new file mode 100644 (file)
index 0000000..f2912d1
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.21 $
+ $Date: 2010/09/10 06:38:26 $
+ $Author: faust $
+*/
+
+#ifndef AO_H
+#define AO_H
+
+#include <string>
+#include <pthread.h>
+#include "base_auth.h"
+#include "base_store.h"
+#include "notifer.h"
+#include "user_ips.h"
+#include "../../../users.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class AUTH_AO;
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class CHG_BEFORE_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void        Notify(const varParamType & oldValue, const varParamType & newValue);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetAuthorizator(const AUTH_AO * a) { auth = a; }
+
+private:
+    user_iter   user;
+    const       AUTH_AO * auth;
+};
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class CHG_AFTER_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void        Notify(const varParamType & oldValue, const varParamType & newValue);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetAuthorizator(const AUTH_AO * a) { auth = a; }
+
+private:
+    user_iter   user;
+    const AUTH_AO * auth;
+};
+//-----------------------------------------------------------------------------
+class AUTH_AO_SETTINGS
+{
+public:
+    const string& GetStrError() const { static string s; return s; }
+    int ParseSettings(const MODULE_SETTINGS &) { return 0; }
+};
+//-----------------------------------------------------------------------------
+class AUTH_AO :public BASE_AUTH
+{
+public:
+    AUTH_AO();
+    virtual ~AUTH_AO(){};
+
+    void                SetUsers(USERS * u);
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER *){};
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS *){};
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+    void                AddUser(user_iter u);
+    void                DelUser(user_iter u);
+
+    void                UpdateUserAuthorization(user_iter u) const;
+    void                Unauthorize(user_iter u) const;
+
+    int                 SendMessage(const STG_MSG & msg, uint32_t ip) const;
+
+private:
+    void                GetUsers();
+    void                SetUserNotifiers(user_iter u);
+    void                UnSetUserNotifiers(user_iter u);
+
+    mutable string      errorStr;
+    AUTH_AO_SETTINGS    aoSettings;
+    USERS             * users;
+    list<user_iter>     usersList;
+    bool                isRunning;
+    MODULE_SETTINGS     settings;
+
+    /*
+    ÍÙ ÄÏÌÖÎÙ ÐÅÒÅÐÒÏ×ÅÒÉÔØ ×ÏÚÍÏÖÎÏÓÔØ Á×ÔÏÒÉÚÁÃÉÉ ÀÚÅÒÁ ÐÒÉ ÉÚÍÅÎÅÎÉÉ
+    ÓÌÅÄÕÀÝÉÈ ÅÇÏ ÐÁÒÁÍÅÔÒÏ×:
+    - alwaysOnline
+    - ips
+    */
+
+    list<CHG_BEFORE_NOTIFIER<int> >         BeforeChgAONotifierList;
+    list<CHG_AFTER_NOTIFIER<int> >          AfterChgAONotifierList;
+
+    list<CHG_BEFORE_NOTIFIER<USER_IPS> >    BeforeChgIPNotifierList;
+    list<CHG_AFTER_NOTIFIER<USER_IPS> >     AfterChgIPNotifierList;
+
+    class ADD_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+    {
+    public:
+        ADD_USER_NONIFIER(){};
+        virtual ~ADD_USER_NONIFIER(){};
+
+        void SetAuthorizator(AUTH_AO * a) { auth = a; }
+        void Notify(const user_iter & user)
+            {
+            auth->AddUser(user);
+            }
+
+    private:
+        AUTH_AO * auth;
+    } onAddUserNotifier;
+
+    class DEL_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+    {
+    public:
+        DEL_USER_NONIFIER(){};
+        virtual ~DEL_USER_NONIFIER(){};
+
+        void SetAuthorizator(AUTH_AO * a) { auth = a; }
+        void Notify(const user_iter & user)
+            {
+            auth->DelUser(user);
+            }
+
+    private:
+        AUTH_AO * auth;
+    } onDelUserNotifier;
+
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
+
diff --git a/projects/stargazer/plugins/authorization/inetaccess/Makefile b/projects/stargazer/plugins/authorization/inetaccess/Makefile
new file mode 100644 (file)
index 0000000..6299771
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.10 2010/02/16 11:41:00 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+LIBS += $(LIB_THREAD)
+
+PROG = mod_auth_ia.so
+
+SRCS = ./inetaccess.cpp
+
+STGLIBS = -lstg_common -lstg_crypto
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/authorization/inetaccess/antiflood.cpp b/projects/stargazer/plugins/authorization/inetaccess/antiflood.cpp
new file mode 100644 (file)
index 0000000..86790e0
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *    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@ua.fm>
+ */
+
+
+#include <string.h>
+
+#include "antiflood.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+int FloodIPCompare(void * p1, void * p2)
+{
+/*
+óÒÁ×ÎÉ×ÁÅÍ Ä×Á éð × ÓÔÒÕËÔÒÕ Ó ÁÎÔÉÆÌÕÄÏÍ
+ * */
+
+FLOOD_NODE * n1, *n2;
+
+n1 = (FLOOD_NODE *)p1;
+n2 = (FLOOD_NODE *)p2;
+printfd(__FILE__, "FloodIPCompare %X %X\n", n1->ip, n2->ip);
+return n1->ip - n2->ip;
+}
+//-----------------------------------------------------------------------------
+ANTIFLOOD::ANTIFLOOD():
+floodTree(FloodIPCompare)
+{
+/*
+óÒÅÄÎÅÅ ÎÁÉÍÅÎØÛÅÅ ÒÁÚÒÅÛÅÎÎÏÅ ×ÒÅÍÑ ÍÅÖÄÕ ÐÁËÅÔÁÍÉ. ÍÓ.
+ * */
+
+avrgTime = 500;
+}
+//-----------------------------------------------------------------------------
+bool ANTIFLOOD::AllowIP(uint32_t ip, bool * logged)
+{
+/*
+ðÒÏ×ÅÒËÁ ÔÏÇÏ ÎÅ ÓÌÉÛËÏÍ ÌÉ ÞÁÓÔÏ ÐÒÉÈÏÄÑÔ ÐÁËÅÔÙ Ó ÕËÁÚÁÎÎÏÇÏ ÁÊÐÉÛÎÉËÁ
+ * */
+
+BSPNODE * findNode;
+FLOOD_NODE floodNode;
+
+floodNode.ip = ip;
+findNode = floodTree.Find(&floodNode);
+
+gettimeofday(&tv, NULL);
+currentTime = ((uint64_t)tv.tv_sec)*1000 + ((uint64_t)tv.tv_usec)/1000;
+
+if (findNode == NULL)
+    {
+    AddNode(ip);
+    printfd(__FILE__, "AddNode(%X)\n", ip);
+    return true;
+    }
+else
+    {
+    printfd(__FILE__, "UpdateNodeTime(%X)\n", findNode->record);
+    UpdateNodeTime((FLOOD_NODE*)(findNode->record));
+    }
+
+if (currentTime - CalcAvrgNodeTime((FLOOD_NODE*)findNode->record) < avrgTime)
+    {
+    if (((FLOOD_NODE*)findNode->record)->logged == false)
+        {
+        *logged = false;
+        ((FLOOD_NODE*)findNode->record)->logged = true;
+        //floodNode.logged = true;
+        }
+    else
+        {
+        *logged = true;
+        }
+    return false;
+    }
+
+((FLOOD_NODE*)findNode->record)->logged = false;
+return true;
+}
+//-----------------------------------------------------------------------------
+void ANTIFLOOD::UpdateNodeTime(FLOOD_NODE * node)
+{
+/*
+ïÂÎÏ×ÌÑÅÍ ×ÒÅÍÑ ÐÏÓÌÅÄÎÅÇÏ ÐÒÅÛÅÄÛÅÇÏ ÐÁËÅÔÁ
+ * */
+
+node->timeIP[node->pos] = currentTime;
+
+node->pos++;
+if (node->pos >= FLOOD_LBL_MAX)
+    node->pos = 0;
+
+}
+//-----------------------------------------------------------------------------
+void ANTIFLOOD::Clean()
+{
+/*
+þÍÓÔËÁ ÄÅÒÅ×Á ÓÏ ÓÌÉÛËÏÍ ÓÔÁÒÙÍÉ ÄÁÎÎÙÍÉ
+ * */
+
+BSPNODE * bspNode = floodTree.Max(floodTree.GetRoot());
+FLOOD_NODE * n;
+BSPNODE * delNode;
+currentTime = ((uint64_t)tv.tv_sec)*1000 + ((uint64_t)tv.tv_usec)/1000;
+
+while (bspNode)
+    {
+    n = (FLOOD_NODE*)bspNode->record;
+    if (currentTime - CalcAvrgNodeTime(n) > 2 * 60)
+        {
+        delNode = floodTree.Delete(bspNode);
+        delete (FLOOD_NODE*)delNode->record;
+        delete delNode;
+        }
+    bspNode = floodTree.Max(floodTree.GetRoot());
+    }
+
+printfd(__FILE__, "after clean max=%X\n", floodTree.Max(floodTree.GetRoot()));
+printfd(__FILE__, "after clean min=%X\n", floodTree.Min(floodTree.GetRoot()));
+
+}
+//-----------------------------------------------------------------------------
+void ANTIFLOOD::AddNode(uint32_t ip)
+{
+/*
+äÏÂÁ×ÌÑÅÍ ÎÏ×ÙÊ éð × ÄÅÒÅ×Ï
+ * */
+
+FLOOD_NODE * fn;
+BSPNODE * node;
+
+fn = new FLOOD_NODE;
+
+fn->pos = 0;
+fn->ip = ip;
+fn->logged = false;
+
+memset(fn->timeIP, 0, sizeof(uint64_t) * FLOOD_LBL_MAX);
+fn->timeIP[0] = currentTime;
+
+node = new BSPNODE;
+node->record = fn;
+
+floodTree.Add(node);
+}
+//-----------------------------------------------------------------------------
+uint64_t ANTIFLOOD::CalcAvrgNodeTime(FLOOD_NODE * fn)
+{
+/*
+÷ÙÞÉÓÌÑÅÍ ÓÒÅÄÎÅÅ ×ÒÅÍÑ ÐÏÓÌÅÄÎÉÈ ÐÒÅÛÅÄÛÉÈ ÐÁËÅÔÏ×
+ * */
+
+uint64_t t = 0;
+for (int i = 0; i < FLOOD_LBL_MAX; i++)
+    t += fn->timeIP[i];
+
+printfd(__FILE__, "node time %lld\n", t/FLOOD_LBL_MAX);
+printfd(__FILE__, "current time %lld\n", currentTime);
+
+return t/FLOOD_LBL_MAX;
+}
+//-----------------------------------------------------------------------------
+void ANTIFLOOD::SetAvrgTime(uint64_t t)
+{
+avrgTime = t;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/plugins/authorization/inetaccess/antiflood.h b/projects/stargazer/plugins/authorization/inetaccess/antiflood.h
new file mode 100644 (file)
index 0000000..2c0f596
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *    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@ua.fm>
+ */
+
+
+#ifndef ANTIFLOOD_H
+#define ANTIFLOOD_H
+
+
+#include <sys/time.h>
+
+#include "bsp.h"
+#include "os_int.h"
+
+#define FLOOD_LBL_MAX   (10)
+
+//-----------------------------------------------------------------------------
+struct FLOOD_NODE
+{
+uint32_t ip;
+uint64_t timeIP[FLOOD_LBL_MAX];
+int pos;
+bool logged;
+};
+
+//-----------------------------------------------------------------------------
+class ANTIFLOOD
+{
+public:
+    ANTIFLOOD();
+    bool AllowIP(uint32_t ip, bool * logged);
+    void Clean();
+    void SetAvrgTime(uint64_t);
+
+private:
+    uint64_t CalcAvrgNodeTime(FLOOD_NODE * fn);
+    void AddNode(uint32_t ip);
+    void UpdateNodeTime(FLOOD_NODE * node);
+
+    TREE floodTree;
+    struct timeval tv;
+    uint64_t avrgTime;
+    uint64_t currentTime;
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
+
+
+
diff --git a/projects/stargazer/plugins/authorization/inetaccess/inetaccess.cpp b/projects/stargazer/plugins/authorization/inetaccess/inetaccess.cpp
new file mode 100644 (file)
index 0000000..0d2dbe2
--- /dev/null
@@ -0,0 +1,1840 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.79 $
+ $Date: 2010/03/25 15:18:48 $
+ $Author: faust $
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <csignal>
+#include <cstdlib>
+#include <algorithm>
+
+#include "inetaccess.h"
+#include "common.h"
+
+extern volatile const time_t stgTime;
+
+//-----------------------------------------------------------------------------
+class IA_CREATOR
+{
+private:
+    AUTH_IA * ia;
+
+public:
+    IA_CREATOR()
+        : ia(new AUTH_IA())
+        {
+        };
+    ~IA_CREATOR()
+        {
+        delete ia;
+        };
+
+    AUTH_IA * GetPlugin()
+    {
+        return ia;
+    };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+IA_CREATOR iac;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return iac.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+AUTH_IA_SETTINGS::AUTH_IA_SETTINGS()
+    : userDelay(0),
+      userTimeout(0),
+      port(0),
+      freeMbShowType(freeMbCash)
+{
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    printfd(__FILE__, "Parameter 'Port' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+    return -1;
+    }
+port = p;
+///////////////////////////
+pv.param = "UserDelay";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'UserDelay\' not found.";
+    printfd(__FILE__, "Parameter 'UserDelay' not found\n");
+    return -1;
+    }
+
+if (ParseIntInRange(pvi->value[0], 5, 600, &userDelay))
+    {
+    errorStr = "Cannot parse parameter \'UserDelay\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'UserDelay'\n");
+    return -1;
+    }
+///////////////////////////
+pv.param = "UserTimeout";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'UserTimeout\' not found.";
+    printfd(__FILE__, "Parameter 'UserTimeout' not found\n");
+    return -1;
+    }
+
+if (ParseIntInRange(pvi->value[0], 15, 1200, &userTimeout))
+    {
+    errorStr = "Cannot parse parameter \'UserTimeout\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'UserTimeout'\n");
+    return -1;
+    }
+/////////////////////////////////////////////////////////////
+string freeMbType;
+int n = 0;
+pv.param = "FreeMb";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'FreeMb\' not found.";
+    printfd(__FILE__, "Parameter 'FreeMb' not found\n");
+    return -1;
+    }
+freeMbType = pvi->value[0];
+
+if (strcasecmp(freeMbType.c_str(), "cash") == 0)
+    {
+    freeMbShowType = freeMbCash;
+    }
+else if (strcasecmp(freeMbType.c_str(), "none") == 0)
+    {
+    freeMbShowType = freeMbNone;
+    }
+else if (!str2x(freeMbType.c_str(), n))
+    {
+    if (n < 0 || n >= DIR_NUM)
+        {
+        errorStr = "Incorrect parameter \'" + freeMbType + "\'.";
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+    freeMbShowType = (FREEMB)(freeMb0 + n);
+    }
+else
+    {
+    errorStr = "Incorrect parameter \'" + freeMbType + "\'.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+/////////////////////////////////////////////////////////////
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+#ifdef IA_PHASE_DEBUG
+IA_PHASE::IA_PHASE()
+    : phase(1),
+      flog(NULL)
+{
+gettimeofday(&phaseTime, NULL);
+}
+#else
+IA_PHASE::IA_PHASE()
+    : phase(1)
+{
+gettimeofday(&phaseTime, NULL);
+}
+#endif
+//-----------------------------------------------------------------------------
+IA_PHASE::~IA_PHASE()
+{
+#ifdef IA_PHASE_DEBUG
+flog = fopen(log.c_str(), "at");
+if (flog)
+    {
+    fprintf(flog, "IA %s D\n", login.c_str());
+    fclose(flog);
+    }
+#endif
+}
+//-----------------------------------------------------------------------------
+#ifdef IA_PHASE_DEBUG
+void IA_PHASE::SetLogFileName(const string & logFileName)
+{
+log = logFileName + ".ia.log";
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetUserLogin(const string & login)
+{
+IA_PHASE::login = login;
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::WritePhaseChange(int newPhase)
+{
+UTIME newPhaseTime;
+gettimeofday(&newPhaseTime, NULL);
+flog = fopen(log.c_str(), "at");
+/*int64_t tn = newPhaseTime.GetSec()*1000000 + newPhaseTime.GetUSec();
+int64_t to = phaseTime.GetSec()*1000000 + phaseTime.GetUSec();*/
+if (flog)
+    {
+    string action = newPhase == phase ? "U" : "C";
+    double delta = newPhaseTime.GetSec() - phaseTime.GetSec();
+    delta += (newPhaseTime.GetUSec() - phaseTime.GetUSec()) * 1.0e-6;
+    fprintf(flog, "IA %s %s oldPhase = %d, newPhase = %d. dt = %.6f\n",
+            login.c_str(),
+            action.c_str(),
+            phase,
+            newPhase,
+            delta);
+    fclose(flog);
+    }
+}
+#endif
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase1()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(1);
+#endif
+phase = 1;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase2()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(2);
+#endif
+phase = 2;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase3()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(3);
+#endif
+phase = 3;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase4()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(4);
+#endif
+phase = 4;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::SetPhase5()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(5);
+#endif
+phase = 5;
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+int IA_PHASE::GetPhase() const
+{
+return phase;
+}
+//-----------------------------------------------------------------------------
+void IA_PHASE::UpdateTime()
+{
+#ifdef IA_PHASE_DEBUG
+WritePhaseChange(phase);
+#endif
+gettimeofday(&phaseTime, NULL);
+}
+//-----------------------------------------------------------------------------
+const UTIME & IA_PHASE::GetTime() const
+{
+return phaseTime;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+AUTH_IA::AUTH_IA()
+    : nonstop(false),
+      isRunningRun(false),
+      isRunningRunTimeouter(false),
+      WriteServLog(GetStgLogger()),
+      enabledDirs(0xFFffFFff),
+      onDelUserNotifier(*this)
+{
+InitEncrypt(&ctxS, "pr7Hhen");
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+
+memset(&connSynAck6, 0, sizeof(CONN_SYN_ACK_6));
+memset(&connSynAck8, 0, sizeof(CONN_SYN_ACK_8));
+memset(&disconnSynAck6, 0, sizeof(DISCONN_SYN_ACK_6));
+memset(&disconnSynAck8, 0, sizeof(DISCONN_SYN_ACK_8));
+memset(&aliveSyn6, 0, sizeof(ALIVE_SYN_6));
+memset(&aliveSyn8, 0, sizeof(ALIVE_SYN_8));
+memset(&fin6, 0, sizeof(FIN_6));
+memset(&fin8, 0, sizeof(FIN_8));
+
+printfd(__FILE__, "sizeof(CONN_SYN_6) = %d %d\n",           sizeof(CONN_SYN_6),     Min8(sizeof(CONN_SYN_6)));
+printfd(__FILE__, "sizeof(CONN_SYN_8) = %d %d\n",           sizeof(CONN_SYN_8),     Min8(sizeof(CONN_SYN_8)));
+printfd(__FILE__, "sizeof(CONN_SYN_ACK_6) = %d %d\n",       sizeof(CONN_SYN_ACK_6), Min8(sizeof(CONN_SYN_ACK_6)));
+printfd(__FILE__, "sizeof(CONN_SYN_ACK_8) = %d %d\n",       sizeof(CONN_SYN_ACK_8), Min8(sizeof(CONN_SYN_ACK_8)));
+printfd(__FILE__, "sizeof(CONN_ACK_6) = %d %d\n",           sizeof(CONN_ACK_6),     Min8(sizeof(CONN_ACK_6)));
+printfd(__FILE__, "sizeof(ALIVE_SYN_6) = %d %d\n",          sizeof(ALIVE_SYN_6),    Min8(sizeof(ALIVE_SYN_6)));
+printfd(__FILE__, "sizeof(ALIVE_SYN_8) = %d %d\n",          sizeof(ALIVE_SYN_8),    Min8(sizeof(ALIVE_SYN_8)));
+printfd(__FILE__, "sizeof(ALIVE_ACK_6) = %d %d\n",          sizeof(ALIVE_ACK_6),    Min8(sizeof(ALIVE_ACK_6)));
+printfd(__FILE__, "sizeof(DISCONN_SYN_6) = %d %d\n",        sizeof(DISCONN_SYN_6),  Min8(sizeof(DISCONN_SYN_6)));
+printfd(__FILE__, "sizeof(DISCONN_SYN_ACK_6) = %d %d\n",    sizeof(DISCONN_SYN_ACK_6), Min8(sizeof(DISCONN_SYN_ACK_6)));
+printfd(__FILE__, "sizeof(DISCONN_SYN_ACK_8) = %d %d\n",    sizeof(DISCONN_SYN_ACK_8), Min8(sizeof(DISCONN_SYN_ACK_8)));
+printfd(__FILE__, "sizeof(DISCONN_ACK_6) = %d %d\n",        sizeof(DISCONN_ACK_6),  Min8(sizeof(DISCONN_ACK_6)));
+printfd(__FILE__, "sizeof(FIN_6) = %d %d\n",                sizeof(FIN_6),          Min8(sizeof(FIN_6)));
+printfd(__FILE__, "sizeof(FIN_8) = %d %d\n",                sizeof(FIN_8),          Min8(sizeof(FIN_8)));
+printfd(__FILE__, "sizeof(ERR) = %d %d\n",                  sizeof(ERR),            Min8(sizeof(ERR)));
+printfd(__FILE__, "sizeof(INFO_6) = %d %d\n",               sizeof(INFO_6),         Min8(sizeof(INFO_6)));
+printfd(__FILE__, "sizeof(INFO_7) = %d %d\n",               sizeof(INFO_7),         Min8(sizeof(INFO_7)));
+printfd(__FILE__, "sizeof(INFO_8) = %d %d\n",               sizeof(INFO_8),         Min8(sizeof(INFO_8)));
+
+packetTypes["CONN_SYN"] = CONN_SYN_N;
+packetTypes["CONN_SYN_ACK"] = CONN_SYN_ACK_N;
+packetTypes["CONN_ACK"] = CONN_ACK_N;
+packetTypes["ALIVE_SYN"] = ALIVE_SYN_N;
+packetTypes["ALIVE_ACK"] = ALIVE_ACK_N;
+packetTypes["DISCONN_SYN"] = DISCONN_SYN_N;
+packetTypes["DISCONN_SYN_ACK"] = DISCONN_SYN_ACK_N;
+packetTypes["DISCONN_ACK"] = DISCONN_ACK_N;
+packetTypes["FIN"] = FIN_N;
+packetTypes["ERR"] = ERROR_N;
+}
+//-----------------------------------------------------------------------------
+AUTH_IA::~AUTH_IA()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Start()
+{
+users->AddNotifierUserDel(&onDelUserNotifier);
+nonstop = true;
+
+if (PrepareNet())
+    {
+    return -1;
+    }
+
+if (!isRunningRun)
+    {
+    if (pthread_create(&recvThread, NULL, Run, this))
+        {
+        errorStr = "Cannot create thread.";
+        printfd(__FILE__, "Cannot create recv thread\n");
+        return -1;
+        }
+    }
+
+if (!isRunningRunTimeouter)
+    {
+    if (pthread_create(&timeouterThread, NULL, RunTimeouter, this))
+        {
+        errorStr = "Cannot create thread.";
+        printfd(__FILE__, "Cannot create timeouter thread\n");
+        return -1;
+        }
+    }
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Stop()
+{
+if (!IsRunning())
+    return 0;
+
+nonstop = false;
+
+std::for_each(
+        ip2user.begin(),
+        ip2user.end(),
+        UnauthorizeUser(this)
+        );
+
+if (isRunningRun)
+    {
+    //5 seconds to thread stops itself
+    for (int i = 0; i < 25 && isRunningRun; i++)
+        {
+        usleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (isRunningRun)
+        {
+        //TODO pthread_cancel()
+        if (pthread_kill(recvThread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            printfd(__FILE__, "Cannot kill thread\n");
+            return -1;
+            }
+        for (int i = 0; i < 25 && isRunningRun; ++i)
+            usleep(200000);
+        if (isRunningRun)
+            {
+            printfd(__FILE__, "Failed to stop recv thread\n");
+            }
+        else
+            {
+            pthread_join(recvThread, NULL);
+            }
+        printfd(__FILE__, "AUTH_IA killed Run\n");
+        }
+    }
+
+FinalizeNet();
+
+if (isRunningRunTimeouter)
+    {
+    //5 seconds to thread stops itself
+    for (int i = 0; i < 25 && isRunningRunTimeouter; i++)
+        {
+        usleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (isRunningRunTimeouter)
+        {
+        //TODO pthread_cancel()
+        if (pthread_kill(timeouterThread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            return -1;
+            }
+        for (int i = 0; i < 25 && isRunningRunTimeouter; ++i)
+            usleep(200000);
+        if (isRunningRunTimeouter)
+            {
+            printfd(__FILE__, "Failed to stop timeouter thread\n");
+            }
+        else
+            {
+            pthread_join(timeouterThread, NULL);
+            }
+        printfd(__FILE__, "AUTH_IA killed Timeouter\n");
+        }
+    }
+printfd(__FILE__, "AUTH_IA::Stoped successfully.\n");
+users->DelNotifierUserDel(&onDelUserNotifier);
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * AUTH_IA::Run(void * d)
+{
+AUTH_IA * ia = static_cast<AUTH_IA *>(d);
+
+ia->isRunningRun = true;
+
+char buffer[512];
+
+time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+
+while (ia->nonstop)
+    {
+    ia->RecvData(buffer, sizeof(buffer));
+    if ((touchTime + MONITOR_TIME_DELAY_SEC <= stgTime) && ia->stgSettings->GetMonitoring())
+        {
+        touchTime = stgTime;
+        string monFile = ia->stgSettings->GetMonitorDir() + "/inetaccess_r";
+        TouchFile(monFile.c_str());
+        }
+    }
+
+ia->isRunningRun = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void * AUTH_IA::RunTimeouter(void * d)
+{
+AUTH_IA * ia = static_cast<AUTH_IA *>(d);
+
+ia->isRunningRunTimeouter = true;
+
+int a = -1;
+string monFile = ia->stgSettings->GetMonitorDir() + "/inetaccess_t";
+while (ia->nonstop)
+    {
+    usleep(20000);
+    ia->Timeouter();
+    // TODO cahange counter to timer and MONITOR_TIME_DELAY_SEC
+    if (++a % (50*60) == 0 && ia->stgSettings->GetMonitoring())
+        {
+        TouchFile(monFile.c_str());
+        }
+    }
+
+ia->isRunningRunTimeouter = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::ParseSettings()
+{
+int ret = iaSettings.ParseSettings(settings);
+if (ret)
+    errorStr = iaSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::PrepareNet()
+{
+struct sockaddr_in listenAddr;
+
+listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (listenSocket < 0)
+    {
+    errorStr = "Cannot create socket.";
+    return -1;
+    }
+
+listenAddr.sin_family = AF_INET;
+listenAddr.sin_port = htons(iaSettings.GetUserPort());
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+if (bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0)
+    {
+    errorStr = "AUTH_IA: Bind failed.";
+    return -1;
+    }
+
+/*int buffLen;
+if (getsockopt(listenSocket, SOL_SOCKET, SO_SNDBUF, &buffLen, sizeof(buffLen)) < 0)
+    {
+
+    errorStr = "Getsockopt failed. " + string(strerror(errno));
+    return -1;
+    }*/
+
+//WriteServLog("buffLen = %d", buffLen);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::FinalizeNet()
+{
+close(listenSocket);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RecvData(char * buffer, int bufferSize)
+{
+if (!WaitPackets(listenSocket)) // Timeout
+    {
+    return 0;
+    }
+
+struct sockaddr_in outerAddr;
+socklen_t outerAddrLen(sizeof(outerAddr));
+int dataLen = recvfrom(listenSocket, buffer, bufferSize, 0, (struct sockaddr *)&outerAddr, &outerAddrLen);
+
+if (!dataLen) // EOF
+    {
+    return 0;
+    }
+
+if (dataLen <= 0) // Error
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "recvfrom res=%d, error: '%s'\n", dataLen, strerror(errno));
+        return -1;
+        }
+    return 0;
+    }
+
+if (dataLen > 256)
+    return -1;
+
+int protoVer;
+if (CheckHeader(buffer, &protoVer))
+    return -1;
+
+char login[PASSWD_LEN];  //TODO why PASSWD_LEN ?
+memset(login, 0, PASSWD_LEN);
+
+Decrypt(&ctxS, login, buffer + 8, PASSWD_LEN / 8);
+
+uint32_t sip = *((uint32_t*)&outerAddr.sin_addr);
+uint16_t sport = htons(outerAddr.sin_port);
+
+user_iter user;
+if (users->FindByName(login, &user) == 0)
+    {
+    printfd(__FILE__, "User %s FOUND!\n", user->GetLogin().c_str());
+    PacketProcessor(buffer, dataLen, sip, sport, protoVer, &user);
+    }
+else
+    {
+    WriteServLog("User\'s connect failed:: user \'%s\' not found. IP \'%s\'",
+                 login,
+                 inet_ntostring(sip).c_str());
+    printfd(__FILE__, "User %s NOT found!\n", login);
+    SendError(sip, sport, protoVer, "îÅÐÒÁ×ÉÌØÎÙÊ ÌÏÇÉΠÉÌÉ ÐÁÒÏÌØ!");
+    }
+
+return 0;
+
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::CheckHeader(const char * buffer, int * protoVer)
+{
+if (strncmp(IA_ID, buffer, strlen(IA_ID)) != 0)
+    {
+    //SendError(userIP, updateMsg);
+    printfd(__FILE__, "update needed - IA_ID\n");
+    //SendError(userIP, "Incorrect header!");
+    return -1;
+    }
+
+if (buffer[6] != 0) //proto[0] shoud be 0
+    {
+    printfd(__FILE__, "update needed - PROTO major: %d\n", buffer[6]);
+    //SendError(userIP, updateMsg);
+    return -1;
+    }
+
+if (buffer[7] < 6)
+    {
+    // need update
+    //SendError(userIP, updateMsg);
+    printfd(__FILE__, "update needed - PROTO minor: %d\n", buffer[7]);
+    return -1;
+    }
+else
+    {
+    *protoVer = buffer[7];
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Timeouter()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+map<uint32_t, IA_USER>::iterator it;
+it = ip2user.begin();
+uint32_t sip;
+
+while (it != ip2user.end())
+    {
+    sip = it->first;
+
+    static UTIME currTime;
+    gettimeofday(&currTime, NULL);
+
+    if ((it->second.phase.GetPhase() == 2)
+        && (currTime - it->second.phase.GetTime()) > iaSettings.GetUserDelay())
+        {
+        it->second.phase.SetPhase1();
+        printfd(__FILE__, "Phase changed from 2 to 1. Reason: timeout\n");
+        }
+
+    if (it->second.phase.GetPhase() == 3)
+        {
+        if (!it->second.messagesToSend.empty())
+            {
+            if (it->second.protoVer == 6)
+                RealSendMessage6(*it->second.messagesToSend.begin(), sip, it->second);
+
+            if (it->second.protoVer == 7)
+                RealSendMessage7(*it->second.messagesToSend.begin(), sip, it->second);
+
+            if (it->second.protoVer == 8)
+                RealSendMessage8(*it->second.messagesToSend.begin(), sip, it->second);
+
+            it->second.messagesToSend.erase(it->second.messagesToSend.begin());
+            }
+
+        if((currTime - it->second.lastSendAlive) > iaSettings.GetUserDelay())
+            {
+            switch (it->second.protoVer)
+                {
+                case 6:
+                    Send_ALIVE_SYN_6(&(it->second), sip);
+                    break;
+                case 7:
+                    Send_ALIVE_SYN_7(&(it->second), sip);
+                    break;
+                case 8:
+                    Send_ALIVE_SYN_8(&(it->second), sip);
+                    break;
+                }
+
+            gettimeofday(&it->second.lastSendAlive, NULL);
+            }
+
+        if ((currTime - it->second.phase.GetTime()) > iaSettings.GetUserTimeout())
+            {
+            it->second.user->Unauthorize(this);
+            ip2user.erase(it++);
+            continue;
+            }
+        }
+
+    if ((it->second.phase.GetPhase() == 4)
+        && ((currTime - it->second.phase.GetTime()) > iaSettings.GetUserDelay()))
+        {
+        it->second.phase.SetPhase3();
+        printfd(__FILE__, "Phase changed from 4 to 3. Reason: timeout\n");
+        }
+
+    ++it;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::PacketProcessor(char * buff, int dataLen, uint32_t sip, uint16_t sport, int protoVer, user_iter * user)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+// ôÕÔ ÓÏÂÒÁÎÙ ÏÂÒÁÂÏÔÞÉËÉ ÒÁÚÎÙÈ ÐÁËÅÔÏ×
+int pn = -1;
+int packetLen;
+const int offset = LOGIN_LEN + 2 + 6; // LOGIN_LEN + sizeOfMagic + sizeOfVer;
+
+IA_USER * iaUser = NULL;
+
+CONN_SYN_6 * connSyn6;
+CONN_SYN_7 * connSyn7;
+CONN_SYN_8 * connSyn8;
+
+CONN_ACK_6 * connAck;
+ALIVE_ACK_6 * aliveAck;
+DISCONN_SYN_6 * disconnSyn;
+DISCONN_ACK_6 * disconnAck;
+
+map<uint32_t, IA_USER>::iterator it;
+it = ip2user.find(sip);
+
+if (it == ip2user.end() || (*user)->GetID() != it->second.user->GetID())
+    {
+    // åÝÅ ÎÅ ÂÙÌÏ ÚÁÐÒÏÓÏ× Ó ÜÔÏÇÏ IP
+    printfd(__FILE__, "Add new user\n");
+    ip2user[sip].protoVer = protoVer;
+    ip2user[sip].user = *user;
+    ip2user[sip].port = sport;
+    #ifdef IA_PHASE_DEBUG
+    ip2user[sip].phase.SetLogFileName(stgSettings->GetLogFileName());
+    ip2user[sip].phase.SetUserLogin((*user)->GetLogin());
+    #endif
+
+
+    it = ip2user.find(sip); //TODO
+    if (it == ip2user.end())
+        {
+        printfd(__FILE__, "+++ ERROR +++\n");
+        return -1;
+        }
+    }
+
+iaUser = &(it->second);
+
+if (iaUser->port != sport)
+    iaUser->port = sport;
+
+if (iaUser->password != (*user)->property.password.Get())
+    {
+    InitEncrypt(&iaUser->ctx, (*user)->property.password.Get());
+    iaUser->password = (*user)->property.password.Get();
+    }
+
+buff += offset;
+Decrypt(&iaUser->ctx, buff, buff, (dataLen - offset) / 8);
+
+char packetName[IA_MAX_TYPE_LEN];
+strncpy(packetName,  buff + 4, IA_MAX_TYPE_LEN);
+packetName[IA_MAX_TYPE_LEN - 1] = 0;
+
+map<string, int>::iterator pi;
+pi = packetTypes.find(packetName);
+if (pi == packetTypes.end())
+    {
+    SendError(sip, sport, protoVer, "îÅÐÒÁ×ÉÌØÎÙÊ ÌÏÇÉΠÉÌÉ ÐÁÒÏÌØ!");
+    printfd(__FILE__, "Login or password is wrong!\n");
+    WriteServLog("User's connect failed. IP \'%s\'. Wrong login or password", inet_ntostring(sip).c_str());
+    return 0;
+    }
+else
+    {
+    pn = pi->second;
+    }
+
+packetLen = *(int*)buff;
+
+if ((*user)->property.disabled.Get())
+    {
+    SendError(sip, sport, protoVer, "õÞÅÔÎÁÑ ÚÁÐÉÓØ ÚÁÂÌÏËÉÒÏ×ÁÎÁ");
+    return 0;
+    }
+
+if ((*user)->property.passive.Get())
+    {
+    SendError(sip, sport, protoVer, "õÞÅÔÎÁÑ ÚÁÐÉÓØ ÚÁÍÏÒÏÖÅÎÁ");
+    return 0;
+    }
+
+if ((*user)->GetAuthorized() && (*user)->GetCurrIP() != sip)
+    {
+    printfd(__FILE__, "Login %s alredy in use. IP \'%s\'\n", (*user)->GetLogin().c_str(), inet_ntostring(sip).c_str());
+    WriteServLog("Login %s alredy in use. IP \'%s\'", (*user)->GetLogin().c_str(), inet_ntostring(sip).c_str());
+    SendError(sip, sport, protoVer, "÷ÁÛ ÌÏÇÉΠÕÖÅ ÉÓÐÏÌØÚÕÅÔÓÑ!");
+    return 0;
+    }
+
+user_iter u;
+if (users->FindByIPIdx(sip, &u) == 0 && u->GetLogin() != (*user)->GetLogin())
+    {
+    printfd(__FILE__, "IP address alredy in use. IP \'%s\'", inet_ntostring(sip).c_str());
+    WriteServLog("IP address alredy in use. IP \'%s\'", inet_ntostring(sip).c_str());
+    SendError(sip, sport, protoVer, "÷ÁÛ IP ÁÄÒÅÓ ÕÖÅ ÉÓÐÏÌØÚÕÅÔÓÑ!");
+    return 0;
+    }
+
+// ôÅÐÅÒØ ÍÙ ÄÏÌÖÎÙ ÐÒÏ×ÅÒÉÔØ, ÍÏÖÅÔ ÌÉ ÐÏÌØÚÏ×ÁÔÅÌØ ÐÏÄËÌÀÞÉÔÓÑ Ó ÜÔÏÇÏ ÁÄÒÅÓÁ.
+int ipFound = (*user)->property.ips.Get().IsIPInIPS(sip);
+if (!ipFound)
+    {
+    printfd(__FILE__, "User %s. IP address is incorrect. IP \'%s\'\n", (*user)->GetLogin().c_str(), inet_ntostring(sip).c_str());
+    WriteServLog("User %s. IP address is incorrect. IP \'%s\'", (*user)->GetLogin().c_str(), inet_ntostring(sip).c_str());
+    SendError(sip, sport, protoVer, "ðÏÌØÚÏ×ÁÔÅÌØ ÎÅ ÏÐÏÚÎÁÎ! ðÒÏ×ÅÒØÔÅ IP ÁÄÒÅÓ.");
+    return 0;
+    }
+
+int ret = -1;
+
+switch (pn)
+    {
+    case CONN_SYN_N:
+        switch (protoVer)
+            {
+            case 6:
+                connSyn6 = (CONN_SYN_6*)(buff - offset);
+                ret = Process_CONN_SYN_6(connSyn6, &(it->second), user, sip);
+                break;
+            case 7:
+                connSyn7 = (CONN_SYN_7*)(buff - offset);
+                ret = Process_CONN_SYN_7(connSyn7, &(it->second), user, sip);
+                break;
+            case 8:
+                connSyn8 = (CONN_SYN_8*)(buff - offset);
+                ret = Process_CONN_SYN_8(connSyn8, &(it->second), user, sip);
+                break;
+            }
+
+        if (ret != 0)
+            {
+            return 0;
+            }
+        switch (protoVer)
+            {
+            case 6:
+                Send_CONN_SYN_ACK_6(iaUser, user, sip);
+                break;
+            case 7:
+                Send_CONN_SYN_ACK_7(iaUser, user, sip);
+                break;
+            case 8:
+                Send_CONN_SYN_ACK_8(iaUser, user, sip);
+                break;
+            }
+        break;
+
+    case CONN_ACK_N:
+        connAck = (CONN_ACK_6*)(buff - offset);
+        switch (protoVer)
+            {
+            case 6:
+                ret = Process_CONN_ACK_6(connAck, iaUser, user, sip);
+                break;
+            case 7:
+                ret = Process_CONN_ACK_7(connAck, iaUser, user, sip);
+                break;
+            case 8:
+                ret = Process_CONN_ACK_8((CONN_ACK_8*)(buff - offset), iaUser, user, sip);
+                break;
+            }
+
+        if (ret != 0)
+            {
+            SendError(sip, sport, protoVer, errorStr);
+            return 0;
+            }
+
+        switch (protoVer)
+            {
+            case 6:
+                Send_ALIVE_SYN_6(iaUser, sip);
+                break;
+            case 7:
+                Send_ALIVE_SYN_7(iaUser, sip);
+                break;
+            case 8:
+                Send_ALIVE_SYN_8(iaUser, sip);
+                break;
+            }
+
+        break;
+
+        // ðÒÉÂÙÌ ÏÔ×ÅÔ Ó ÐÏÄÔ×ÅÒÖÄÅÎÉÅÍ ALIVE
+    case ALIVE_ACK_N:
+        aliveAck = (ALIVE_ACK_6*)(buff - offset);
+        switch (protoVer)
+            {
+            case 6:
+                ret = Process_ALIVE_ACK_6(aliveAck, iaUser, user, sip);
+                break;
+            case 7:
+                ret = Process_ALIVE_ACK_7(aliveAck, iaUser, user, sip);
+                break;
+            case 8:
+                ret = Process_ALIVE_ACK_8((ALIVE_ACK_8*)(buff - offset), iaUser, user, sip);
+                break;
+            }
+        break;
+
+        // úÁÐÒÏÓ ÎÁ ÏÔËÌÀÞÅÎÉÅ
+    case DISCONN_SYN_N:
+
+        disconnSyn = (DISCONN_SYN_6*)(buff - offset);
+        switch (protoVer)
+            {
+            case 6:
+                ret = Process_DISCONN_SYN_6(disconnSyn, iaUser, user, sip);
+                break;
+            case 7:
+                ret = Process_DISCONN_SYN_7(disconnSyn, iaUser, user, sip);
+                break;
+            case 8:
+                ret = Process_DISCONN_SYN_8((DISCONN_SYN_8*)(buff - offset), iaUser, user, sip);
+                break;
+            }
+
+        if (ret != 0)
+            return 0;
+
+        switch (protoVer)
+            {
+            case 6:
+                Send_DISCONN_SYN_ACK_6(iaUser, sip);
+                break;
+            case 7:
+                Send_DISCONN_SYN_ACK_7(iaUser, sip);
+                break;
+            case 8:
+                Send_DISCONN_SYN_ACK_8(iaUser, sip);
+                break;
+            }
+        break;
+
+    case DISCONN_ACK_N:
+        disconnAck = (DISCONN_ACK_6*)(buff - offset);
+
+        switch (protoVer)
+            {
+            case 6:
+                ret = Process_DISCONN_ACK_6(disconnAck, iaUser, user, sip, it);
+                break;
+            case 7:
+                ret = Process_DISCONN_ACK_7(disconnAck, iaUser, user, sip, it);
+                break;
+            case 8:
+                ret = Process_DISCONN_ACK_8((DISCONN_ACK_8*)(buff - offset), iaUser, user, sip, it);
+                break;
+            }
+
+        switch (protoVer)
+            {
+            case 6:
+                Send_FIN_6(iaUser, sip, it);
+                break;
+            case 7:
+                Send_FIN_7(iaUser, sip, it);
+                break;
+            case 8:
+                Send_FIN_8(iaUser, sip, it);
+                break;
+            }
+        break;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void AUTH_IA::DelUser(user_iter u)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+uint32_t ip = u->GetCurrIP();
+
+if (!ip)
+    return;
+
+map<uint32_t, IA_USER>::iterator it;
+it = ip2user.find(ip);
+if (it == ip2user.end())
+    {
+    //Nothing to delete
+    printfd(__FILE__, "Nothing to delete\n");
+    return;
+    }
+
+if (it->second.user == u)
+    {
+    printfd(__FILE__, "User removed!\n");
+    it->second.user->Unauthorize(this);
+    ip2user.erase(it);
+    }
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::SendError(uint32_t ip, uint16_t port, int protoVer, const string & text)
+{
+struct sockaddr_in sendAddr;
+switch (protoVer)
+    {
+    int res;
+    case 6:
+    case 7:
+        ERR err;
+        memset(&err, 0, sizeof(ERR));
+
+        sendAddr.sin_family = AF_INET;
+        sendAddr.sin_port = htons(port);
+
+        sendAddr.sin_addr.s_addr = ip;// IP ÐÏÌØÚÏ×ÁÔÅÌÑ
+
+        err.len = 1;
+        strncpy((char*)err.type, "ERR", 16);
+        strncpy((char*)err.text, text.c_str(), MAX_MSG_LEN);
+
+        #ifdef ARCH_BE
+        SwapBytes(err.len);
+        #endif
+
+        res = sendto(listenSocket, &err, sizeof(err), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+        printfd(__FILE__, "SendError %d bytes sent\n", res);
+        break;
+
+    case 8:
+        ERR_8 err8;
+        memset(&err8, 0, sizeof(ERR_8));
+
+        sendAddr.sin_family = AF_INET;
+        sendAddr.sin_port = htons(port);
+
+        sendAddr.sin_addr.s_addr = ip;// IP ÐÏÌØÚÏ×ÁÔÅÌÑ
+
+        err8.len = 256;
+        strncpy((char*)err8.type, "ERR", 16);
+        strncpy((char*)err8.text, text.c_str(), MAX_MSG_LEN);
+
+        #ifdef ARCH_BE
+        SwapBytes(err8.len);
+        #endif
+
+        res = sendto(listenSocket, &err8, sizeof(err8), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+        printfd(__FILE__, "SendError_8 %d bytes sent\n", res);
+        break;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send(uint32_t ip, uint16_t port, const char * buffer, int len)
+{
+struct sockaddr_in sendAddr;
+int res;
+
+sendAddr.sin_family = AF_INET;
+sendAddr.sin_port = htons(port);
+sendAddr.sin_addr.s_addr = ip;
+
+res = sendto(listenSocket, buffer, len, 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+
+static struct timeval tv;
+gettimeofday(&tv, NULL);
+
+return res;
+}
+//-----------------------------------------------------------------------------
+void AUTH_IA::InitEncrypt(BLOWFISH_CTX * ctx, const string & password)
+{
+unsigned char keyL[PASSWD_LEN];  // ðÁÒÏÌØ ÄÌÑ ÛÉÆÒÏ×ËÉ
+memset(keyL, 0, PASSWD_LEN);
+strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+}
+//-----------------------------------------------------------------------------
+void AUTH_IA::Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
+{
+// len8 - ÄÌÉÎÁ × 8-ÍÉ ÂÁÊÔÏ×ÙÈ ÂÌÏËÁÈ
+
+for (int i = 0; i < len8; i++)
+    DecodeString(dst + i * 8, src + i * 8, ctx);
+}
+//-----------------------------------------------------------------------------
+void AUTH_IA::Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
+{
+// len8 - ÄÌÉÎÁ × 8-ÍÉ ÂÁÊÔÏ×ÙÈ ÂÌÏËÁÈ
+
+for (int i = 0; i < len8; i++)
+    EncodeString(dst + i * 8, src + i * 8, ctx);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::SendMessage(const STG_MSG & msg, uint32_t ip) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+printfd(__FILE__, "SendMessage userIP=%s\n", inet_ntostring(ip).c_str());
+
+map<uint32_t, IA_USER>::iterator it;
+it = ip2user.find(ip);
+if (it == ip2user.end())
+    {
+    errorStr = "Unknown user.";
+    return -1;
+    }
+it->second.messagesToSend.push_back(msg);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RealSendMessage6(const STG_MSG & msg, uint32_t ip, IA_USER & user)
+{
+printfd(__FILE__, "RealSendMessage 6 user=%s\n", user.user->GetLogin().c_str());
+
+char buffer[256];
+INFO_6 info;
+
+memset(&info, 0, sizeof(INFO_6));
+
+info.len = 256;
+strncpy((char*)info.type, "INFO", 16);
+info.infoType = 'I';
+strncpy((char*)info.text, msg.text.c_str(), 235);
+info.text[234] = 0;
+
+size_t len = info.len;
+#ifdef ARCH_BE
+SwapBytes(info.len);
+#endif
+
+memcpy(buffer, &info, sizeof(INFO_6));
+Encrypt(&user.ctx, buffer, buffer, len / 8);
+Send(ip, iaSettings.GetUserPort(), buffer, len);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RealSendMessage7(const STG_MSG & msg, uint32_t ip, IA_USER & user)
+{
+printfd(__FILE__, "RealSendMessage 7 user=%s\n", user.user->GetLogin().c_str());
+
+char buffer[300];
+INFO_7 info;
+
+memset(&info, 0, sizeof(INFO_7));
+
+info.len = 264;
+strncpy((char*)info.type, "INFO_7", 16);
+info.infoType = msg.header.type;
+info.showTime = msg.header.showTime;
+
+info.sendTime = msg.header.creationTime;
+
+size_t len = info.len;
+#ifdef ARCH_BE
+SwapBytes(info.len);
+SwapBytes(info.sendTime);
+#endif
+
+strncpy((char*)info.text, msg.text.c_str(), MAX_MSG_LEN - 1);
+info.text[MAX_MSG_LEN - 1] = 0;
+
+memcpy(buffer, &info, sizeof(INFO_7));
+
+Encrypt(&user.ctx, buffer, buffer, len / 8);
+Send(ip, iaSettings.GetUserPort(), buffer, len);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::RealSendMessage8(const STG_MSG & msg, uint32_t ip, IA_USER & user)
+{
+printfd(__FILE__, "RealSendMessage 8 user=%s\n", user.user->GetLogin().c_str());
+
+char buffer[1500];
+memset(buffer, 0, sizeof(buffer));
+
+INFO_8 info;
+
+memset(&info, 0, sizeof(INFO_8));
+
+info.len = 1056;
+strncpy((char*)info.type, "INFO_8", 16);
+info.infoType = msg.header.type;
+info.showTime = msg.header.showTime;
+info.sendTime = msg.header.creationTime;
+
+strncpy((char*)info.text, msg.text.c_str(), IA_MAX_MSG_LEN_8 - 1);
+info.text[IA_MAX_MSG_LEN_8 - 1] = 0;
+
+size_t len = info.len;
+#ifdef ARCH_BE
+SwapBytes(info.len);
+SwapBytes(info.sendTime);
+#endif
+
+memcpy(buffer, &info, sizeof(INFO_8));
+
+Encrypt(&user.ctx, buffer, buffer, len / 8);
+Send(ip, user.port, buffer, len);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_SYN_6(CONN_SYN_6 *, IA_USER * iaUser, user_iter *, uint32_t)
+{
+if (!(iaUser->phase.GetPhase() == 1 || iaUser->phase.GetPhase() == 3))
+    return -1;
+
+enabledDirs = 0xFFffFFff;
+
+iaUser->phase.SetPhase2();
+printfd(__FILE__, "Phase changed from %d to 2. Reason: CONN_SYN_6\n", iaUser->phase.GetPhase());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_SYN_7(CONN_SYN_7 * connSyn, IA_USER * iaUser, user_iter * user, uint32_t sip)
+{
+return Process_CONN_SYN_6(connSyn, iaUser, user, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_SYN_8(CONN_SYN_8 * connSyn, IA_USER * iaUser, user_iter * user, uint32_t sip)
+{
+#ifdef ARCH_BE
+SwapBytes(connSyn->dirs);
+#endif
+int ret = Process_CONN_SYN_6((CONN_SYN_6*)connSyn, iaUser, user, sip);
+enabledDirs = connSyn->dirs;
+return ret;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_ACK_6(CONN_ACK_6 * connAck, IA_USER * iaUser, user_iter *, uint32_t sip)
+{
+#ifdef ARCH_BE
+SwapBytes(connAck->len);
+SwapBytes(connAck->rnd);
+#endif
+printfd( __FILE__, "CONN_ACK_6 %s\n", connAck->type);
+// ÕÓÔÁÎÏ×ÉÔØ ÎÏ×ÕÀ ÆÁÚÕ É ×ÒÅÍÑ É ÒÁÚÒÅÛÉÔØ ÉÎÅÔ
+if ((iaUser->phase.GetPhase() == 2) && (connAck->rnd == iaUser->rnd + 1))
+    {
+    iaUser->phase.UpdateTime();
+
+    iaUser->lastSendAlive = iaUser->phase.GetTime();
+    if (iaUser->user->Authorize(sip, "", enabledDirs, this) == 0)
+        {
+        iaUser->phase.SetPhase3();
+        printfd(__FILE__, "Phase changed from 2 to 3. Reason: CONN_ACK_6\n");
+        return 0;
+        }
+    else
+        {
+        errorStr = iaUser->user->GetStrError();
+        iaUser->phase.SetPhase1();
+        printfd(__FILE__, "Phase changed from 2 to 1. Reason: failed to authorize user\n");
+        return -1;
+        }
+    }
+printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), connAck->rnd);
+return -1;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_ACK_7(CONN_ACK_7 * connAck, IA_USER * iaUser, user_iter * user, uint32_t sip)
+{
+return Process_CONN_ACK_6(connAck, iaUser, user, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_CONN_ACK_8(CONN_ACK_8 * connAck, IA_USER * iaUser, user_iter *, uint32_t sip)
+{
+#ifdef ARCH_BE
+SwapBytes(connAck->len);
+SwapBytes(connAck->rnd);
+#endif
+printfd( __FILE__, "CONN_ACK_8 %s\n", connAck->type);
+
+if ((iaUser->phase.GetPhase() == 2) && (connAck->rnd == iaUser->rnd + 1))
+    {
+    iaUser->phase.UpdateTime();
+    iaUser->lastSendAlive = iaUser->phase.GetTime();
+    if (iaUser->user->Authorize(sip, "", enabledDirs, this) == 0)
+        {
+        iaUser->phase.SetPhase3();
+        printfd(__FILE__, "Phase changed from 2 to 3. Reason: CONN_ACK_8\n");
+        return 0;
+        }
+    else
+        {
+        errorStr = iaUser->user->GetStrError();
+        iaUser->phase.SetPhase1();
+        printfd(__FILE__, "Phase changed from 2 to 1. Reason: failed to authorize user\n");
+        return -1;
+        }
+    }
+printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), connAck->rnd);
+return -1;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_ALIVE_ACK_6(ALIVE_ACK_6 * aliveAck, IA_USER * iaUser, user_iter *, uint32_t)
+{
+#ifdef ARCH_BE
+SwapBytes(aliveAck->len);
+SwapBytes(aliveAck->rnd);
+#endif
+printfd(__FILE__, "ALIVE_ACK_6\n");
+if ((iaUser->phase.GetPhase() == 3) && (aliveAck->rnd == iaUser->rnd + 1))
+    {
+    iaUser->phase.UpdateTime();
+    #ifdef IA_DEBUG
+    iaUser->aliveSent = false;
+    #endif
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_ALIVE_ACK_7(ALIVE_ACK_7 * aliveAck, IA_USER * iaUser, user_iter * user, uint32_t sip)
+{
+return Process_ALIVE_ACK_6(aliveAck, iaUser, user, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_ALIVE_ACK_8(ALIVE_ACK_8 * aliveAck, IA_USER * iaUser, user_iter *, uint32_t)
+{
+#ifdef ARCH_BE
+SwapBytes(aliveAck->len);
+SwapBytes(aliveAck->rnd);
+#endif
+printfd(__FILE__, "ALIVE_ACK_8\n");
+if ((iaUser->phase.GetPhase() == 3) && (aliveAck->rnd == iaUser->rnd + 1))
+    {
+    iaUser->phase.UpdateTime();
+    #ifdef IA_DEBUG
+    iaUser->aliveSent = false;
+    #endif
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_SYN_6(DISCONN_SYN_6 *, IA_USER * iaUser, user_iter *, uint32_t)
+{
+printfd(__FILE__, "DISCONN_SYN_6\n");
+if (iaUser->phase.GetPhase() != 3)
+    {
+    printfd(__FILE__, "Invalid phase. Expected 3, actual %d\n", iaUser->phase.GetPhase());
+    errorStr = "Incorrect request DISCONN_SYN";
+    return -1;
+    }
+
+iaUser->phase.SetPhase4();
+printfd(__FILE__, "Phase changed from 3 to 4. Reason: DISCONN_SYN_6\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_SYN_7(DISCONN_SYN_7 * disconnSyn, IA_USER * iaUser, user_iter * user, uint32_t sip)
+{
+return Process_DISCONN_SYN_6(disconnSyn, iaUser, user, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_SYN_8(DISCONN_SYN_8 *, IA_USER * iaUser, user_iter *, uint32_t)
+{
+if (iaUser->phase.GetPhase() != 3)
+    {
+    errorStr = "Incorrect request DISCONN_SYN";
+    printfd(__FILE__, "Invalid phase. Expected 3, actual %d\n", iaUser->phase.GetPhase());
+    return -1;
+    }
+
+iaUser->phase.SetPhase4();
+printfd(__FILE__, "Phase changed from 3 to 4. Reason: DISCONN_SYN_6\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_ACK_6(DISCONN_ACK_6 * disconnAck,
+                                   IA_USER * iaUser,
+                                   user_iter *,
+                                   uint32_t,
+                                   map<uint32_t, IA_USER>::iterator)
+{
+#ifdef ARCH_BE
+SwapBytes(disconnAck->len);
+SwapBytes(disconnAck->rnd);
+#endif
+printfd(__FILE__, "DISCONN_ACK_6\n");
+if (!((iaUser->phase.GetPhase() == 4) && (disconnAck->rnd == iaUser->rnd + 1)))
+    {
+    printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), disconnAck->rnd);
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_ACK_7(DISCONN_ACK_7 * disconnAck, IA_USER * iaUser, user_iter * user, uint32_t sip, map<uint32_t, IA_USER>::iterator it)
+{
+return Process_DISCONN_ACK_6(disconnAck, iaUser, user, sip, it);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Process_DISCONN_ACK_8(DISCONN_ACK_8 * disconnAck, IA_USER * iaUser, user_iter *, uint32_t, map<uint32_t, IA_USER>::iterator)
+{
+#ifdef ARCH_BE
+SwapBytes(disconnAck->len);
+SwapBytes(disconnAck->rnd);
+#endif
+printfd(__FILE__, "DISCONN_ACK_8\n");
+if (!((iaUser->phase.GetPhase() == 4) && (disconnAck->rnd == iaUser->rnd + 1)))
+    {
+    printfd(__FILE__, "Invalid phase or control number. Phase: %d. Control number: %d\n", iaUser->phase.GetPhase(), disconnAck->rnd);
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_CONN_SYN_ACK_6(IA_USER * iaUser, user_iter *, uint32_t sip)
+{
+//+++ Fill static data in connSynAck +++
+// TODO Move this code. It must be executed only once
+connSynAck6.len = Min8(sizeof(CONN_SYN_ACK_6));
+strcpy((char*)connSynAck6.type, "CONN_SYN_ACK");
+for (int j = 0; j < DIR_NUM; j++)
+    {
+    strncpy((char*)connSynAck6.dirName[j],
+            stgSettings->GetDirName(j).c_str(),
+            sizeof(string16));
+
+    connSynAck6.dirName[j][sizeof(string16) - 1] = 0;
+    }
+//--- Fill static data in connSynAck ---
+
+iaUser->rnd = random();
+connSynAck6.rnd = iaUser->rnd;
+
+connSynAck6.userTimeOut = iaSettings.GetUserTimeout();
+connSynAck6.aliveDelay = iaSettings.GetUserDelay();
+
+#ifdef ARCH_BE
+SwapBytes(connSynAck6.len);
+SwapBytes(connSynAck6.rnd);
+SwapBytes(connSynAck6.userTimeOut);
+SwapBytes(connSynAck6.aliveDelay);
+#endif
+
+Encrypt(&iaUser->ctx, (char*)&connSynAck6, (char*)&connSynAck6, Min8(sizeof(CONN_SYN_ACK_6))/8);
+return Send(sip, iaSettings.GetUserPort(), (char*)&connSynAck6, Min8(sizeof(CONN_SYN_ACK_6)));;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_CONN_SYN_ACK_7(IA_USER * iaUser, user_iter * user, uint32_t sip)
+{
+return Send_CONN_SYN_ACK_6(iaUser, user, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_CONN_SYN_ACK_8(IA_USER * iaUser, user_iter *, uint32_t sip)
+{
+strcpy((char*)connSynAck8.hdr.magic, IA_ID);
+connSynAck8.hdr.protoVer[0] = 0;
+connSynAck8.hdr.protoVer[1] = 8;
+
+//+++ Fill static data in connSynAck +++
+// TODO Move this code. It must be executed only once
+connSynAck8.len = Min8(sizeof(CONN_SYN_ACK_8));
+strcpy((char*)connSynAck8.type, "CONN_SYN_ACK");
+for (int j = 0; j < DIR_NUM; j++)
+    {
+    strncpy((char*)connSynAck8.dirName[j],
+            stgSettings->GetDirName(j).c_str(),
+            sizeof(string16));
+
+    connSynAck8.dirName[j][sizeof(string16) - 1] = 0;
+    }
+//--- Fill static data in connSynAck ---
+
+iaUser->rnd = random();
+connSynAck8.rnd = iaUser->rnd;
+
+connSynAck8.userTimeOut = iaSettings.GetUserTimeout();
+connSynAck8.aliveDelay = iaSettings.GetUserDelay();
+
+#ifdef ARCH_BE
+SwapBytes(connSynAck8.len);
+SwapBytes(connSynAck8.rnd);
+SwapBytes(connSynAck8.userTimeOut);
+SwapBytes(connSynAck8.aliveDelay);
+#endif
+
+Encrypt(&iaUser->ctx, (char*)&connSynAck8, (char*)&connSynAck8, Min8(sizeof(CONN_SYN_ACK_8))/8);
+return Send(sip, iaUser->port, (char*)&connSynAck8, Min8(sizeof(CONN_SYN_ACK_8)));
+//return Send(sip, iaUser->port, (char*)&connSynAck8, 384);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_ALIVE_SYN_6(IA_USER * iaUser, uint32_t sip)
+{
+aliveSyn6.len = Min8(sizeof(ALIVE_SYN_6));
+aliveSyn6.rnd = iaUser->rnd = random();
+
+strcpy((char*)aliveSyn6.type, "ALIVE_SYN");
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    aliveSyn6.md[i] = iaUser->user->property.down.Get()[i];
+    aliveSyn6.mu[i] = iaUser->user->property.up.Get()[i];
+
+    aliveSyn6.sd[i] = iaUser->user->GetSessionDownload()[i];
+    aliveSyn6.su[i] = iaUser->user->GetSessionUpload()[i];
+    }
+
+//TODO
+int dn = iaSettings.GetFreeMbShowType();
+const TARIFF * tf = iaUser->user->GetTariff();
+
+if (dn < DIR_NUM)
+    {
+    double p = tf->GetPriceWithTraffType(aliveSyn6.mu[dn],
+                                         aliveSyn6.md[dn],
+                                         dn,
+                                         stgTime);
+    p *= (1024 * 1024);
+    if (p == 0)
+        {
+        snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "---");
+        }
+    else
+        {
+        double fmb = iaUser->user->property.freeMb;
+        fmb = fmb < 0 ? 0 : fmb;
+        snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "%.3f", fmb / p);
+        }
+    }
+else
+    {
+    if (freeMbNone == iaSettings.GetFreeMbShowType())
+        {
+        aliveSyn6.freeMb[0] = 0;
+        }
+    else
+        {
+        double fmb = iaUser->user->property.freeMb;
+        fmb = fmb < 0 ? 0 : fmb;
+        snprintf((char*)aliveSyn6.freeMb, IA_FREEMB_LEN, "C%.3f", fmb);
+        }
+    }
+
+#ifdef IA_DEBUG
+if (iaUser->aliveSent)
+    {
+    printfd(__FILE__, "========= ALIVE_ACK_6(7) TIMEOUT !!! %s =========\n", iaUser->user->GetLogin().c_str());
+    }
+iaUser->aliveSent = true;
+#endif
+
+aliveSyn6.cash =(int64_t) (iaUser->user->property.cash.Get() * 1000.0);
+if (!stgSettings->GetShowFeeInCash())
+    aliveSyn6.cash -= (int64_t)(tf->GetFee() * 1000.0);
+
+#ifdef ARCH_BE
+SwapBytes(aliveSyn6.len);
+SwapBytes(aliveSyn6.rnd);
+SwapBytes(aliveSyn6.cash);
+for (int i = 0; i < DIR_NUM; ++i)
+    {
+    SwapBytes(aliveSyn6.mu[i]);
+    SwapBytes(aliveSyn6.md[i]);
+    SwapBytes(aliveSyn6.su[i]);
+    SwapBytes(aliveSyn6.sd[i]);
+    }
+#endif
+
+Encrypt(&(iaUser->ctx), (char*)&aliveSyn6, (char*)&aliveSyn6, Min8(sizeof(aliveSyn6))/8);
+return Send(sip, iaSettings.GetUserPort(), (char*)&aliveSyn6, Min8(sizeof(aliveSyn6)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_ALIVE_SYN_7(IA_USER * iaUser, uint32_t sip)
+{
+return Send_ALIVE_SYN_6(iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_ALIVE_SYN_8(IA_USER * iaUser, uint32_t sip)
+{
+strcpy((char*)aliveSyn8.hdr.magic, IA_ID);
+aliveSyn8.hdr.protoVer[0] = 0;
+aliveSyn8.hdr.protoVer[1] = 8;
+
+aliveSyn8.len = Min8(sizeof(ALIVE_SYN_8));
+aliveSyn8.rnd = iaUser->rnd = random();
+
+strcpy((char*)aliveSyn8.type, "ALIVE_SYN");
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    aliveSyn8.md[i] = iaUser->user->property.down.Get()[i];
+    aliveSyn8.mu[i] = iaUser->user->property.up.Get()[i];
+
+    aliveSyn8.sd[i] = iaUser->user->GetSessionDownload()[i];
+    aliveSyn8.su[i] = iaUser->user->GetSessionUpload()[i];
+    }
+
+//TODO
+int dn = iaSettings.GetFreeMbShowType();
+
+if (dn < DIR_NUM)
+    {
+    const TARIFF * tf = iaUser->user->GetTariff();
+    double p = tf->GetPriceWithTraffType(aliveSyn8.mu[dn],
+                                         aliveSyn8.md[dn],
+                                         dn,
+                                         stgTime);
+    p *= (1024 * 1024);
+    if (p == 0)
+        {
+        snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "---");
+        }
+    else
+        {
+        double fmb = iaUser->user->property.freeMb;
+        fmb = fmb < 0 ? 0 : fmb;
+        snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "%.3f", fmb / p);
+        }
+    }
+else
+    {
+    if (freeMbNone == iaSettings.GetFreeMbShowType())
+        {
+        aliveSyn8.freeMb[0] = 0;
+        }
+    else
+        {
+        double fmb = iaUser->user->property.freeMb;
+        fmb = fmb < 0 ? 0 : fmb;
+        snprintf((char*)aliveSyn8.freeMb, IA_FREEMB_LEN, "C%.3f", fmb);
+        }
+    }
+
+#ifdef IA_DEBUG
+if (iaUser->aliveSent)
+    {
+    printfd(__FILE__, "========= ALIVE_ACK_8 TIMEOUT !!! =========\n");
+    }
+iaUser->aliveSent = true;
+#endif
+
+const TARIFF * tf = iaUser->user->GetTariff();
+
+aliveSyn8.cash =(int64_t) (iaUser->user->property.cash.Get() * 1000.0);
+if (!stgSettings->GetShowFeeInCash())
+    aliveSyn8.cash -= (int64_t)(tf->GetFee() * 1000.0);
+
+#ifdef ARCH_BE
+SwapBytes(aliveSyn8.len);
+SwapBytes(aliveSyn8.rnd);
+SwapBytes(aliveSyn8.cash);
+SwapBytes(aliveSyn8.status);
+for (int i = 0; i < DIR_NUM; ++i)
+    {
+    SwapBytes(aliveSyn8.mu[i]);
+    SwapBytes(aliveSyn8.md[i]);
+    SwapBytes(aliveSyn8.su[i]);
+    SwapBytes(aliveSyn8.sd[i]);
+    }
+#endif
+
+Encrypt(&(iaUser->ctx), (char*)&aliveSyn8, (char*)&aliveSyn8, Min8(sizeof(aliveSyn8))/8);
+return Send(sip, iaUser->port, (char*)&aliveSyn8, Min8(sizeof(aliveSyn8)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_DISCONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip)
+{
+disconnSynAck6.len = Min8(sizeof(DISCONN_SYN_ACK_6));
+strcpy((char*)disconnSynAck6.type, "DISCONN_SYN_ACK");
+disconnSynAck6.rnd = iaUser->rnd = random();
+
+#ifdef ARCH_BE
+SwapBytes(disconnSynAck6.len);
+SwapBytes(disconnSynAck6.rnd);
+#endif
+
+Encrypt(&iaUser->ctx, (char*)&disconnSynAck6, (char*)&disconnSynAck6, Min8(sizeof(disconnSynAck6))/8);
+return Send(sip, iaSettings.GetUserPort(), (char*)&disconnSynAck6, Min8(sizeof(disconnSynAck6)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_DISCONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip)
+{
+return Send_DISCONN_SYN_ACK_6(iaUser, sip);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_DISCONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip)
+{
+strcpy((char*)disconnSynAck8.hdr.magic, IA_ID);
+disconnSynAck8.hdr.protoVer[0] = 0;
+disconnSynAck8.hdr.protoVer[1] = 8;
+
+disconnSynAck8.len = Min8(sizeof(DISCONN_SYN_ACK_8));
+strcpy((char*)disconnSynAck8.type, "DISCONN_SYN_ACK");
+disconnSynAck8.rnd = iaUser->rnd = random();
+
+#ifdef ARCH_BE
+SwapBytes(disconnSynAck8.len);
+SwapBytes(disconnSynAck8.rnd);
+#endif
+
+Encrypt(&iaUser->ctx, (char*)&disconnSynAck8, (char*)&disconnSynAck8, Min8(sizeof(disconnSynAck8))/8);
+return Send(sip, iaUser->port, (char*)&disconnSynAck8, Min8(sizeof(disconnSynAck8)));
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_FIN_6(IA_USER * iaUser, uint32_t sip, map<uint32_t, IA_USER>::iterator it)
+{
+fin6.len = Min8(sizeof(FIN_6));
+strcpy((char*)fin6.type, "FIN");
+strcpy((char*)fin6.ok, "OK");
+
+#ifdef ARCH_BE
+SwapBytes(fin6.len);
+#endif
+
+Encrypt(&iaUser->ctx, (char*)&fin6, (char*)&fin6, Min8(sizeof(fin6))/8);
+
+iaUser->user->Unauthorize(this);
+
+int ret = Send(sip, iaSettings.GetUserPort(), (char*)&fin6, Min8(sizeof(fin6)));
+ip2user.erase(it);
+return ret;
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_FIN_7(IA_USER * iaUser, uint32_t sip, map<uint32_t, IA_USER>::iterator it)
+{
+return Send_FIN_6(iaUser, sip, it);
+}
+//-----------------------------------------------------------------------------
+int AUTH_IA::Send_FIN_8(IA_USER * iaUser, uint32_t sip, map<uint32_t, IA_USER>::iterator it)
+{
+strcpy((char*)fin8.hdr.magic, IA_ID);
+fin8.hdr.protoVer[0] = 0;
+fin8.hdr.protoVer[1] = 8;
+
+fin8.len = Min8(sizeof(FIN_8));
+strcpy((char*)fin8.type, "FIN");
+strcpy((char*)fin8.ok, "OK");
+
+#ifdef ARCH_BE
+SwapBytes(fin8.len);
+#endif
+
+Encrypt(&iaUser->ctx, (char*)&fin8, (char*)&fin8, Min8(sizeof(fin8))/8);
+
+iaUser->user->Unauthorize(this);
+
+int ret = Send(sip, iaUser->port, (char*)&fin8, Min8(sizeof(fin8)));
+ip2user.erase(it);
+return ret;
+}
+//-----------------------------------------------------------------------------
+bool AUTH_IA::WaitPackets(int sd) const
+{
+fd_set rfds;
+FD_ZERO(&rfds);
+FD_SET(sd, &rfds);
+
+struct timeval tv;
+tv.tv_sec = 0;
+tv.tv_usec = 500000;
+
+int res = select(sd + 1, &rfds, NULL, NULL, &tv);
+if (res == -1) // Error
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
+        }
+    return false;
+    }
+
+if (res == 0) // Timeout
+    {
+    return false;
+    }
+
+return true;
+}
diff --git a/projects/stargazer/plugins/authorization/inetaccess/inetaccess.h b/projects/stargazer/plugins/authorization/inetaccess/inetaccess.h
new file mode 100644 (file)
index 0000000..0e194db
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.34 $
+ $Date: 2010/09/10 06:39:19 $
+ $Author: faust $
+ */
+
+#ifndef INETACCESS_H
+#define INETACCESS_H
+
+#include <sys/time.h>
+#include <pthread.h>
+#include <cstring>
+#include <ctime>
+#include <string>
+#include <map>
+#include <functional>
+#include <utility>
+
+#include "os_int.h"
+#include "base_auth.h"
+#include "base_store.h"
+#include "notifer.h"
+#include "user_ips.h"
+#include "../../../user.h"
+#include "../../../users.h"
+#include "ia_packets.h"
+#include "blowfish.h"
+#include "stg_logger.h"
+#include "utime.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+#define IA_PROTO_VER    (6)
+
+//#define IA_DEBUG (1)
+//#define IA_PHASE_DEBUG (1)
+
+class AUTH_IA;
+//-----------------------------------------------------------------------------
+enum FREEMB
+{
+    freeMb0 = 0,
+    freeMb1,
+    freeMb2,
+    freeMb3,
+    freeMb4,
+    freeMb5,
+    freeMb6,
+    freeMb7,
+    freeMb8,
+    freeMb9,
+    freeMb10,
+    freeMb11,
+    freeMb12,
+    freeMb13,
+    freeMb14,
+    freeMb15,
+    freeMb16,
+    freeMb17,
+    freeMb18,
+    freeMb19,
+    freeMbCash = 100,
+    freeMbNone = 101
+};
+//-----------------------------------------------------------------------------
+class IA_PHASE
+{
+public:
+    IA_PHASE();
+    ~IA_PHASE();
+
+    void    SetPhase1();
+    void    SetPhase2();
+    void    SetPhase3();
+    void    SetPhase4();
+    void    SetPhase5();
+    int     GetPhase() const;
+
+    void    UpdateTime();
+    const UTIME & GetTime() const;
+
+    #ifdef IA_PHASE_DEBUG
+    void    SetUserLogin(const string & login);
+    void    SetLogFileName(const string & logFileName);
+    #endif
+
+private:
+    int             phase;
+    UTIME           phaseTime;
+
+    #ifdef IA_PHASE_DEBUG
+    void WritePhaseChange(int newPhase);
+    string log;
+    string login;
+    FILE * flog;
+    #endif
+};
+//-----------------------------------------------------------------------------
+struct IA_USER
+{
+    IA_USER()
+    {
+        //phase     = 1;
+        //phaseTime = 0;
+        lastSendAlive = 0;
+        rnd       = random();
+        port      = 0;
+        password = "NO PASSWORD";
+        // +++ Preparing CTX +++
+        unsigned char keyL[PASSWD_LEN];  // ðÁÒÏÌØ ÄÌÑ ÛÉÆÒÏ×ËÉ
+        memset(keyL, 0, PASSWD_LEN);
+        strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+        Blowfish_Init(&ctx, keyL, PASSWD_LEN);
+        // --- Preparing CTX ---
+        #ifdef IA_DEBUG
+        aliveSent = false;
+        #endif
+    };
+
+    IA_USER(const IA_USER & u)
+    {
+        user          = u.user;
+        phase         = u.phase;
+        //phaseTime     = u.phaseTime;
+        lastSendAlive = u.lastSendAlive;
+        rnd           = u.rnd;
+        password      = u.password;
+        protoVer      = u.protoVer;
+        port          = u.port;
+        #ifdef IA_DEBUG
+        aliveSent  = u.aliveSent;
+        #endif
+        memcpy(&ctx, &u.ctx, sizeof(BLOWFISH_CTX));
+    };
+
+    user_iter       user;
+    //int             phase;
+    //UTIME           phaseTime;
+    IA_PHASE        phase;
+    UTIME           lastSendAlive;
+    uint32_t        rnd;
+    uint16_t        port;
+    BLOWFISH_CTX    ctx;
+    list<STG_MSG>   messagesToSend;
+    int             protoVer;
+    string          password;
+    #ifdef IA_DEBUG
+    bool            aliveSent;
+    #endif
+};
+//-----------------------------------------------------------------------------
+class AUTH_IA_SETTINGS
+{
+public:
+                    AUTH_IA_SETTINGS();
+    virtual         ~AUTH_IA_SETTINGS() {};
+    const string&   GetStrError() const { return errorStr; };
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    int             GetUserDelay() const { return userDelay; };
+    int             GetUserTimeout() const { return userTimeout; };
+    int             GetUserPort() const { return port; };
+    FREEMB          GetFreeMbShowType() const { return freeMbShowType; };
+
+private:
+    int             ParseIntInRange(const string & str, int min, int max, int * val);
+    int             userDelay;
+    int             userTimeout;
+    uint16_t        port;
+    string          errorStr;
+    FREEMB          freeMbShowType;
+};
+//-----------------------------------------------------------------------------
+class AUTH_IA :public BASE_AUTH
+{
+public:
+                        AUTH_IA();
+    virtual             ~AUTH_IA();
+
+    void                SetUsers(USERS * u) { users = u; };
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER *){};
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS * s) { stgSettings = s; };
+    void                SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning() { return isRunningRunTimeouter || isRunningRun; };
+
+    const string      & GetStrError() const { return errorStr; };
+    const string        GetVersion() const { return "InetAccess authorization plugin v.1.4"; };
+    uint16_t            GetStartPosition() const { return 50; };
+    uint16_t            GetStopPosition() const { return 50; };
+
+    void                DelUser(user_iter u);
+
+    int                 SendMessage(const STG_MSG & msg, uint32_t ip) const;
+
+private:
+    static void *       Run(void *);
+    static void *       RunTimeouter(void * d);
+    int                 PrepareNet();
+    int                 FinalizeNet();
+    int                 RecvData(char * buffer, int bufferSize);
+    int                 CheckHeader(const char * buffer, int * protoVer);
+    int                 PacketProcessor(char * buff, int dataLen, uint32_t sip, uint16_t sport, int protoVer, user_iter * user);
+
+    int                 Process_CONN_SYN_6(CONN_SYN_6 * connSyn, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_CONN_SYN_7(CONN_SYN_7 * connSyn, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_CONN_SYN_8(CONN_SYN_8 * connSyn, IA_USER * iaUser, user_iter * user, uint32_t sip);
+
+    int                 Process_CONN_ACK_6(CONN_ACK_6 * connAck, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_CONN_ACK_7(CONN_ACK_7 * connAck, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_CONN_ACK_8(CONN_ACK_8 * connAck, IA_USER * iaUser, user_iter * user, uint32_t sip);
+
+    int                 Process_ALIVE_ACK_6(ALIVE_ACK_6 * aliveAck, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_ALIVE_ACK_7(ALIVE_ACK_7 * aliveAck, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_ALIVE_ACK_8(ALIVE_ACK_8 * aliveAck, IA_USER * iaUser, user_iter * user, uint32_t sip);
+
+    int                 Process_DISCONN_SYN_6(DISCONN_SYN_6 * disconnSyn, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_DISCONN_SYN_7(DISCONN_SYN_7 * disconnSyn, IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Process_DISCONN_SYN_8(DISCONN_SYN_8 * disconnSyn, IA_USER * iaUser, user_iter * user, uint32_t sip);
+
+    int                 Process_DISCONN_ACK_6(DISCONN_ACK_6 * disconnSyn,
+                                              IA_USER * iaUser,
+                                              user_iter * user,
+                                              uint32_t sip,
+                                              map<uint32_t, IA_USER>::iterator it);
+    int                 Process_DISCONN_ACK_7(DISCONN_ACK_7 * disconnSyn,
+                                              IA_USER * iaUser,
+                                              user_iter * user,
+                                              uint32_t sip,
+                                              map<uint32_t, IA_USER>::iterator it);
+    int                 Process_DISCONN_ACK_8(DISCONN_ACK_8 * disconnSyn,
+                                              IA_USER * iaUser,
+                                              user_iter * user,
+                                              uint32_t sip,
+                                              map<uint32_t, IA_USER>::iterator it);
+
+    int                 Send_CONN_SYN_ACK_6(IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Send_CONN_SYN_ACK_7(IA_USER * iaUser, user_iter * user, uint32_t sip);
+    int                 Send_CONN_SYN_ACK_8(IA_USER * iaUser, user_iter * user, uint32_t sip);
+
+    int                 Send_ALIVE_SYN_6(IA_USER * iaUser, uint32_t sip);
+    int                 Send_ALIVE_SYN_7(IA_USER * iaUser, uint32_t sip);
+    int                 Send_ALIVE_SYN_8(IA_USER * iaUser, uint32_t sip);
+
+    int                 Send_DISCONN_SYN_ACK_6(IA_USER * iaUser, uint32_t sip);
+    int                 Send_DISCONN_SYN_ACK_7(IA_USER * iaUser, uint32_t sip);
+    int                 Send_DISCONN_SYN_ACK_8(IA_USER * iaUser, uint32_t sip);
+
+    int                 Send_FIN_6(IA_USER * iaUser, uint32_t sip, map<uint32_t, IA_USER>::iterator it);
+    int                 Send_FIN_7(IA_USER * iaUser, uint32_t sip, map<uint32_t, IA_USER>::iterator it);
+    int                 Send_FIN_8(IA_USER * iaUser, uint32_t sip, map<uint32_t, IA_USER>::iterator it);
+
+    int                 Timeouter();
+
+    void                InitEncrypt(BLOWFISH_CTX * ctx, const string & password);
+    void                Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
+    void                Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
+
+    int                 SendError(uint32_t ip, uint16_t port, int protoVer, const string & text);
+    int                 Send(uint32_t ip, uint16_t port, const char * buffer, int len);
+    int                 RealSendMessage6(const STG_MSG & msg, uint32_t ip, IA_USER & user);
+    int                 RealSendMessage7(const STG_MSG & msg, uint32_t ip, IA_USER & user);
+    int                 RealSendMessage8(const STG_MSG & msg, uint32_t ip, IA_USER & user);
+
+    bool                WaitPackets(int sd) const;
+
+    BLOWFISH_CTX        ctxS;        //for loginS
+
+    mutable string      errorStr;
+    AUTH_IA_SETTINGS    iaSettings;
+    MODULE_SETTINGS     settings;
+
+    bool                nonstop;
+
+    bool                isRunningRun;
+    bool                isRunningRunTimeouter;
+
+    USERS *             users;
+    const SETTINGS *    stgSettings;
+
+    mutable map<uint32_t, IA_USER>  ip2user;
+
+    pthread_t           recvThread;
+    pthread_t           timeouterThread;
+    mutable pthread_mutex_t mutex;
+
+    int                 listenSocket;
+
+    CONN_SYN_ACK_6      connSynAck6;
+    CONN_SYN_ACK_8      connSynAck8;
+
+    DISCONN_SYN_ACK_6   disconnSynAck6;
+    DISCONN_SYN_ACK_8   disconnSynAck8;
+
+    ALIVE_SYN_6         aliveSyn6;
+    ALIVE_SYN_8         aliveSyn8;
+    FIN_6               fin6;
+    FIN_8               fin8;
+
+    map<string, int>    packetTypes;
+
+    STG_LOGGER &        WriteServLog;
+
+    uint32_t            enabledDirs;
+
+    class DEL_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+    {
+    public:
+        DEL_USER_NONIFIER(AUTH_IA & a) : auth(a) {};
+        virtual ~DEL_USER_NONIFIER(){};
+
+        void Notify(const user_iter & user)
+            {
+            auth.DelUser(user);
+            }
+
+    private:
+        AUTH_IA & auth;
+    } onDelUserNotifier;
+
+    class UnauthorizeUser : std::unary_function<const std::pair<uint32_t, IA_USER> &, void> {
+        public:
+            UnauthorizeUser(AUTH_IA * a) : auth(a) {};
+            void operator()(const std::pair<uint32_t, IA_USER> & p)
+            {
+                p.second.user->Unauthorize(auth);
+            }
+        private:
+            AUTH_IA * auth;
+    };
+
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
+
diff --git a/projects/stargazer/plugins/authorization/stress/Makefile b/projects/stargazer/plugins/authorization/stress/Makefile
new file mode 100644 (file)
index 0000000..2bdcf1b
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.4 2008/12/04 17:01:28 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_auth_stress.so
+
+SRCS = ./stress.cpp
+
+LIBS += $(LIB_THREAD)
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/authorization/stress/stress.cpp b/projects/stargazer/plugins/authorization/stress/stress.cpp
new file mode 100644 (file)
index 0000000..d0d86d0
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.5 $
+ $Date: 2009/06/19 12:50:32 $
+ $Author: faust $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "stress.h"
+#include "../../../user.h"
+
+class STRESS_CREATOR
+{
+private:
+    AUTH_STRESS * dc;
+
+public:
+    STRESS_CREATOR()
+        {
+        printfd(__FILE__, "constructor STRESS_CREATOR\n");
+        dc = new AUTH_STRESS();
+        };
+    ~STRESS_CREATOR()
+        {
+        printfd(__FILE__, "destructor STRESS_CREATOR\n");
+        delete dc;
+        };
+
+    BASE_PLUGIN * GetPlugin()
+    {
+        return dc;
+    };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+STRESS_CREATOR stressc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// ëÌÁÓÓ ÄÌÑ ÐÏÉÓËÁ ÀÚÅÒÁ × ÓÐÉÓËÅ ÎÏÔÉÆÉËÁÔÏÒÏ×
+template <typename varType>
+class IS_CONTAINS_USER: public binary_function<varType, user_iter, bool>
+{
+public:
+    bool operator()(varType notifier, user_iter user) const
+        {
+        return notifier.GetUser() == user;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+//printf("BASE_CAPTURER * GetCapturer()\n");
+return stressc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+AUTH_STRESS_SETTINGS::AUTH_STRESS_SETTINGS()
+    : averageOnlineTime(0)
+{
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+
+pv.param = "AverageOnlineTime";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'" + pv.param + "\' not found.";
+    return -1;
+    }
+
+if (ParseIntInRange(pvi->value[0], 5, 10*3600, &averageOnlineTime))
+    {
+    errorStr = "Cannot parse parameter \'" + pv.param + "\': " + errorStr;
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS_SETTINGS::GetAverageOnlineTime() const
+{
+return averageOnlineTime;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string AUTH_STRESS::GetVersion() const
+{
+return "Stress authorizator v.0.1";
+}
+//-----------------------------------------------------------------------------
+AUTH_STRESS::AUTH_STRESS()
+{
+pthread_mutex_init(&mutex, NULL);
+isRunning = false;
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::SetUsers(USERS * u)
+{
+users = u;
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS::ParseSettings()
+{
+int ret = stressSettings.ParseSettings(settings);
+if (ret)
+    errorStr = stressSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+const string & AUTH_STRESS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS::Start()
+{
+GetUsers();
+nonstop = true;
+
+list<user_iter>::iterator users_iter;
+
+onAddUserNotifier.SetAuthorizator(this);
+onDelUserNotifier.SetAuthorizator(this);
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+if (!isRunning)
+    {
+    if (pthread_create(&thread, NULL, Run, this))
+        {
+        errorStr = "Cannot create thread.";
+        return -1;
+        }
+    }
+
+users_iter = usersList.begin();
+while (users_iter != usersList.end())
+    {
+    Authorize(*users_iter);
+    users_iter++;
+    }
+
+//isRunning = true;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS::Stop()
+{
+nonstop = false;
+if (isRunning)
+    {
+    //5 seconds to thread stops itself
+    int i;
+    for (i = 0; i < 25; i++)
+        {
+        if (!isRunning)
+            break;
+        stgUsleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (isRunning)
+        {
+        if (pthread_kill(thread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            return -1;
+            }
+        printfd(__FILE__, "AUTH_STRESS killed Run\n");
+        }
+    }
+
+users->DelNotifierUserAdd(&onAddUserNotifier);
+users->DelNotifierUserDel(&onDelUserNotifier);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool AUTH_STRESS::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+uint16_t AUTH_STRESS::GetStartPosition() const
+{
+return 70;
+}
+//-----------------------------------------------------------------------------
+uint16_t AUTH_STRESS::GetStopPosition() const
+{
+return 70;
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::SetUserNotifiers(user_iter u)
+{
+// ---------- IP -------------------
+CHG_BEFORE_NOTIFIER<USER_IPS> BeforeChgIPNotifier;
+CHG_AFTER_NOTIFIER<USER_IPS>  AfterChgIPNotifier;
+
+BeforeChgIPNotifier.SetAuthorizator(this);
+BeforeChgIPNotifier.SetUser(u);
+BeforeChgIPNotifierList.push_front(BeforeChgIPNotifier);
+
+AfterChgIPNotifier.SetAuthorizator(this);
+AfterChgIPNotifier.SetUser(u);
+AfterChgIPNotifierList.push_front(AfterChgIPNotifier);
+
+u->property.ips.AddBeforeNotifier(&(*BeforeChgIPNotifierList.begin()));
+u->property.ips.AddAfterNotifier(&(*AfterChgIPNotifierList.begin()));
+// ---------- IP end ---------------
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::UnSetUserNotifiers(user_iter u)
+{
+// ---          IP              ---
+IS_CONTAINS_USER<CHG_BEFORE_NOTIFIER<USER_IPS> > IsContainsUserIPB;
+IS_CONTAINS_USER<CHG_AFTER_NOTIFIER<USER_IPS> >  IsContainsUserIPA;
+
+list<CHG_BEFORE_NOTIFIER<USER_IPS> >::iterator ipBIter;
+list<CHG_AFTER_NOTIFIER<USER_IPS> >::iterator  ipAIter;
+
+ipBIter = find_if(BeforeChgIPNotifierList.begin(),
+                  BeforeChgIPNotifierList.end(),
+                  bind2nd(IsContainsUserIPB, u));
+
+if (ipBIter != BeforeChgIPNotifierList.end())
+    {
+    ipBIter->GetUser()->property.ips.DelBeforeNotifier(&(*ipBIter));
+    BeforeChgIPNotifierList.erase(ipBIter);
+    }
+
+ipAIter = find_if(AfterChgIPNotifierList.begin(),
+                  AfterChgIPNotifierList.end(),
+                  bind2nd(IsContainsUserIPA, u));
+
+if (ipAIter != AfterChgIPNotifierList.end())
+    {
+    ipAIter->GetUser()->property.ips.DelAfterNotifier(&(*ipAIter));
+    AfterChgIPNotifierList.erase(ipAIter);
+    }
+// ---          IP end          ---
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::GetUsers()
+{
+user_iter u;
+printfd(__FILE__, "users->OpenSearch() usernum=%d\n", users->GetUserNum());
+int h = users->OpenSearch();
+if (!h)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    return;
+    }
+
+while (1)
+    {
+    if (users->SearchNext(h, &u))
+        {
+        break;
+        }
+    usersList.push_back(u);
+    SetUserNotifiers(u);
+    }
+
+users->CloseSearch(h);
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::Unauthorize(user_iter u) const
+{
+if (!u->IsAuthorizedBy(this))
+    return;
+
+printfd(__FILE__, "Unauthorized user %s\n", u->GetLogin().c_str());
+u->Unauthorize(this);
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::Authorize(user_iter u) const
+{
+USER_IPS ips = u->property.ips;
+if (ips.OnlyOneIP() && !u->IsAuthorizedBy(this))
+    {
+    if (u->Authorize(ips[0].ip, "", 0xFFffFFff, this) == 0)
+        {
+        printfd(__FILE__, "Authorized user %s\n", u->GetLogin().c_str());
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::AddUser(user_iter u)
+{
+//printfd(__FILE__, "User added to list %s\n", u->GetLogin().c_str());
+SetUserNotifiers(u);
+usersList.push_back(u);
+}
+//-----------------------------------------------------------------------------
+void AUTH_STRESS::DelUser(user_iter u)
+{
+Unauthorize(u);
+UnSetUserNotifiers(u);
+
+list<user_iter>::iterator users_iter;
+users_iter = usersList.begin();
+
+while (users_iter != usersList.end())
+    {
+    if (u == *users_iter)
+        {
+        usersList.erase(users_iter);
+        printfd(__FILE__, "User removed from list %s\n", u->GetLogin().c_str());
+        break;
+        }
+    users_iter++;
+    }
+}
+//-----------------------------------------------------------------------------
+int AUTH_STRESS::SendMessage(const STG_MSG & msg, uint32_t ip) const
+{
+errorStr = "Authorization modele \'AUTH_STRESS\' does not support sending messages";
+return -1;
+}
+//-----------------------------------------------------------------------------
+void * AUTH_STRESS::Run(void * d)
+{
+AUTH_STRESS * ia;
+ia = (AUTH_STRESS *)d;
+
+ia->isRunning = true;
+
+while (ia->nonstop)
+    {
+    printfd(__FILE__, "AUTH_STRESS::Run\n");
+
+    list<user_iter>::iterator users_iter;
+    users_iter = ia->usersList.begin();
+    while (users_iter != ia->usersList.end())
+        {
+        if (random() % 2*ia->stressSettings.GetAverageOnlineTime() == 1)
+            {
+            ia->Authorize(*users_iter);
+            printfd(__FILE__, "AUTH_STRESS::Authorize\n");
+            }
+        if (random() % 2*ia->stressSettings.GetAverageOnlineTime() == 2)
+            {
+            ia->Unauthorize(*users_iter);
+            printfd(__FILE__, "AUTH_STRESS::Unauthorize\n");
+            }
+
+        users_iter++;
+        }
+
+    sleep(1);
+    }
+
+ia->isRunning = false;
+return NULL;
+}
+
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void CHG_BEFORE_NOTIFIER<varParamType>::Notify(const varParamType & oldValue, const varParamType & newValue)
+{
+auth->Unauthorize(user);
+}
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void CHG_AFTER_NOTIFIER<varParamType>::Notify(const varParamType & oldValue, const varParamType & newValue)
+{
+auth->Unauthorize(user);
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/authorization/stress/stress.h b/projects/stargazer/plugins/authorization/stress/stress.h
new file mode 100644 (file)
index 0000000..1caf3a4
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.3 $
+ $Date: 2009/06/19 12:50:32 $
+ $Author: faust $
+ */
+
+
+#ifndef STRESS_H
+#define STRESS_H
+
+#include <string>
+#include <pthread.h>
+#include "base_auth.h"
+#include "notifer.h"
+#include "user_ips.h"
+#include "../../../users.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class AUTH_STRESS;
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class CHG_BEFORE_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void Notify(const varParamType & oldValue, const varParamType & newValue);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetAuthorizator(const AUTH_STRESS * a) { auth = a; }
+
+private:
+    user_iter   user;
+    const       AUTH_STRESS * auth;
+};
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class CHG_AFTER_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void        Notify(const varParamType & oldValue, const varParamType & newValue);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetAuthorizator(const AUTH_STRESS * a) { auth = a; }
+
+private:
+    user_iter   user;
+    const AUTH_STRESS * auth;
+};
+//-----------------------------------------------------------------------------
+class AUTH_STRESS_SETTINGS
+{
+public:
+                    AUTH_STRESS_SETTINGS();
+    const string&   GetStrError() const { return errorStr; }
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    int             GetAverageOnlineTime() const;
+private:
+    int             ParseIntInRange(const string & str, int min, int max, int * val);
+    int             averageOnlineTime;
+    string          errorStr;
+};
+//-----------------------------------------------------------------------------
+class AUTH_STRESS :public BASE_AUTH
+{
+public:
+    AUTH_STRESS();
+    virtual ~AUTH_STRESS(){};
+
+    void                SetUsers(USERS * u);
+    void                SetTariffs(TARIFFS * t){};
+    void                SetAdmins(ADMINS * a){};
+    void                SetTraffcounter(TRAFFCOUNTER * tc){};
+    void                SetStore(BASE_STORE * ){};
+    void                SetStgSettings(const SETTINGS *){};
+
+    int                 Start();
+    int                 Stop();
+    bool                IsRunning();
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+    void                AddUser(user_iter u);
+    void                DelUser(user_iter u);
+
+    void                Authorize(user_iter u) const;
+    void                Unauthorize(user_iter u) const;
+
+    int                 SendMessage(const STG_MSG & msg, uint32_t ip) const;
+
+private:
+    void                GetUsers();
+    void                SetUserNotifiers(user_iter u);
+    void                UnSetUserNotifiers(user_iter u);
+
+    bool                nonstop;
+
+    static void *       Run(void *);
+
+    mutable string      errorStr;
+    AUTH_STRESS_SETTINGS    stressSettings;
+    USERS             * users;
+    list<user_iter>     usersList;
+    bool                isRunning;
+    MODULE_SETTINGS     settings;
+
+    pthread_t           thread;
+    pthread_mutex_t     mutex;
+
+    list<CHG_BEFORE_NOTIFIER<USER_IPS> >    BeforeChgIPNotifierList;
+    list<CHG_AFTER_NOTIFIER<USER_IPS> >     AfterChgIPNotifierList;
+
+    class ADD_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+    {
+    public:
+        ADD_USER_NONIFIER(){};
+        virtual ~ADD_USER_NONIFIER(){};
+
+        void SetAuthorizator(AUTH_STRESS * a) { auth = a; }
+        void Notify(const user_iter & user)
+            {
+            auth->AddUser(user);
+            }
+
+    private:
+        AUTH_STRESS * auth;
+    } onAddUserNotifier;
+
+    class DEL_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+    {
+    public:
+        DEL_USER_NONIFIER(){};
+        virtual ~DEL_USER_NONIFIER(){};
+
+        void SetAuthorizator(AUTH_STRESS * a) { auth = a; }
+        void Notify(const user_iter & user)
+            {
+            auth->DelUser(user);
+            }
+
+    private:
+        AUTH_STRESS * auth;
+    } onDelUserNotifier;
+
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
+
diff --git a/projects/stargazer/plugins/capture/cap_debug/Makefile b/projects/stargazer/plugins/capture/cap_debug/Makefile
new file mode 100644 (file)
index 0000000..ade3738
--- /dev/null
@@ -0,0 +1,24 @@
+###############################################################################
+# $Id: Makefile,v 1.10 2008/12/04 17:03:25 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_debug.so
+
+SRCS = ./debug_cap.cpp \
+       ./checksum.c \
+       ./icmp.c \
+       ./ip.c \
+       ./misc.c \
+       ./packet.c \
+       ./socket.c \
+       ./tcp.c \
+       ./udp.c
+
+STGLIBS = -lstg_common
+
+LIBS += $(LIB_THREAD)
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/cap_debug/checksum.c b/projects/stargazer/plugins/capture/cap_debug/checksum.c
new file mode 100644 (file)
index 0000000..28cef34
--- /dev/null
@@ -0,0 +1,47 @@
+/*$Id: checksum.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+unsigned short
+in_cksum(unsigned short *addr, int len)
+{
+       int                             nleft = len;
+       int                             sum = 0;
+       unsigned short  *w = addr;
+       unsigned short  answer = 0;
+
+       /*
+        * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+        * sequential 16 bit words to it, and at the end, fold back all the
+        * carry bits from the top 16 bits into the lower 16 bits.
+        */
+       while (nleft > 1)  {
+               sum += *w++;
+               nleft -= 2;
+       }
+
+               /* mop up an odd byte, if necessary */
+       if (nleft == 1) {
+               *(unsigned char *)(&answer) = *(unsigned char *)w ;
+               sum += answer;
+       }
+
+               /* add back carry outs from top 16 bits to low 16 bits */
+       sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
+       sum += (sum >> 16);                     /* add carry */
+       answer = ~sum;                          /* truncate to 16 bits */
+       return(answer);
+}
diff --git a/projects/stargazer/plugins/capture/cap_debug/checksum.h b/projects/stargazer/plugins/capture/cap_debug/checksum.h
new file mode 100644 (file)
index 0000000..2698a52
--- /dev/null
@@ -0,0 +1,20 @@
+/* $Id: checksum.h,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+unsigned short in_cksum(unsigned short *addr, int len);
diff --git a/projects/stargazer/plugins/capture/cap_debug/constants.h b/projects/stargazer/plugins/capture/cap_debug/constants.h
new file mode 100644 (file)
index 0000000..e845a44
--- /dev/null
@@ -0,0 +1,106 @@
+/* $Id: constants.h,v 1.1 2005/12/12 18:14:22 nobunaga Exp $
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+* socket types
+*/
+#define PKT_RAW                SOCK_RAW
+#define PKT_STREAM     SOCK_STREAM
+#define PKT_DGRAM      SOCK_DGRAM
+
+/*
+* Link Layer
+*/
+#define PKT_LINK_ARP   0x01
+#define PKT_LINK_RARP  0x02
+
+/*
+* Network Layer
+*/ 
+#define PKT_NET_IP     0x01
+#define PKT_NET_ICMP   0x02
+#define PKT_NET_IGMP   0x04
+
+/*
+* Transport layer
+*/
+#define PKT_TRANS_TCP  0x01
+#define PKT_TRANS_UDP  0x02
+
+/* --- [ IP ] ------------------------ */
+/* IP options */
+#define PKT_IP_OPT_EOL               0               /* end of option list */
+#define PKT_IP_OPT_END               PKT_IP_OPT_EOL
+#define PKT_IP_OPT_NOP               1               /* no operation */
+#define PKT_IP_OPT_NOOP              PKT_IP_OPT_NOP
+
+#define PKT_IP_OPT_RR                7               /* record packet route */
+#define PKT_IP_OPT_TS                68              /* timestamp */
+#define PKT_IP_OPT_TIMESTAMP         PKT_IP_OPT_TS
+#define PKT_IP_OPT_SECURITY          130             /* provide s,c,h,tcc */
+#define PKT_IP_OPT_SEC               PKT_IP_OPT_SECURITY
+#define PKT_IP_OPT_LSRR              131             /* loose source route */
+#define PKT_IP_OPT_SATID             136             /* satnet id */
+#define PKT_IP_OPT_SID               PKT_IP_OPT_SATID
+#define PKT_IP_OPT_SSRR              137             /* strict source route */
+#define PKT_IP_OPT_RA                148             /* router alert */
+
+/* flag bits for ipt_flg */
+#define PKT_IP_OPT_TS_TSONLY         0         /* timestamps only */
+#define PKT_IP_OPT_TS_TSANDADDR      1         /* timestamps and addresses */
+#define PKT_IP_OPT_TS_PRESPEC        3         /* specified modules only */
+
+/* --- [ TCP ] ------------------------ */
+/* tcp flags */
+#ifndef __FAVOUR_BSD
+#define TH_FIN        0x01
+#define TH_SYN        0x02
+#define TH_RST        0x04
+#define TH_PUSH       0x08
+#define TH_ACK        0x10
+#define TH_URG        0x20
+#endif
+/* additional flags */
+#define TH_XMAS        0x40
+#define TH_YMAS        0x80
+
+/* tcp options */
+#define PKT_TCP_OPT_END        0x00
+#define PKT_TCP_OPT_NOP        0x01
+#define PKT_TCP_OPT_MSS        0x02
+#define PKT_TCP_OPT_WSF        0x03    /*window scale factor*/
+#define PKT_TCP_OPT_SACK_PERM  0x04
+#define PKT_TCP_OPT_SACK       0x05
+#define PKT_TCP_OPT_TIME       0x08    /* timestamp option */
+
+/* tcp option lenghts */
+#define PKT_TCP_OPT_END_LEN            0x01
+#define PKT_TCP_OPT_NOP_LEN            0x01
+#define PKT_TCP_OPT_MSS_LEN            0x04
+#define PKT_TCP_OPT_WSF_LEN            0x03    /*window scale factor*/
+#define PKT_TCP_OPT_SACK_PERM_LEN      0x02
+#define PKT_TCP_OPT_SACK_LEN           0x01
+#define PKT_TCP_OPT_TIME_LEN           0x0a    /* timestamp option */
+
+/* return values and errors */
+#define PKTOK          0
+#define EPKTRANGE      -64
+#define EERRNO         -63 /* errno has been set */
+#define EPKTINVALPTR   -62
+#define EPKTUNKNOWNTYPE        -61
diff --git a/projects/stargazer/plugins/capture/cap_debug/debug_cap.cpp b/projects/stargazer/plugins/capture/cap_debug/debug_cap.cpp
new file mode 100644 (file)
index 0000000..799e399
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ *    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: 18.09.2002
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.21 $
+$Date: 2009/03/19 20:03:35 $
+$Author: faust $
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "debug_cap.h"
+#include "../../../traffcounter.h"
+#include "libpal.h"
+
+//-----------------------------------------------------------------------------
+void WriteStat(uint32_t u, uint32_t d)
+{
+FILE * f;
+f = fopen("/tmp/cap.stat", "at");
+fprintf(f, "up %5.2f Mbit, down %5.2f Mbit, sum %5.2f Mbit\n",
+        u / (1000000*8.0),
+        d / (1000000*8.0),
+        (u + d) / (1000000*8.0));
+fclose(f);
+}
+//-----------------------------------------------------------------------------
+
+class CAP_DEBUG_CREATOR
+{
+private:
+    DEBUG_CAP * dc;
+
+public:
+    CAP_DEBUG_CREATOR()
+        : dc(new DEBUG_CAP())
+        {
+        };
+    ~CAP_DEBUG_CREATOR()
+        {
+        delete dc;
+        };
+
+    DEBUG_CAP * GetCapturer()
+    {
+        return dc;
+    };
+};
+//-----------------------------------------------------------------------------
+RAW_PACKET MakeTCPPacket(const char * src,
+                         const char * dst,
+                         uint16_t sport,
+                         uint16_t dport,
+                         uint16_t len);
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CAP_DEBUG_CREATOR cdc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return cdc.GetCapturer();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string DEBUG_CAP::GetVersion() const
+{
+return "Debug_cap v.0.01a";
+}
+//-----------------------------------------------------------------------------
+DEBUG_CAP::DEBUG_CAP()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void DEBUG_CAP::SetTraffcounter(TRAFFCOUNTER * tc)
+{
+traffCnt = tc;
+}
+//-----------------------------------------------------------------------------
+const string & DEBUG_CAP::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int DEBUG_CAP::Start()
+{
+if (isRunning)
+    return 0;
+
+printfd(__FILE__, "DEBUG_CAP::Start()\n");
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run1, this) == 0)
+    {
+    return 0;
+    }
+
+errorStr = "Cannot create thread.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int DEBUG_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    stgUsleep(200000);
+    //printf(".");
+    }
+
+/*if (i)
+    printf("\n");*/
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    //TODO pthread_cancel()
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        return -1;
+        }
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool DEBUG_CAP::IsRunning()
+{
+return nonstop;
+}
+//-----------------------------------------------------------------------------
+void * DEBUG_CAP::Run1(void * data)
+{
+printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
+
+DEBUG_CAP * dc = (DEBUG_CAP *)data;
+dc->isRunning = true;
+
+RAW_PACKET rp;
+rp = MakeTCPPacket("192.168.1.1", "192.168.1.21", 255, 255, 200);
+int a = 0;
+sleep(3);
+
+struct tm * tm;
+time_t t;
+uint32_t u = 0;
+uint32_t d = 0;
+
+//2 upload : 3 download
+
+int usize;
+int dsize;
+
+t = stgTime;
+tm = localtime(&t);
+int min = tm->tm_min;
+int sec = tm->tm_sec;
+
+char cliIP[20];
+char srvIP[20];
+char trashIP1[20];
+char trashIP2[20];
+
+while (dc->nonstop)
+    {
+    for (int i = 8; i <= 252; i++)
+        {
+               
+        usize = random()%100 + 100;
+               dsize = random()%500 + 900;
+               
+        for (int j = 2; j < 11; j++)
+            {
+                       sprintf(cliIP, "192.168.%d.%d", j, i);
+            sprintf(srvIP, "10.1.%d.%d", random()%8, 1);
+
+            rp = MakeTCPPacket(srvIP, cliIP, 80, random()%2 + 2000, dsize);
+            d += dsize;
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(cliIP, srvIP, random()%2 + 2000, 80, usize);
+            u += usize;
+            dc->traffCnt->Process(rp);
+            }
+        }
+
+    usleep(100000);
+    t = stgTime;
+
+    if (min != localtime(&t)->tm_min)
+        {
+        min = localtime(&t)->tm_min;
+        WriteStat(u, d);
+        u = d = 0;
+        }
+
+    a++;
+
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void * DEBUG_CAP::Run2(void * data)
+{
+printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
+
+DEBUG_CAP * dc = (DEBUG_CAP *)data;
+dc->isRunning = true;
+
+RAW_PACKET rp;
+rp = MakeTCPPacket("192.168.1.1", "192.168.1.21", 255, 255, 200);
+int a = 0;
+sleep(3);
+
+struct tm * tm;
+time_t t;
+uint32_t u = 0;
+uint32_t d = 0;
+
+//2 upload : 3 download
+
+int usize = 200;
+int dsize = 1500;
+
+t = stgTime;
+tm = localtime(&t);
+int min = tm->tm_min;
+
+char cliIP[20];
+char srvIP[20];
+
+while (dc->nonstop)
+    {
+    for (int i = 101; i <= 150; i++)
+        {
+        sprintf(cliIP, "192.168.1.%d", i);
+        for (int dp = 0; dp < 1; dp++)
+            {
+            //sprintf(srvIP, "10.1.%d.%d", i, 10 + dp);
+            sprintf(srvIP, "10.1.%d.%d", i, 10 + dp);
+
+            rp = MakeTCPPacket(srvIP, cliIP, 80, 10000 + i + dp, dsize);
+            d += dsize;
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(srvIP, cliIP, 80, 10000 + i + dp, dsize);
+            d += dsize;
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(srvIP, cliIP, 80, 10000 + i + dp, dsize);
+            dc->traffCnt->Process(rp);
+            d += dsize;
+
+
+            rp = MakeTCPPacket(cliIP, srvIP, 10000 + i + dp, 80, usize);
+            u += usize;
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(cliIP, srvIP, 10000 + i + dp, 80, usize);
+            u += usize;
+            dc->traffCnt->Process(rp);
+            }
+        }
+
+    //usleep(20000);
+    t = stgTime;
+
+    if (min != localtime(&t)->tm_min)
+        {
+        min = localtime(&t)->tm_min;
+        WriteStat(u, d);
+        u = d = 0;
+        }
+
+    a++;
+
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void * DEBUG_CAP::Run3(void * data)
+{
+printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
+
+DEBUG_CAP * dc = (DEBUG_CAP *)data;
+dc->isRunning = true;
+
+RAW_PACKET rp;
+rp = MakeTCPPacket("192.168.1.1", "192.168.1.21", 255, 255, 200);
+int a = 0;
+sleep(3);
+
+struct tm * tm;
+time_t t;
+uint32_t u = 0;
+uint32_t d = 0;
+
+//2 upload : 3 download
+
+int usize = 200;
+int dsize = 1500;
+
+t = stgTime;
+tm = localtime(&t);
+
+char cliIP[20];
+char srvIP1[20];
+char srvIP2[20];
+char srvIP3[20];
+
+int firstTime = true;
+
+while (dc->nonstop)
+    {
+    if (firstTime)
+        {
+        sprintf(srvIP1, "10.1.%d.%d", random() % 14 + 153, random() % 11 + 35);
+
+        sprintf(srvIP2, "%d.%d.%d.%d",
+                random() % 20 + 81,
+                random() % 28 + 153,
+                random() % 28 + 37,
+                random() % 28 + 13);
+
+        sprintf(srvIP3, "%d.%d.%d.%d",
+                random() % 20 + 81,
+                random() % 28 + 153,
+                random() % 28 + 37,
+                random() % 28 + 13);
+
+        printfd(__FILE__, "firstTime=false\n");
+        firstTime = false;
+        }
+
+    int rnd = random() % 400;
+    if (rnd < 5)
+        {
+        sprintf(srvIP1, "10.1.%d.%d", random() % 14 + 153, random() % 11 + 35);
+        printfd(__FILE__, "srvIP1=%s\n", srvIP1);
+        }
+    if (rnd == 9)
+        {
+        sprintf(srvIP2, "%d.%d.%d.%d",
+                random() % 20 + 81,
+                random() % 28 + 153,
+                random() % 28 + 37,
+                random() % 28 + 13);
+        printfd(__FILE__, "srvIP2=%s\n", srvIP2);
+        }
+    if (rnd == 5)
+        {
+        sprintf(srvIP2, "%d.%d.%d.%d",
+                random() % 20 + 81,
+                random() % 28 + 153,
+                random() % 28 + 37,
+                random() % 28 + 13);
+        printfd(__FILE__, "srvIP3=%s\n", srvIP3);
+        }
+
+    for (int i = 2; i < 52; i++)
+        {
+        sprintf(cliIP, "192.168.1.%d", i);
+        for (int dp = 0; dp < 1; dp++)
+            {
+            usize = 50 + random() % 100;
+            dsize = 1000 + random() % 400;
+
+            rp = MakeTCPPacket(srvIP1, cliIP, 80, 10000 + i + dp, dsize);
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(srvIP2, cliIP, 80, 10000 + i + dp, dsize);
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(srvIP3, cliIP, 80, 10000 + i + dp, dsize);
+            dc->traffCnt->Process(rp);
+
+
+            rp = MakeTCPPacket(cliIP, srvIP1, 10000 + i + dp, 80, usize);
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(cliIP, srvIP2, 10000 + i + dp, 80, usize);
+            dc->traffCnt->Process(rp);
+
+            rp = MakeTCPPacket(cliIP, srvIP3, 10000 + i + dp, 80, usize);
+            dc->traffCnt->Process(rp);
+            }
+        }
+
+    usleep(300000);
+    /*t = stgTime;
+
+    if (min != localtime(&t)->tm_min)
+        {
+        min = localtime(&t)->tm_min;
+        WriteStat(u, d);
+        u = d = 0;
+        }*/
+
+    a++;
+
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t DEBUG_CAP::GetStartPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t DEBUG_CAP::GetStopPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+RAW_PACKET MakeTCPPacket(const char * src,
+                         const char * dst,
+                         uint16_t sport,
+                         uint16_t dport,
+                         uint16_t len)
+{
+struct packet pkt;
+if (pkt_init(&pkt, 0, 100))
+    {
+    printfd(__FILE__, "pkt_init error!\n");
+    }
+
+in_addr_t sip = inet_addr(src);
+in_addr_t dip = inet_addr(dst);
+
+pkt_ip_header(&pkt,
+              5,        //header len
+              4,
+              0,
+              len,      //total len
+              0,
+              0,
+              64,        //ttl
+              6,         //TCP
+              0,
+              *(uint32_t*)&sip,
+              *(uint32_t*)&dip);
+
+pkt_move_actptr(&pkt, 20);
+
+pkt_tcp_header(&pkt,
+               sport,
+               dport,
+               1,           // seq,
+               1,           // ackseq,
+               5,           // headerlen,
+               0,           // reserved,
+               0,           // flags,
+               0,           // window,
+               0,           // checksum,
+               0);          // urgent
+
+RAW_PACKET rp;
+memcpy(&rp, pkt.pkt, sizeof(rp));
+
+if (pkt_free(&pkt))
+    {
+    printfd(__FILE__, "pkt_free error!\n");
+    }
+rp.dataLen = -1;
+strcpy(rp.iface, "eth0");
+return rp;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/plugins/capture/cap_debug/debug_cap.h b/projects/stargazer/plugins/capture/cap_debug/debug_cap.h
new file mode 100644 (file)
index 0000000..35bcec4
--- /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
+ */
+
+/*
+Date: 18.09.2002
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.12 $
+$Date: 2009/06/23 11:32:27 $
+$Author: faust $
+*/
+
+#include <string>
+#include <pthread.h>
+
+#include "os_int.h"
+#include "base_plugin.h"
+#include "base_settings.h"
+
+using namespace std;
+extern "C" BASE_PLUGIN * GetPlugin();
+
+//-----------------------------------------------------------------------------
+struct iphdr_eth
+{
+    uint8_t     ihl:4,
+                version:4;
+    uint8_t     tos;
+    uint16_t    tot_len;
+    uint16_t    id;
+    uint16_t    frag_off;
+    uint8_t     ttl;
+    uint8_t     protocol;
+    uint16_t    check;
+    uint32_t    saddr;
+    uint32_t    daddr;
+    int32_t     len;
+    char        iface[10];
+};
+//-----------------------------------------------------------------------------
+class CAP_SETTINGS//: public BASE_SETTINGS
+{
+public:
+    const string& GetStrError() const { static string s; return s; }
+    int             ParseSettings(const MODULE_SETTINGS & s) { return 0; };
+};
+//-----------------------------------------------------------------------------
+class DEBUG_CAP :public BASE_PLUGIN
+{
+public:
+    DEBUG_CAP();
+    virtual ~DEBUG_CAP(){};
+
+    void                SetUsers(USERS * u){};
+    void                SetTariffs(TARIFFS * t){};
+    void                SetAdmins(ADMINS * a){};
+    void                SetTraffcounter(TRAFFCOUNTER * tc);
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS *){};
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    int                 ParseSettings() { return 0; };
+    void                SetSettings(const MODULE_SETTINGS & s){};
+    bool                IsRunning();
+    const string &      GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+private:
+    static void *       Run1(void *);
+    static void *       Run2(void *);
+    static void *       Run3(void *);
+    mutable string      errorStr;
+    CAP_SETTINGS        capSettings;
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+
+    TRAFFCOUNTER *      traffCnt;
+};
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/capture/cap_debug/icmp.c b/projects/stargazer/plugins/capture/cap_debug/icmp.c
new file mode 100644 (file)
index 0000000..abbaef1
--- /dev/null
@@ -0,0 +1,154 @@
+/* $Id: icmp.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+
+int 
+pkt_icmp_header(struct packet *pkt, unsigned char type, unsigned char code, unsigned short int checksum) 
+{
+
+       struct icmp *icmp;
+       if (pkt) {
+               icmp = (struct icmp *) pkt->pkt_ptr;
+               icmp->icmp_type = type;
+               icmp->icmp_code = code;
+               icmp->icmp_cksum = htons(checksum);
+               return 0;
+       } else
+               return EPKTINVALPTR;
+}
+
+int pkt_icmp_addr_mask(struct packet *pkt, unsigned short int id, unsigned short int seqno, unsigned int mask, char *cmask)
+{
+       struct icmp *icmp;
+       struct in_addr inetaddr;
+       
+       if (pkt) {
+               icmp = (struct icmp *)pkt->pkt_ptr;
+       } else
+               return EPKTINVALPTR;
+       icmp->icmp_id = htons(id);
+       icmp->icmp_seq = htons(seqno);
+       if (!cmask) {
+               icmp->icmp_mask = htons(mask);
+       } else {
+               if (inet_aton(cmask, &inetaddr) != 0) {
+                       icmp->icmp_mask = inetaddr.s_addr;
+               } else
+                       return EERRNO;
+       }
+       return 0;
+}
+
+int
+pkt_icmp_cksum(struct packet *pkt, unsigned int len)
+{
+       struct icmp *icmp;
+
+       if (!pkt)
+               return EPKTINVALPTR;
+       
+       icmp = (struct icmp *) pkt->pkt_ptr;
+       icmp->icmp_cksum = 0;
+       icmp->icmp_cksum = in_cksum((unsigned short *)icmp, len);
+       return 0;
+}
+
+int 
+pkt_icmp_dest_unreach(struct packet *pkt, unsigned int unused)
+{
+       struct icmp *icmp;
+
+       if (pkt) {
+               icmp = (struct icmp *)pkt->pkt_ptr;
+       } else
+               return EPKTINVALPTR;
+       icmp->icmp_void = htons(unused);
+       return 0;
+}
+
+int 
+pkt_icmp_source_quench(struct packet *pkt, unsigned int unused)
+{
+       struct icmp *icmp;
+
+       if (pkt) {
+               icmp = (struct icmp *)pkt->pkt_ptr;
+       } else
+               return EPKTINVALPTR;
+       icmp->icmp_void = htons(unused);
+       return 0;
+}
+
+int
+pkt_icmp_redirect(struct packet *pkt, unsigned int routerip, char *crouterip)
+{
+       struct icmp *icmp;
+       struct in_addr inetaddr;
+
+       if (pkt) {
+               icmp = (struct icmp *)pkt->pkt_ptr;
+       } else {
+               return EPKTINVALPTR;
+       }
+       if (crouterip) {
+               if (inet_aton(crouterip, &inetaddr) != 0) {
+                       icmp->icmp_gwaddr = inetaddr;
+               } else
+                       return EERRNO;
+       } else {
+               inetaddr.s_addr = htons(routerip);
+               icmp->icmp_gwaddr = inetaddr;
+       }
+       return 0;
+}
+
+int
+pkt_icmp_echo(struct packet *pkt, unsigned short int id, unsigned short int seqno, void *data, size_t data_len)
+{
+       struct icmp *icmp;
+
+       if (pkt) {
+               icmp = (struct icmp *) pkt->pkt_ptr;
+       } else
+               return EPKTINVALPTR;
+       icmp->icmp_id = htons(id);
+       icmp->icmp_seq = htons(seqno);
+       if (data) {
+               memcpy(icmp->icmp_data, data, data_len);
+       }
+       return 0;
+}
+
+int
+pkt_icmp_timestamp(struct packet *pkt, unsigned short int id, unsigned short int seqno, unsigned int ts_otime, unsigned int ts_rtime, unsigned int ts_ttime)
+{
+       struct icmp *icmp;
+
+       if (pkt)
+               icmp = (struct icmp *) pkt->pkt_ptr;
+       else
+               return EPKTINVALPTR;
+       icmp->icmp_id = htons(id);
+       icmp->icmp_seq = htons(seqno);
+       icmp->icmp_otime = htons(ts_otime);
+       icmp->icmp_rtime = htons(ts_rtime);
+       icmp->icmp_ttime = htons(ts_ttime);
+       return 0;
+}
diff --git a/projects/stargazer/plugins/capture/cap_debug/ip.c b/projects/stargazer/plugins/capture/cap_debug/ip.c
new file mode 100644 (file)
index 0000000..bc632f3
--- /dev/null
@@ -0,0 +1,124 @@
+/* $Id: ip.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+
+int
+pkt_ip_header(struct packet *pkt,
+                unsigned int iphdr_len,
+                unsigned int version,
+                unsigned char tos,
+                unsigned short int total_len,
+                unsigned short int id,
+                unsigned short int frag_off,
+                unsigned char ttl,
+                unsigned char protocol,
+                unsigned short int cksum,
+                unsigned int saddr,
+                unsigned int daddr)
+{
+        struct ip *ip;
+
+       if (!pkt)
+               return EPKTINVALPTR;
+       
+        ip = (struct ip *) pkt->pkt_ptr;
+
+        ip->ip_hl = iphdr_len;
+        ip->ip_v = version;
+        ip->ip_tos = tos;
+        ip->ip_len = htons(total_len);
+        ip->ip_id = htons(id);
+        ip->ip_off = htons(frag_off);
+        ip->ip_ttl = ttl;
+        ip->ip_p = protocol;
+        ip->ip_src.s_addr = saddr;
+        ip->ip_dst.s_addr = daddr;
+
+       return 0;
+}
+
+int
+pkt_ip_option_header(struct packet *pkt, unsigned char type, unsigned char len, unsigned char ptr, unsigned char oflw_flg, void *optval, size_t optlen)
+{
+       unsigned char *vp;
+       
+       if (!pkt)
+               return EPKTINVALPTR;
+       
+       vp = pkt->pkt_ptr;
+       *vp = type;             
+       switch (type) {
+               case PKT_IP_OPT_END:
+                       break;
+               case PKT_IP_OPT_NOP:
+                       break;
+               case PKT_IP_OPT_SEC:
+                       if ((pkt->pkt_pos + 2 + optlen) <= pkt->pkt_size) {
+                               *(vp+1) = len;
+                               memcpy((void*)(vp+2), optval, optlen);
+                       } else {
+                               return EPKTRANGE;
+                       }
+                       break;
+               case PKT_IP_OPT_RR:
+               case PKT_IP_OPT_LSRR:
+               case PKT_IP_OPT_SSRR:
+               case PKT_IP_OPT_SID:
+                       if ((pkt->pkt_pos + 3 + optlen) <= pkt->pkt_size) {
+                               *(vp+1) = len;
+                               *(vp+2) = ptr;
+                               memcpy((void*)(vp+3), optval, optlen);
+                       } else {
+                               return EPKTRANGE;
+                       }
+                       break;
+               case PKT_IP_OPT_TS:
+                       if ((pkt->pkt_pos + 4 + optlen) <= pkt->pkt_size) {
+                               *(vp+1) = len;
+                               *(vp+2) = ptr;
+                               *(vp+3) = oflw_flg;
+                               memcpy((void*)(vp+4), optval, optlen);
+                       } else {
+                               return EPKTRANGE;
+                       }
+                       break;
+               default:
+                       return EPKTUNKNOWNTYPE;
+       }
+       return PKTOK;
+}      
+       
+int
+pkt_ip_cksum(struct packet *pkt)
+{
+       /*
+       * checksum should be calculated by kernel 
+       * when we are using SOCK_RAW access.
+       */
+       struct ip *ip;
+
+       if (!pkt)
+               return EPKTINVALPTR;
+       
+       ip = (struct ip *) pkt->pkt_ptr;
+       ip->ip_sum = 0;
+       ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip));
+       return 0;
+}
diff --git a/projects/stargazer/plugins/capture/cap_debug/libpal.h b/projects/stargazer/plugins/capture/cap_debug/libpal.h
new file mode 100644 (file)
index 0000000..cbd239f
--- /dev/null
@@ -0,0 +1,130 @@
+/* $Id: libpal.h,v 1.1 2005/12/12 18:14:22 nobunaga Exp $
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _LIBPAL_H_
+#define _LIBPAL_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "checksum.h"
+#include "constants.h"
+
+/*
+* generic packet structure
+*
+* we maintain a so called "active ptr" inside the packet. Most operations
+* on the packet will take place at the position the pointer points at.
+* The pointer should never be moved directly, instead the functions
+* pkt_set_actpr() and pkt_move_actptr() are provided.
+* Using this approach we can perform bounds checking and make sure our
+* library functions won't segfault.
+* pkt_type is not really being used at the moment. I don't know if it
+* ever will be. It might just be left out one day, so keep your fingers
+* off. Use pkt_init() to set it. And dont even think of messing with the
+* packet payload pointer pkt. You do NOT want to do that. Use the provided
+* library functions.
+* To be clear: don't do _anything_ with this struct. Just pass it as a
+* parameter, be happy and your programs will (hopefully) work. 
+*/
+struct packet {
+       unsigned long   pkt_type;
+       unsigned char   *pkt;
+       unsigned int    pkt_size;
+       unsigned char   *pkt_ptr; /* active ptr inside packet */
+       unsigned int    pkt_pos; /* pkt_ptr position, starting at 0 */
+};
+
+/*
+* our socket structure
+*
+* same as above. Use the provided library fuctions to change its values.
+* Do not do it on your own. Live and let die. You have been warned.
+*/
+struct pkt_socket {
+       int rawfd;
+       struct sockaddr_in *sckad;
+       /*struct sockaddr_ll *sckll;*/
+       socklen_t sckad_len;    
+};
+
+/* memory management */
+int pkt_init(struct packet *pkt, unsigned long type, unsigned int size);
+int pkt_free(struct packet *pkt);
+
+/* pointer movement */
+int pkt_set_actptr(struct packet *pkt, unsigned int bytepos);  
+int pkt_move_actptr(struct packet *pkt, int relmov);
+
+/* raw data */
+int pkt_add_systimestamp(struct packet *pkt);
+int pkt_add_data(struct packet *pkt, char *data, size_t data_len);
+int pkt_resize(struct packet *pkt, unsigned int newsize);
+
+/* socket operations */
+int pkt_socket_open(struct pkt_socket *sck, int type);
+int pkt_socket_close(struct pkt_socket *sck);
+int pkt_socket_prepare(struct pkt_socket *sck, char *daddr);
+int pkt_socket_setopt(struct pkt_socket *sck, int level, int optname, void *optval, socklen_t optlen);
+
+/* sending */
+int pkt_send(struct packet *pkt, struct pkt_socket *sck);
+
+/* IP */
+int pkt_ip_header(struct packet *pkt, unsigned int iphdr_len, unsigned int version, unsigned char tos, unsigned short int total_len, unsigned short int id, unsigned short int frag_off /* 3bit flag, 13bit offset */, unsigned char ttl, unsigned char protocol, unsigned short int cksum, unsigned int saddr, unsigned int daddr);
+int pkt_ip_cksum(struct packet *pkt);
+int pkt_ip_option_header(struct packet *pkt, unsigned char type, unsigned char len, unsigned char ptr, unsigned char oflw_flg, void *optval, size_t optlen);
+
+/* TCP */
+int pkt_tcp_header(struct packet *pkt, unsigned short int sport, unsigned short int dport, unsigned int seq, unsigned int ackseq, unsigned char headerlen, unsigned char reserved, unsigned char flags, unsigned short window, unsigned short int checksum, unsigned short int urgent);
+int pkt_tcp_cksum(struct packet *pkt, char *saddr, char *daddr, unsigned int tcp_pkt_size);
+int pkt_tcp_option(struct packet *pkt, unsigned char kind, unsigned char len, void *optval, size_t optlen);
+
+/* UDP */
+int pkt_udp_header(struct packet *pkt, unsigned short int sport, unsigned short int dport, unsigned short int udp_total_len, unsigned short int checksum);
+int pkt_udp_cksum(struct packet *pkt, char *saddr, char *daddr, unsigned int udp_total_len);
+
+/* ICMP */
+int pkt_icmp_header(struct packet *pkt, unsigned char type, unsigned char code, unsigned short int checksum);
+int pkt_icmp_cksum(struct packet *pkt, unsigned int len);
+int pkt_icmp_addr_mask(struct packet *pkt, unsigned short int id, unsigned short int seqno, unsigned int mask, char *cmask);
+int pkt_icmp_dest_unreach(struct packet *pkt, unsigned int unused);
+int pkt_icmp_source_quench(struct packet *pkt, unsigned int unused);
+int pkt_icmp_redirect(struct packet *pkt, unsigned int routerip, char *crouterip);
+int pkt_icmp_echo(struct packet *pkt, unsigned short int id, unsigned short int seqno, void *data, size_t data_len);
+int pkt_icmp_timestamp(struct packet *pkt, unsigned short int id, unsigned short int seqno, unsigned int ts_otime, unsigned int ts_rtime, unsigned int ts_ttime);
+
+/* functions that might be useful and might be added some day ... 
+int pkt_shift_data(struct packet *pkt, unsigned int from, unsigned int to, unsigned int len);
+int pkt_tcp_change_seqno(int rel_seq, int rel_ackseq);
+int pkt_tcp_set_seqno(unsigned int seq, unsigned int ackseq);
+int pkt_ip_option(struct packet *pkt, unsigned char code, unsigned char len, unsigned char ptr);
+int pkt_ip_option_addval(struct *pkt, unsigned char posptr, unsigned int optval);
+*/
+
+#endif
diff --git a/projects/stargazer/plugins/capture/cap_debug/misc.c b/projects/stargazer/plugins/capture/cap_debug/misc.c
new file mode 100644 (file)
index 0000000..bd0b06a
--- /dev/null
@@ -0,0 +1,41 @@
+/* $Id: misc.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+
+/*
+<++doc++>
+@name int pkt_add_systimestamp(struct packet *pkt)
+@desc Adds a system timestamp (struct timeval) at the position where pkt-&gt;pkt_ptr points to.
+@param pkt packet into which a timestamp with the current system time will be added. 
+<--doc-->
+*/
+int
+pkt_add_systimestamp(struct packet *pkt)
+{
+        if (!pkt)
+                return EPKTINVALPTR;
+        if (pkt->pkt_size < (pkt->pkt_pos + sizeof(struct timeval)))
+                return EPKTRANGE;
+        if (gettimeofday((struct timeval *)pkt->pkt_ptr, NULL) == 0)
+                return 0;
+        else
+                return EERRNO;
+}
+
diff --git a/projects/stargazer/plugins/capture/cap_debug/packet.c b/projects/stargazer/plugins/capture/cap_debug/packet.c
new file mode 100644 (file)
index 0000000..6b76f00
--- /dev/null
@@ -0,0 +1,161 @@
+/* $Id: packet.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+
+/*
+<++doc++>
+@name int pkt_init(struct packet *pkt, unsigned long type, unsigned int size)
+@desc Allocates memory for a new packet and initializes its internal variables
+@param pkt pointer to the new packet
+@param type type of the packet. Its setting is currently ignored, but this is likely to change. Possible values are e.g. PKT_NET_IP|PKT_TRANS_TCP. See packet.h for other values
+@param size overall size if the packet not including ethernet headers or trailers.
+<--doc-->
+*/
+int
+pkt_init(struct packet *pkt, unsigned long type, unsigned int size)
+{
+       if ((pkt->pkt = (unsigned char *) malloc(size)) == NULL) {
+               /* no mem, we assume errno will be set */
+               return -1;
+       } else {
+               /* clear mem out */
+               memset(pkt->pkt, 0, size);
+               /* init vars */
+               pkt->pkt_type = type;
+               pkt->pkt_size = size;
+               /* set active ptr to beginning of mem */
+               pkt->pkt_ptr = pkt->pkt;
+               pkt->pkt_pos = 0;
+               return 0;
+       }
+}
+
+/*
+<++doc++>
+@name int pkt_free(struct packet *pkt)
+@desc Used to destroy a packet and to free used memory
+@param pkt the packet to destroy
+<--doc-->
+*/
+int
+pkt_free(struct packet *pkt)
+{
+       if (pkt) {
+               free(pkt->pkt);
+               pkt->pkt=NULL;
+               return 0;
+       }
+       return EPKTINVALPTR;
+}
+
+/*
+<++doc++>
+@name int pkt_set_actptr(struct packet *pkt, unsigned int bytepos)
+@desc This function sets the active pointer position inside the packet.
+@param pkt the packet whose active ptr is to be set
+@param bytepos the byte position where to set the active ptr to, starting from 0
+<--doc-->
+*/
+
+int
+pkt_set_actptr(struct packet *pkt, unsigned int bytepos)
+{
+       if (!pkt)
+               return EPKTINVALPTR;
+       if (bytepos > pkt->pkt_size) {
+               return EPKTRANGE;
+       } else {
+               pkt->pkt_ptr = pkt->pkt + bytepos;
+               return PKTOK;
+       }
+}
+
+/*
+<++doc++>
+@name int pkt_move_actptr(struct packet *pkt, int relmov) 
+@desc This function moves the active pointer inside the packet.
+@param pkt the packet whose active ptr is to be moved
+@param relmov number of bytes the active ptr shall be moved. To move it backward, negative values may be used.
+<--doc-->
+*/
+int 
+pkt_move_actptr(struct packet *pkt, int relmov)
+{
+       if (!pkt)
+               return EPKTINVALPTR;
+       if ((pkt->pkt_pos + relmov > pkt->pkt_size) ||
+               (pkt->pkt_pos + relmov < 0)) {
+               return EPKTRANGE;
+       } else {
+               pkt->pkt_ptr += relmov;
+               return PKTOK;
+       }
+}
+
+/*
+<++doc++>
+@name int pkt_add_data(struct packet *pkt, char *data, size_t data_len)
+@desc Adds supplied data at the current active ptr position of the given packet.This basically is a memcpy() wrapper function.
+@param pkt data will be written into this packet
+@param data a pointer to the data that shall be copied into the packet
+@param data_len the amount of data (in bytes) that will be copied
+<--doc-->
+*/
+int
+pkt_add_data(struct packet *pkt, char *data, size_t data_len)
+{
+       if (!pkt || !data)
+               return EPKTINVALPTR;
+       if (pkt->pkt_size >= (pkt->pkt_pos + data_len)) {
+               memcpy(pkt->pkt_ptr, data, data_len);
+               return 0;
+       } else
+               return EPKTRANGE;
+}
+
+/*
+<++doc++>
+@name int pkt_resize(struct packet *pkt, unsigned int newsize)
+@desc The given packet will be resized to newsize
+@param pkt the packet to resize
+@param newsize the new size of the packet
+<--doc-->
+*/
+int
+pkt_resize(struct packet *pkt, unsigned int newsize)
+{
+       unsigned char *newpkt;
+
+       if (!pkt)
+               return EPKTINVALPTR;
+
+       if ((newpkt = (unsigned char *) malloc(newsize)) != NULL) {
+               memset(newpkt, 0, newsize);
+               memcpy(newpkt, pkt->pkt, (pkt->pkt_size < newsize ? pkt->pkt_size : newsize));
+               pkt->pkt_size = newsize;
+               pkt->pkt_ptr = newpkt;
+               pkt->pkt_pos = 0;
+               /* free old mem */
+               free (pkt->pkt);
+               pkt->pkt = newpkt;
+               return 0;
+       } else
+               return EERRNO;
+}
diff --git a/projects/stargazer/plugins/capture/cap_debug/socket.c b/projects/stargazer/plugins/capture/cap_debug/socket.c
new file mode 100644 (file)
index 0000000..b7044bc
--- /dev/null
@@ -0,0 +1,163 @@
+/* $Id: socket.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+
+/*
+<++doc++>
+@name int pkt_socket_open(struct pkt_socket *sck, int type)
+@desc Opens a packet socket. This is necessary to be able to send any packages.
+@param sck pointer to a pkt_socket structure
+@param type The type of the socket. Possible values are PKT_RAW (to open a raw socket. IP, TCP/UDP and application header have to be forged before sending) , PKT_STREAM, PKT_DGRAM. STREAM and DGRAM are supported by this function, but other function do not care.
+<--doc-->
+*/
+int
+pkt_socket_open(struct pkt_socket *sck, int type)
+{
+       int proto;
+       int iphdrincl = 1;
+       int ret = 0;
+
+       if (!sck)
+               return EPKTINVALPTR;
+       
+       /* get mem for sockaddr structure */
+       if ((sck->sckad = (struct sockaddr_in *) malloc (sizeof(struct sockaddr_in))) == NULL) {
+               return -1;
+       }
+       sck->sckad_len = sizeof(struct sockaddr_in);
+       memset(sck->sckad, 0, sck->sckad_len);
+       
+       /* except for raw sockets, proto is set to 0 */
+       /* (Stevens, UNP 2nd ed., 1998) */
+       switch (type) {
+               case PKT_RAW:
+                       proto = IPPROTO_RAW;
+                       break;
+               default:
+                       proto = 0;
+                       break;
+       }
+       if ((sck->rawfd = socket(AF_INET, type, proto)) == -1) {
+               return -1;
+       }
+       if (type == PKT_RAW) {
+               if ((ret = setsockopt(sck->rawfd, IPPROTO_IP, IP_HDRINCL, (const void *) &iphdrincl, sizeof(iphdrincl))) < 0) {
+                       return -1;
+               }
+       }
+       return 0;
+}      
+
+       
+/*
+<++doc++>
+@name int pkt_socket_close(struct pkt_socket *sck)
+@desc Closes a packet socket and frees used memory.
+@param sck pointer to a pkt_socket structure
+<--doc-->
+*/
+int
+pkt_socket_close(struct pkt_socket *sck)
+{
+       if (!sck)
+               return EPKTINVALPTR;
+       close(sck->rawfd);
+       free(sck->sckad);
+       sck->sckad=NULL;
+       return 0;
+}
+
+/*
+<++doc++>
+@name int pkt_socket_prepare(struct pkt_socket *sck, char *daddr)
+@desc this function is necessary to enable the kernel to determine the correct outgoing interface
+@param sck pointer to a pkt_socket structure
+@param daddr dotted-decimal destination IP address
+<--doc-->
+*/
+int
+pkt_socket_prepare(struct pkt_socket *sck, char *daddr)
+{
+       /* 
+       * this is necessary for the kernel to determine outgoing
+       * interface.
+       */
+       
+       int ret = 0;
+       
+       if (!sck || !daddr)
+               return EPKTINVALPTR;
+               
+       /* set up sockaddr struct */
+       memset(sck->sckad, 0, sck->sckad_len);
+       if ((ret = inet_pton(AF_INET, daddr, &(sck->sckad->sin_addr))) == 0) {
+               return -1;
+       }
+       sck->sckad->sin_family = AF_INET;
+       
+       /*
+       * i dont think we need to set the dest port...
+       */
+       return 0;
+}
+
+/*
+<++doc++>
+@name int pkt_socket_setopt(struct pkt_socket *sck, int level, int optname, void *optval, socklen_t optlen)
+@desc this is basically a wrapper function for setsockopt(2)
+@param sck pointer to a pkt_socket structure
+@param level level the socket option will apply to (should be SOL_SOCKET)
+@param optname option name, see sys/socket.h for values
+@param optval new option value (for boolean options: 0=false)
+@param optlen option value size (this is a value-result parameter!)
+<--doc-->
+*/
+int
+pkt_socket_setopt(struct pkt_socket *sck, int level, 
+               int optname, void *optval, socklen_t optlen)
+{
+       if (!sck)
+               return EPKTINVALPTR;
+       return (setsockopt(sck->rawfd, level, optname, optval, optlen));
+}
+
+
+/*
+<++doc++>
+@name int pkt_send(struct packet *pkt, struct pkt_socket *sck)
+@desc sends the packet pkt unsing the socket sck
+@param pkt pointer to a packet structure
+@param sck pointer to a pkt_socket structure
+<--doc-->
+*/
+int 
+pkt_send(struct packet *pkt, struct pkt_socket *sck)
+{
+       int ret = 0;
+       
+       if (!pkt || !sck)
+               return EPKTINVALPTR;
+       
+       /* no sendto-flags support */
+       if ((ret = sendto(sck->rawfd, pkt->pkt, pkt->pkt_size, 0, (struct sockaddr *) sck->sckad, sck->sckad_len)) == -1) {
+               return -1;
+       }
+       return 0;
+}
diff --git a/projects/stargazer/plugins/capture/cap_debug/tcp.c b/projects/stargazer/plugins/capture/cap_debug/tcp.c
new file mode 100644 (file)
index 0000000..ad39931
--- /dev/null
@@ -0,0 +1,154 @@
+/* $Id: tcp.c,v 1.2 2009/06/19 12:50:47 faust Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+#include "types.h" /* internal types */
+
+int
+pkt_tcp_header(struct packet *pkt,
+                unsigned short int sport,
+                unsigned short int dport,
+                unsigned int seq,
+                unsigned int ackseq,
+                unsigned char headerlen,
+                unsigned char reserved,
+                unsigned char flags,
+                unsigned short window,
+                unsigned short int checksum,
+                unsigned short int urgent)
+{
+       struct tcphdr *tcp;
+
+       if (!pkt)
+               return EPKTINVALPTR;
+       
+       tcp = (struct tcphdr *) pkt->pkt_ptr;
+       tcp->source = htons(sport);
+        tcp->dest = htons(dport);
+        tcp->seq = htonl(seq);
+        tcp->ack_seq = htonl(ackseq);
+        tcp->window = htons(window);
+        tcp->urg_ptr = htons(urgent);
+
+        tcp->doff = headerlen;
+        tcp->res1 = reserved;
+        if (flags) {
+                tcp->fin = ((flags & TH_FIN) != 0);
+                tcp->syn = ((flags & TH_SYN) != 0);
+                tcp->rst = ((flags & TH_RST) != 0);
+                tcp->psh = ((flags & TH_RST) != 0);
+                tcp->ack = ((flags & TH_ACK) != 0);
+                tcp->urg = ((flags & TH_URG) != 0);
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+                tcp->res2 = (flags & (TH_XMAS | TH_YMAS)) >> 6;
+#  elif __BYTE_ORDER == __BIG_ENDIAN
+                tcp->res2 = (flags & (TH_XMAS | TH_YMAS));
+#  else
+#   error "Adjust your <bits/endian.h> defines"
+#  endif
+        } else {
+                tcp->fin = 0; 
+                tcp->syn = 0;
+                tcp->rst = 0;
+                tcp->psh = 0; 
+                tcp->ack = 0;
+                tcp->urg = 0;
+                tcp->res2 = 0;
+        }
+       tcp->check = htons(checksum);
+       return 0;
+}
+
+int
+pkt_tcp_cksum(struct packet *pkt, char *saddr, char *daddr, 
+               unsigned int tcp_pkt_size)
+{
+       char *tosum;
+       struct pseudohdr *psh;
+       struct tcphdr *tcp;
+       struct in_addr addr;
+
+       if (!pkt || !saddr || !daddr)
+               return EPKTINVALPTR;
+       
+       if ((tcp_pkt_size + pkt->pkt_pos) > pkt->pkt_size -1)
+               return EPKTRANGE;
+       
+       if ((tosum = (char *) malloc(tcp_pkt_size+sizeof(struct pseudohdr))) != NULL) {
+               memset(tosum, 0, tcp_pkt_size+sizeof(struct pseudohdr));
+               psh = (struct pseudohdr *) tosum;
+               tcp = (struct tcphdr *) pkt->pkt_ptr;
+
+               tcp->check = 0;
+               
+               if (inet_pton(AF_INET, saddr, &addr) < 0)
+                       return EERRNO;
+               psh->saddr = addr.s_addr;
+               if (inet_pton(AF_INET, daddr, &addr) < 0)
+                       return EERRNO;
+               psh->daddr = addr.s_addr;
+               psh->zero = 0x00;
+               psh->protocol = IPPROTO_TCP;
+               psh->length = htons(tcp_pkt_size);
+               
+               memcpy(tosum + sizeof(struct pseudohdr), tcp, tcp_pkt_size);
+               tcp->check = in_cksum((unsigned short *)tosum, tcp_pkt_size + sizeof(struct pseudohdr));
+               free(tosum);
+               return 0;
+       } else
+               return EERRNO;
+}
+               
+int
+pkt_tcp_option(struct packet *pkt, unsigned char kind, 
+               unsigned char len, void *optval, size_t optlen)
+{
+       void *vp;
+       unsigned short int mss;
+
+       if (!pkt)
+               return EPKTINVALPTR;
+       
+       if ((pkt->pkt_size) < (pkt->pkt_pos+2+optlen))
+               return EPKTRANGE;
+       
+       vp = (void *)pkt->pkt_ptr;
+
+       memcpy(vp, &kind, 1);
+       char * p;
+       p = (char*)vp;
+       p++;
+       vp = p;
+       //vp++;
+       memcpy(vp, &len, 1);
+       //vp++;
+       p = (char*)vp;
+       p++;
+       vp = p;
+       if (kind == PKT_TCP_OPT_MSS) {
+               mss = htons(*(unsigned short int *)optval);
+               memcpy(vp, &mss, optlen);
+       } else if (kind ==  PKT_TCP_OPT_TIME) {
+               unsigned int time = htonl(*(unsigned int *)optval);
+               memcpy(vp, &time, optlen);
+       } else {
+               memcpy(vp, optval, optlen);
+       }
+       return 0;
+}
diff --git a/projects/stargazer/plugins/capture/cap_debug/types.h b/projects/stargazer/plugins/capture/cap_debug/types.h
new file mode 100644 (file)
index 0000000..3d428fe
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id: types.h,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _LIBPAL_TYPES_H_
+#define _LIBPAL_TYPES_H_
+
+/*
+* these are types users wont need
+*/
+
+/* Stevens' pseudo header */
+struct pseudohdr {
+        u_int32_t       saddr;
+        u_int32_t       daddr;
+        u_int8_t        zero;
+        u_int8_t        protocol;
+        u_int16_t       length;
+};
+#endif
diff --git a/projects/stargazer/plugins/capture/cap_debug/udp.c b/projects/stargazer/plugins/capture/cap_debug/udp.c
new file mode 100644 (file)
index 0000000..238c95d
--- /dev/null
@@ -0,0 +1,82 @@
+/* $Id: udp.c,v 1.1 2005/12/12 18:14:22 nobunaga Exp $ 
+
+Copyright (C) 2002 Marc Kirchner <kirchner@stud.fh-heilbronn.de>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "libpal.h"
+#include "types.h"
+
+int 
+pkt_udp_header(struct packet *pkt, unsigned short int sport, unsigned short int dport, unsigned short int udp_total_len, unsigned short int checksum)
+{
+       struct udphdr *udp;
+       
+       if (!pkt)
+               return EPKTINVALPTR;
+       if (pkt->pkt_size >= (pkt->pkt_pos + sizeof(struct udphdr))) {
+               udp = (struct udphdr *) pkt->pkt_ptr;
+               udp->source = htons(sport);
+               udp->dest = htons(dport);
+               udp->len = htons(udp_total_len);
+               udp->check = htons(checksum);
+               return 0;
+       } else
+               return EPKTRANGE;
+}
+
+int
+pkt_udp_cksum(struct packet *pkt, char *saddr, char *daddr,
+                unsigned int udp_total_len)
+{
+        char *tosum;
+        struct pseudohdr *psh;
+        struct udphdr *udp;
+       unsigned short int check=0;
+       struct in_addr addr;
+
+        if (!pkt || !saddr || !daddr)
+                return EPKTINVALPTR;
+
+        if ((udp_total_len + pkt->pkt_pos) > pkt->pkt_size -1)
+                return EPKTRANGE;
+
+        if ((tosum = (char *) malloc(udp_total_len+sizeof(struct pseudohdr))) != NULL) {
+                memset(tosum, 0, udp_total_len+sizeof(struct pseudohdr));
+                psh = (struct pseudohdr *) tosum;
+                udp = (struct udphdr *) pkt->pkt_ptr;
+
+                udp->check = 0;
+
+               if (inet_pton(AF_INET, saddr, &addr) < 0)
+                       return EERRNO;
+               psh->saddr = addr.s_addr;
+               if (inet_pton(AF_INET, daddr, &addr) < 0)
+                       return EERRNO;
+               psh->daddr = addr.s_addr;
+                psh->zero = 0x00;
+                psh->protocol = IPPROTO_UDP;
+                psh->length = htons(udp_total_len);
+
+                memcpy(tosum + sizeof(struct pseudohdr), udp, udp_total_len);
+                check = in_cksum((unsigned short *)tosum, udp_total_len + sizeof(struct pseudohdr));
+               /* _no_ call to htons(), because tosum is in network byte order */
+               udp->check = check == 0 ? 0xffff : check;
+                free(tosum);
+                return 0;
+        } else
+                return EERRNO;
+}
diff --git a/projects/stargazer/plugins/capture/cap_nf/Makefile b/projects/stargazer/plugins/capture/cap_nf/Makefile
new file mode 100644 (file)
index 0000000..3eddb29
--- /dev/null
@@ -0,0 +1,15 @@
+###############################################################################
+# $Id: Makefile,v 1.2 2008/12/04 17:04:41 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_nf.so
+
+SRCS = ./cap_nf.cpp
+
+LIBS += $(LIB_THREAD)
+STGLIBS = -lstg_common
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp b/projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp
new file mode 100644 (file)
index 0000000..11a96ef
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ *    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: 16.05.2008
+*/
+
+/*
+* Author : Maxim Mamontov <faust@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.11 $
+$Date: 2010/09/10 06:41:06 $
+$Author: faust $
+*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <csignal>
+#include <cerrno>
+#include <cstring>
+
+#include "common.h" 
+#include "cap_nf.h"
+#include "raw_ip_packet.h"
+
+#include "../../../traffcounter.h"
+
+class CAP_NF_CREATOR
+{
+public:
+    CAP_NF_CREATOR()
+        : nf(new NF_CAP())
+        {
+        };
+
+    ~CAP_NF_CREATOR()
+        {
+        delete nf;
+        };
+
+    NF_CAP * GetCapturer() { return nf; };
+private:
+    NF_CAP * nf;
+} cnc;
+
+BASE_PLUGIN * GetPlugin()
+{
+return cnc.GetCapturer();
+}
+
+NF_CAP::NF_CAP()
+    : traffCnt(NULL),
+      tidTCP(0),
+      tidUDP(0),
+      runningTCP(false),
+      runningUDP(false),
+      stoppedTCP(true),
+      stoppedUDP(true),
+      portT(0),
+      portU(0),
+      sockTCP(-1),
+      sockUDP(-1)
+{
+}
+
+NF_CAP::~NF_CAP()
+{
+}
+
+int NF_CAP::ParseSettings()
+{
+vector<PARAM_VALUE>::iterator it;
+for (it = settings.moduleParams.begin(); it != settings.moduleParams.end(); ++it)
+    {
+    if (it->param == "TCPPort")
+        {
+        if (str2x(it->value[0], portT))
+            {
+            errorStr = "Invalid TCPPort value";
+            printfd(__FILE__, "Error: Invalid TCPPort value\n");
+            return -1;
+            }
+        continue;
+        }
+    if (it->param == "UDPPort")
+        {
+        if (str2x(it->value[0], portU))
+            {
+            errorStr = "Invalid UDPPort value";
+            printfd(__FILE__, "Error: Invalid UDPPort value\n");
+            return -1;
+            }
+        continue;
+        }
+    printfd(__FILE__, "'%s' is not a valid module param\n", it->param.c_str());
+    }
+return 0;
+}
+
+int NF_CAP::Start()
+{
+if (portU > 0)
+    {
+    if (OpenUDP())
+        {
+        return -1;
+        }
+    runningUDP = true;
+    if (pthread_create(&tidUDP, NULL, RunUDP, this))
+        {
+        runningUDP = false;
+        CloseUDP();
+        errorStr = "Cannot create UDP thread";
+        printfd(__FILE__, "Error: Cannot create UDP thread\n");
+        return -1;
+        }
+    }
+if (portT > 0)
+    {
+    if (OpenTCP())
+        {
+        return -1;
+        }
+    runningTCP = true;
+    if (pthread_create(&tidTCP, NULL, RunTCP, this))
+        {
+        runningTCP = false;
+        CloseTCP();
+        errorStr = "Cannot create TCP thread";
+        printfd(__FILE__, "Error: Cannot create TCP thread\n");
+        return -1;
+        }
+    }
+return 0;
+}
+
+int NF_CAP::Stop()
+{
+runningTCP = runningUDP = false;
+if (portU && !stoppedUDP)
+    {
+    CloseUDP();
+    for (int i = 0; i < 25 && !stoppedUDP; ++i)
+        {
+        usleep(200000);
+        }
+    if (stoppedUDP)
+        {
+        pthread_join(tidUDP, NULL);
+        }
+    else
+        {
+        if (pthread_kill(tidUDP, SIGUSR1))
+            {
+            errorStr = "Error sending signal to UDP thread";
+            printfd(__FILE__, "Error: Error sending signal to UDP thread\n");
+            return -1;
+            }
+        printfd(__FILE__, "UDP thread NOT stopped\n");
+        }
+    }
+if (portT && !stoppedTCP)
+    {
+    CloseTCP();
+    for (int i = 0; i < 25 && !stoppedTCP; ++i)
+        {
+        usleep(200000);
+        }
+    if (stoppedTCP)
+        {
+        pthread_join(tidTCP, NULL);
+        }
+    else
+        {
+        if (pthread_kill(tidTCP, SIGUSR1))
+            {
+            errorStr = "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");
+        }
+    }
+return 0;
+}
+
+bool NF_CAP::OpenUDP()
+{
+struct sockaddr_in sin;
+sockUDP = socket(PF_INET, SOCK_DGRAM, 0);
+if (sockUDP <= 0)
+    {
+    errorStr = "Error opening UDP socket";
+    printfd(__FILE__, "Error: Error opening UDP socket\n");
+    return true;
+    }
+sin.sin_family = AF_INET;
+sin.sin_port = htons(portU);
+sin.sin_addr.s_addr = inet_addr("0.0.0.0");
+if (bind(sockUDP, (struct sockaddr *)&sin, sizeof(sin)))
+    {
+    errorStr = "Error binding UDP socket";
+    printfd(__FILE__, "Error: Error binding UDP socket\n");
+    return true;
+    }
+return false;
+}
+
+bool NF_CAP::OpenTCP()
+{
+struct sockaddr_in sin;
+sockTCP = socket(PF_INET, SOCK_STREAM, 0);
+if (sockTCP <= 0)
+    {
+    errorStr = "Error opening TCP socket";
+    printfd(__FILE__, "Error: Error opening TCP socket\n");
+    return true;
+    }
+sin.sin_family = AF_INET;
+sin.sin_port = htons(portT);
+sin.sin_addr.s_addr = inet_addr("0.0.0.0");
+if (bind(sockTCP, (struct sockaddr *)&sin, sizeof(sin)))
+    {
+    errorStr = "Error binding TCP socket";
+    printfd(__FILE__, "Error: Error binding TCP socket\n");
+    return true;
+    }
+if (listen(sockTCP, 1))
+    {
+    errorStr = "Error listening on TCP socket";
+    printfd(__FILE__, "Error: Error listening TCP socket\n");
+    return true;
+    }
+return false;
+}
+
+void * NF_CAP::RunUDP(void * c)
+{
+NF_CAP * cap = static_cast<NF_CAP *>(c);
+uint8_t buf[BUF_SIZE];
+int res;
+struct sockaddr_in sin;
+socklen_t slen;
+cap->stoppedUDP = false;
+while (cap->runningUDP)
+    {
+    if (!cap->WaitPackets(cap->sockUDP))
+        {
+        continue;
+        }
+
+    // Data
+    slen = sizeof(sin);
+    res = recvfrom(cap->sockUDP, buf, BUF_SIZE, 0, reinterpret_cast<struct sockaddr *>(&sin), &slen);
+    if (!cap->runningUDP)
+        break;
+
+    if (res == 0) // EOF
+        {
+        continue;
+        }
+
+
+    // Wrong logic!
+    // Need to check actual data length and wait all data to receive
+    if (res < 24)
+        {
+        if (errno != EINTR)
+            {
+            cap->errorStr = "Invalid data received";
+            printfd(__FILE__, "Error: Invalid data received through UDP\n");
+            }
+        continue;
+        }
+
+    cap->ParseBuffer(buf, res);
+    }
+cap->stoppedUDP = true;
+return NULL;
+}
+
+void * NF_CAP::RunTCP(void * c)
+{
+NF_CAP * cap = static_cast<NF_CAP *>(c);
+uint8_t buf[BUF_SIZE];
+int res;
+int sd;
+struct sockaddr_in sin;
+socklen_t slen;
+cap->stoppedTCP = false;
+while (cap->runningTCP)
+    {
+    if (!cap->WaitPackets(cap->sockTCP))
+        {
+        continue;
+        }
+
+    // Data
+    slen = sizeof(sin);
+    sd = accept(cap->sockTCP, reinterpret_cast<struct sockaddr *>(&sin), &slen);
+    if (!cap->runningTCP)
+        break;
+
+    if (sd <= 0)
+        {
+        if (errno != EINTR)
+            {
+            cap->errorStr = "Error accepting connection";
+            printfd(__FILE__, "Error: Error accepting connection\n");
+            }
+        continue;
+        }
+
+    if (!cap->WaitPackets(sd))
+        {
+        close(sd);
+        continue;
+        }
+
+    res = recv(sd, buf, BUF_SIZE, MSG_WAITALL);
+    close(sd);
+
+    if (!cap->runningTCP)
+        break;
+
+    if (res == 0) // EOF
+        {
+        continue;
+        }
+
+    // Wrong logic!
+    // Need to check actual data length and wait all data to receive
+    if (res < 24)
+        {
+        if (errno != EINTR)
+            {
+            cap->errorStr = "Invalid data received";
+            printfd(__FILE__, "Error: Invalid data received through TCP\n");
+            }
+        continue;
+        }
+
+    cap->ParseBuffer(buf, res);
+    }
+cap->stoppedTCP = true;
+return NULL;
+}
+
+void NF_CAP::ParseBuffer(uint8_t * buf, int size)
+{
+RAW_PACKET ip;
+NF_HEADER * hdr = reinterpret_cast<NF_HEADER *>(buf);
+if (htons(hdr->version) != 5)
+    {
+    return;
+    }
+
+int packets = htons(hdr->count);
+
+if (packets < 0 || packets > 30)
+    {
+    return;
+    }
+
+if (24 + 48 * packets != size)
+    {
+    // See 'wrong logic' upper
+    return;
+    }
+
+for (int i = 0; i < packets; ++i)
+    {
+    NF_DATA * data = reinterpret_cast<NF_DATA *>(buf + 24 + i * 48);
+
+    /*ip.pckt[0] = 4 << 4;
+    ip.pckt[0] |= 5;
+    ip.pckt[9] = data->proto;
+    ip.dataLen = ntohl(data->octets);
+    *(uint32_t *)(ip.pckt + 12) = data->srcAddr;
+    *(uint32_t *)(ip.pckt + 16) = data->dstAddr;
+    *(uint16_t *)(ip.pckt + 20) = data->srcPort;
+    *(uint16_t *)(ip.pckt + 22) = data->dstPort;*/
+    ip.ipHeader.ip_v = 4;
+    ip.ipHeader.ip_hl = 5;
+    ip.ipHeader.ip_p = data->proto;
+    ip.dataLen = ntohl(data->octets);
+    ip.ipHeader.ip_src.s_addr = data->srcAddr;
+    ip.ipHeader.ip_dst.s_addr = data->dstAddr;
+    ip.sPort = data->srcPort;
+    ip.dPort = data->dstPort;
+
+    traffCnt->Process(ip);
+    }
+}
+
+bool NF_CAP::WaitPackets(int sd) const
+{
+fd_set rfds;
+FD_ZERO(&rfds);
+FD_SET(sd, &rfds);
+
+struct timeval tv;
+tv.tv_sec = 0;
+tv.tv_usec = 500000;
+
+int res = select(sd + 1, &rfds, NULL, NULL, &tv);
+if (res == -1) // Error
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
+        }
+    return false;
+    }
+
+if (res == 0) // Timeout
+    {
+    return false;
+    }
+
+return true;
+}
diff --git a/projects/stargazer/plugins/capture/cap_nf/cap_nf.h b/projects/stargazer/plugins/capture/cap_nf/cap_nf.h
new file mode 100644 (file)
index 0000000..6844fe2
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *    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: 16.05.2008
+*/
+
+/*
+* Author : Maxim Mamontov <faust@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.5 $
+$Date: 2009/12/13 12:56:07 $
+$Author: faust $
+*/
+#ifndef __CAP_NF_H__
+#define __CAP_NF_H__
+
+#include <string>
+#include <pthread.h>
+
+#include "os_int.h"
+#include "base_plugin.h"
+
+#define VERSION "CAP_NF v. 0.4"
+#define START_POS 0
+#define STOP_POS 0
+
+struct NF_HEADER
+{
+    uint16_t version;   // Protocol version
+    uint16_t count;     // Flows count
+    uint32_t uptime;    // System uptime
+    uint32_t timestamp; // UNIX timestamp
+    uint32_t nsecs;     // Residual nanoseconds
+    uint32_t flowSeq;   // Sequence counter
+    uint8_t  eType;     // Engine type
+    uint8_t  eID;       // Engine ID
+    uint16_t sInterval; // Sampling mode and interval
+} __attribute__ ((packed));
+
+struct NF_DATA
+{
+    uint32_t srcAddr;   // Flow source address
+    uint32_t dstAddr;   // Flow destination address
+    uint32_t nextHop;   // IP addres on next hop router
+    uint16_t inSNMP;    // SNMP index of input iface
+    uint16_t outSNMP;   // SNMP index of output iface
+    uint32_t packets;   // Packets in flow
+    uint32_t octets;    // Total number of bytes in flow
+    uint32_t timeStart; // Uptime on first packet in flow
+    uint32_t timeFinish;// Uptime on last packet in flow
+    uint16_t srcPort;   // Flow source port
+    uint16_t dstPort;   // Flow destination port
+    uint8_t  pad1;      // 1-byte padding
+    uint8_t  TCPFlags;  // Cumulative OR of TCP flags
+    uint8_t  proto;     // IP protocol type (tcp, udp, etc.)
+    uint8_t  tos;       // IP Type of Service (ToS)
+    uint16_t srcAS;     // Source BGP autonomous system number
+    uint16_t dstAS;     // Destination BGP autonomus system number
+    uint8_t  srcMask;   // Source address mask in "slash" notation
+    uint8_t  dstMask;   // Destination address mask in "slash" notation
+    uint16_t pad2;      // 2-byte padding
+} __attribute__ ((packed));
+
+#define BUF_SIZE (sizeof(NF_HEADER) + 30 * sizeof(NF_DATA))
+
+class NF_CAP : public BASE_PLUGIN 
+{
+public:
+    NF_CAP();
+    ~NF_CAP();
+
+    void            SetUsers(USERS *) {};
+    void            SetTariffs(TARIFFS *) {};
+    void            SetAdmins(ADMINS *) {};
+    void            SetTraffcounter(TRAFFCOUNTER * tc) { traffCnt = tc; };
+    void            SetStore(BASE_STORE *) {};
+    void            SetStgSettings(const SETTINGS *) {};
+    void            SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int             ParseSettings();
+
+    int             Start();
+    int             Stop();
+    int             Reload() { return 0; };
+    bool            IsRunning() { return runningTCP || runningUDP; };
+    const string  & GetStrError() const { return errorStr; };
+    const string    GetVersion() const { return VERSION; };
+    uint16_t        GetStartPosition() const { return START_POS; };
+    uint16_t        GetStopPosition() const { return STOP_POS; };
+
+private:
+    TRAFFCOUNTER * traffCnt;
+    MODULE_SETTINGS settings;
+    pthread_t tidTCP;
+    pthread_t tidUDP;
+    bool runningTCP;
+    bool runningUDP;
+    bool stoppedTCP;
+    bool stoppedUDP;
+    uint16_t portT;
+    uint16_t portU;
+    int sockTCP;
+    int sockUDP;
+    mutable std::string errorStr;
+
+    static void * RunUDP(void *);
+    static void * RunTCP(void *);
+    void ParseBuffer(uint8_t *, int);
+
+    bool OpenTCP();
+    bool OpenUDP();
+    void CloseTCP() { close(sockTCP); };
+    void CloseUDP() { close(sockUDP); };
+
+    bool WaitPackets(int sd) const;
+};
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+#endif
diff --git a/projects/stargazer/plugins/capture/divert_freebsd/Makefile b/projects/stargazer/plugins/capture/divert_freebsd/Makefile
new file mode 100644 (file)
index 0000000..cd7824a
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.4 2008/12/04 17:05:21 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_divert.so
+
+SRCS = ./divert_cap.cpp 
+
+STGLIBS = -lstg_common
+
+LIBS += $(LIB_THREAD)
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/divert_freebsd/divert_cap.cpp b/projects/stargazer/plugins/capture/divert_freebsd/divert_cap.cpp
new file mode 100644 (file)
index 0000000..a76629f
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ *    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@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.13 $
+$Date: 2010/09/10 06:43:03 $
+*/
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "divert_cap.h"
+
+#define BUFF_LEN (16384) /* max mtu -> lo=16436  TODO why?*/
+
+//-----------------------------------------------------------------------------
+struct DIVERT_DATA
+{
+int sock;
+short int port;
+unsigned char buffer[BUFF_LEN];
+char iface[10];
+};
+//-----------------------------------------------------------------------------
+pollfd pollddiv;
+DIVERT_DATA cddiv;  //capture data
+//-----------------------------------------------------------------------------
+class DIVERT_CAP_CREATOR
+{
+private:
+    DIVERT_CAP * divc;
+
+public:
+    DIVERT_CAP_CREATOR()
+        : divc(new DIVERT_CAP())
+        {
+        };
+    ~DIVERT_CAP_CREATOR()
+        {
+        delete divc;
+        };
+
+    DIVERT_CAP * GetCapturer()
+    {
+    return divc;
+    };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+DIVERT_CAP_CREATOR dcc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return dcc.GetCapturer();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string DIVERT_CAP::GetVersion() const
+{
+return "Divert_cap v.1.0";
+}
+//-----------------------------------------------------------------------------
+DIVERT_CAP::DIVERT_CAP()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void DIVERT_CAP::SetTraffcounter(TRAFFCOUNTER * tc)
+{
+traffCnt = tc;
+}
+//-----------------------------------------------------------------------------
+const string & DIVERT_CAP::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::Start()
+{
+if (isRunning)
+    return 0;
+
+if (DivertCapOpen() < 0)
+    {
+    errorStr = "Cannot open socket!";
+    printfd(__FILE__, "Cannot open socket\n");
+    return -1;
+    }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this) == 0)
+    {
+    return 0;
+    }
+
+errorStr = "Cannot create thread.";
+printfd(__FILE__, "Cannot create thread\n");
+return -1;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+
+DivertCapClose();
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        printfd(__FILE__, "Cannot kill thread\n");
+        return -1;
+        }
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool DIVERT_CAP::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * DIVERT_CAP::Run(void * d)
+{
+DIVERT_CAP * dc = (DIVERT_CAP *)d;
+dc->isRunning = true;
+
+/*struct ETH_IP
+{
+uint16_t    ethHdr[8];
+RAW_PACKET  rp;
+char        padding[4];
+char        padding1[8];
+};
+
+ETH_IP * ethIP;
+
+char ethip[sizeof(ETH_IP)];
+
+//memset(&ethIP, 0, sizeof(ethIP));
+memset(&ethip, 0, sizeof(ETH_IP));
+
+ethIP = (ETH_IP *)&ethip;
+ethIP->rp.dataLen = -1;
+*/
+//char * iface = NULL;
+char buffer[64];
+while (dc->nonstop)
+    {
+    RAW_PACKET rp;
+    dc->DivertCapRead(buffer, 64, NULL);
+
+    //printf("%x %x %x %x \n", buffer[0], buffer[4], buffer[8], buffer[12]);
+    //printf("%x %x %x %x \n", buffer[16], buffer[20], buffer[24], buffer[28]);
+    //printf("%x %x %x %x \n", buffer[32], buffer[36], buffer[40], buffer[44]);
+
+    if (buffer[12] != 0x8)
+        continue;
+
+    memcpy(rp.pckt, &buffer[14], pcktSize);
+
+    //dc->traffCnt->Process(*((RAW_PACKET*)( &buffer[14] ))); // - too dirty!
+    dc->traffCnt->Process(rp);
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t DIVERT_CAP::GetStartPosition() const
+{
+return 10;
+}
+//-----------------------------------------------------------------------------
+uint16_t DIVERT_CAP::GetStopPosition() const
+{
+return 10;
+}
+//-----------------------------------------------------------------------------
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapOpen()
+{
+memset(&pollddiv, 0, sizeof(pollddiv));
+memset(&cddiv, 0, sizeof(DIVERT_DATA));
+
+strcpy(cddiv.iface, "foo");
+cddiv.port = port;
+
+DivertCapOpen(0);
+pollddiv.events = POLLIN;
+pollddiv.fd = cddiv.sock;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapOpen(int)
+{
+int ret;
+cddiv.sock = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
+if (cddiv.sock < 0)
+    {
+    errorStr = "Create divert socket error.";
+    printfd(__FILE__, "Cannot create divert socket\n");
+    return -1;
+    }
+
+struct sockaddr_in divAddr;
+
+memset(&divAddr, 0, sizeof(divAddr));
+
+divAddr.sin_family = AF_INET;
+divAddr.sin_port = htons(cddiv.port);
+divAddr.sin_addr.s_addr = INADDR_ANY;
+
+ret = bind(cddiv.sock, (struct sockaddr *)&divAddr, sizeof(divAddr));
+
+if (ret < 0)
+    {
+    errorStr = "Bind divert socket error.";
+    printfd(__FILE__, "Cannot bind divert socket\n");
+    return -1;
+    }
+
+return cddiv.sock;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface)
+{
+poll(&pollddiv, 1, -1);
+
+if (pollddiv.revents & POLLIN)
+    {
+    DivertCapRead(b, blen, iface, 0);
+    pollddiv.revents = 0;
+    return 0;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface, int)
+{
+static char buf[BUFF_LEN];
+static struct sockaddr_in divertaddr;
+static int bytes;
+static socklen_t divertaddrSize = sizeof(divertaddr);
+
+if ((bytes = recvfrom (cddiv.sock, buf, BUFF_LEN,
+                       0, (struct sockaddr*) &divertaddr, &divertaddrSize)) > 50)
+    {
+    memcpy(b + 14, buf, blen - 14);
+    b[12] = 0x8;
+
+    if (iface)
+        *iface = cddiv.iface;
+
+    sendto(cddiv.sock, buf, bytes, 0, (struct sockaddr*)&divertaddr, divertaddrSize);
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::DivertCapClose()
+{
+close(cddiv.sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::ParseSettings()
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+
+pv.param = "Port";
+pvi = find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
+if (pvi == settings.moduleParams.end())
+    {
+    port = 15701;
+    return 0;
+    }
+
+if (ParseIntInRange(pvi->value[0], 1, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+    return -1;
+    }
+
+port = p;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DIVERT_CAP::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void DIVERT_CAP::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/capture/divert_freebsd/divert_cap.h b/projects/stargazer/plugins/capture/divert_freebsd/divert_cap.h
new file mode 100644 (file)
index 0000000..8423421
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *    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@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.6 $
+$Date: 2009/06/23 11:32:27 $
+*/
+
+#ifndef DIVERT_CAP_H
+#define DIVERT_CAP_H
+
+#include <string>
+#include <pthread.h>
+
+#include "base_plugin.h"
+#include "base_settings.h"
+#include "../../../traffcounter.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+//-----------------------------------------------------------------------------
+class DIVERT_CAP :public BASE_PLUGIN
+{
+public:
+    DIVERT_CAP();
+    virtual ~DIVERT_CAP(){};
+
+    void                SetUsers(USERS *){};
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER * tc);
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS *){};
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+private:
+    static void *       Run(void *);
+
+    int                 DivertCapOpen();
+    int                 DivertCapOpen(int n);
+    int                 DivertCapRead(char * buffer, int blen, char ** iface);
+    int                 DivertCapRead(char * buffer, int blen, char ** iface, int n);
+    int                 DivertCapClose();
+
+    int                 ParseIntInRange(const string & str, int min, int max, int * val);
+
+    MODULE_SETTINGS     settings;
+
+    int                 port;
+
+    mutable string      errorStr;
+
+    pthread_t           thread;
+
+    bool                nonstop;
+    bool                isRunning;
+
+    //int                 capSock;
+
+    TRAFFCOUNTER *      traffCnt;
+};
+//-----------------------------------------------------------------------------
+
+
+#endif
diff --git a/projects/stargazer/plugins/capture/ether_freebsd/Makefile b/projects/stargazer/plugins/capture/ether_freebsd/Makefile
new file mode 100644 (file)
index 0000000..4ab0480
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.7 2008/12/04 17:06:56 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_bpf.so
+
+SRCS = ./ether_cap.cpp 
+
+STGLIBS = -lstg_common
+
+LIBS += $(LIB_THREAD)
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/ether_freebsd/ether_cap.cpp b/projects/stargazer/plugins/capture/ether_freebsd/ether_cap.cpp
new file mode 100644 (file)
index 0000000..0ebec5b
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ *    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: 18.09.2002
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stg.dp.ua>
+*/
+
+/*
+$Revision: 1.19 $
+$Date: 2009/03/24 11:20:15 $
+$Author: faust $
+*/
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "ether_cap.h"
+#include "common.h"
+#include "raw_ip_packet.h"
+
+using namespace std;
+
+//#define CAP_DEBUG 1
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+class BPF_CAP_CREATOR
+{
+private:
+    BPF_CAP * bpfc;
+
+public:
+    BPF_CAP_CREATOR()
+        : bpfc(new BPF_CAP())
+        {
+        };
+    ~BPF_CAP_CREATOR()
+        {
+        delete bpfc;
+        };
+
+    BPF_CAP * GetCapturer()
+    {
+    return bpfc;
+    };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BPF_CAP_CREATOR bcc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return bcc.GetCapturer();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int BPF_CAP_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+//char sep[]= ", \t\n\r";
+//char *s;
+string ifaces;
+//char * str;
+//char *p;
+
+iface.erase(iface.begin(), iface.end());
+
+//PARAM_VALUE pv;
+//pv.param = "WorkDir";
+//vector<PARAM_VALUE>::const_iterator pvi;
+
+if (s.moduleParams.empty())
+    {
+    errorStr = "Parameter \'iface\' not found.";
+    printfd(__FILE__, "Parameter 'iface' not found\n");
+    return -1;
+    }
+
+for (unsigned i = 0; i < s.moduleParams.size(); i++)
+    {
+    if (s.moduleParams[i].param != "iface")
+        {
+        errorStr = "Parameter \'" + s.moduleParams[i].param + "\' unrecognized.";
+        printfd(__FILE__, "Invalid parameter: '%s'\n", s.moduleParams[i].param.c_str());
+        return -1;
+        }
+    for (unsigned j = 0; j < s.moduleParams[i].value.size(); j++)
+        {
+        iface.push_back(s.moduleParams[i].value[j]);
+        }
+    }
+
+/*if (cf.ReadString("Iface", &ifaces, "NoIface") < 0)
+    {
+    errorStr = "Cannot read parameter \'Iface\' from " + cf.GetFileName();
+    return -1;
+    }
+
+str = new char[ifaces.size() + 1];
+strcpy(str, ifaces.c_str());
+p = str;
+
+while((s = strtok(p, sep)))
+    {
+    printfd(__FILE__, "iface[] = %s\n", s);
+    p = NULL;
+    iface.push_back(s);
+    //strncpy(iface[i++], s, DEV_NAME_LEN);
+    //devNum++;
+    }
+
+delete[] str;
+if (!ifaces.size())
+    {
+    errorStr = "Error read parameter \'Iface\' from " + cf.GetFileName();
+    return -1;
+    }*/
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+string BPF_CAP_SETTINGS::GetIface(unsigned int num)
+{
+if (num >= iface.size())
+    {
+    return "";
+    }
+return iface[num];
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string BPF_CAP::GetVersion() const
+{
+return "bpf_cap v.1.0";
+}
+//-----------------------------------------------------------------------------
+BPF_CAP::BPF_CAP()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void BPF_CAP::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::ParseSettings()
+{
+int ret = capSettings.ParseSettings(settings);
+if (ret)
+    {
+    errorStr = capSettings.GetStrError();
+    return ret;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void BPF_CAP::SetTraffcounter(TRAFFCOUNTER * tc)
+{
+traffCnt = tc;
+}
+//-----------------------------------------------------------------------------
+const string & BPF_CAP::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::Start()
+{
+if (isRunning)
+    return 0;
+
+if (BPFCapOpen() < 0)
+    {
+    //errorStr = "Cannot open bpf device!";
+    return -1;
+    }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this) == 0)
+    {
+    return 0;
+    }
+
+errorStr = "Cannot create thread.";
+printfd(__FILE__, "Cannot create thread\n");
+return -1;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+
+BPFCapClose();
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    //TODO pthread_cancel()
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        printfd(__FILE__, "Cannot kill thread\n");
+        return -1;
+        }
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool BPF_CAP::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * BPF_CAP::Run(void * d)
+{
+BPF_CAP * dc = (BPF_CAP *)d;
+dc->isRunning = true;
+
+uint8_t hdr[96]; //68 + 14 + 4(size) + 9(SYS_IFACE) + 1(align to 4) = 96
+
+RAW_PACKET *  rpp = (RAW_PACKET *)&hdr[14];
+memset(hdr, 0, sizeof(hdr));
+
+rpp->dataLen = -1;
+char * iface;
+
+while (dc->nonstop)
+    {
+    dc->BPFCapRead((char*)&hdr, 68 + 14, &iface);
+
+    if (!(hdr[12] == 0x8 && hdr[13] == 0x0))
+    {
+        continue;
+    }
+
+    dc->traffCnt->Process(*rpp);
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t BPF_CAP::GetStartPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t BPF_CAP::GetStopPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapOpen()
+{
+//for (int i = 0; i < settings->devNum; i++)
+int i = 0;
+BPF_DATA bd;
+pollfd pd;
+
+while ((bd.iface = capSettings.GetIface(i)) != "")
+    {
+    bpfData.push_back(bd);
+    if (BPFCapOpen(&bpfData[i]) < 0)
+    {
+    return -1;
+    }
+
+    pd.events = POLLIN;
+    pd.fd = bpfData[i].fd;
+    polld.push_back(pd);
+    i++;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//int BPF_CAP::BPFCapOpen(string ifaceToOpen)
+int BPF_CAP::BPFCapOpen(BPF_DATA * bd)
+{
+char devbpf[20];
+int i = 0;
+int l = BUFF_LEN;
+int im = 1;
+struct ifreq ifr;
+
+do  {
+    sprintf(devbpf, "/dev/bpf%d", i);
+    i++;
+    bd->fd = open(devbpf, O_RDONLY);
+    //cd[n].fd = open(devbpf, O_RDONLY);
+    } while(bd->fd < 0 && errno == EBUSY);
+      //while(cd[n].fd < 0 && errno == EBUSY);
+
+//if (cd[n].fd < 0)
+if (bd->fd < 0)
+    {
+    errorStr = "Can't capture packets. Open bpf device for " + bd->iface + " error.";
+    printfd(__FILE__, "Cannot open BPF device\n");
+    return -1;
+    }
+
+//strncpy(ifr.ifr_name, settings->iface[n], sizeof(ifr.ifr_name));
+strncpy(ifr.ifr_name, bd->iface.c_str(), sizeof(ifr.ifr_name));
+
+//if (ioctl(cd[n].fd, BIOCSBLEN, (caddr_t)&l) < 0)
+if (ioctl(bd->fd, BIOCSBLEN, (caddr_t)&l) < 0)
+    {
+    errorStr = bd->iface + " BIOCSBLEN " + string(strerror(errno));
+    printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
+    return -1;
+    }
+
+//if (ioctl(cd[n].fd, BIOCSETIF, (caddr_t)&ifr) < 0 )
+if (ioctl(bd->fd, BIOCSETIF, (caddr_t)&ifr) < 0)
+    {
+    errorStr = bd->iface + " BIOCSETIF " + string(strerror(errno));
+    printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
+    return -1;
+    }
+
+//if (ioctl(cd[n].fd, BIOCIMMEDIATE, &im) < 0 )
+if (ioctl(bd->fd, BIOCIMMEDIATE, &im) < 0)
+    {
+    errorStr = bd->iface + " BIOCIMMEDIATE " + string(strerror(errno));
+    printfd(__FILE__, "ioctl failed: '%s'\n", errorStr.c_str());
+    return -1;
+    }
+
+return bd->fd;
+//return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapClose()
+{
+for (unsigned int i = 0; i < bpfData.size(); i++)
+  close(bpfData[i].fd);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapRead(char * buffer, int blen, char ** capIface)
+{
+poll(&polld[0], polld.size(), -1);
+
+for (unsigned int i = 0; i < polld.size(); i++)
+    {
+    if (polld[i].revents & POLLIN)
+        {
+        BPFCapRead(buffer, blen, capIface, &bpfData[i]);
+        polld[i].revents = 0;
+        return 0;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int BPF_CAP::BPFCapRead(char * buffer, int blen, char **, BPF_DATA * bd)
+{
+if (bd->canRead)
+    {
+    bd->r = read(bd->fd, bd->buffer, BUFF_LEN);
+    if (bd->r < 0)
+        {
+        //printfd(__FILE__, " error read\n");
+        usleep(20000);
+        }
+
+    bd->p = bd->buffer;
+    bd->bh = (struct bpf_hdr*)bd->p;
+    bd->canRead = 0;
+    }
+
+if(bd->r > bd->sum)
+    {
+    memcpy(buffer, (char*)(bd->p) + bd->bh->bh_hdrlen, blen);
+    //strncpy(iface, settings->iface[n], 9);
+    //*iface = settings->iface[n];
+
+    bd->sum += BPF_WORDALIGN(bd->bh->bh_hdrlen + bd->bh->bh_caplen);
+    bd->p = bd->p + BPF_WORDALIGN(bd->bh->bh_hdrlen + bd->bh->bh_caplen);
+    bd->bh = (struct bpf_hdr*)bd->p;
+    }
+
+if(bd->r <= bd->sum)
+    {
+    bd->canRead = 1;
+    bd->sum = 0;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/capture/ether_freebsd/ether_cap.h b/projects/stargazer/plugins/capture/ether_freebsd/ether_cap.h
new file mode 100644 (file)
index 0000000..6e651d3
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *    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
+ */
+
+ /*
+ $Revision: 1.11 $
+ $Date: 2009/06/23 11:32:27 $
+ $Author: faust $
+ */
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+
+#ifndef ETHER_CAP_H
+#define ETHER_CAP_H
+
+#include <string>
+#include <vector>
+#include <pthread.h>
+
+#ifdef FREE_BSD5
+#include <inttypes.h>
+#endif
+
+#ifdef FREE_BSD
+#include <sys/inttypes.h>
+#endif
+
+#include "base_plugin.h"
+#include "base_settings.h"
+#include "../../../traffcounter.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+#define BUFF_LEN    (128)
+
+//-----------------------------------------------------------------------------
+struct BPF_DATA
+{
+    BPF_DATA()
+        {
+        fd = 0;
+        p = NULL;
+        r = 0;
+        sum = 0;
+        memset(buffer, 0, BUFF_LEN);
+        bh = NULL;
+        canRead = 1;
+        iface = "";
+        //memset(&polld, 0, sizeof(pollfd));
+        };
+
+    BPF_DATA(const BPF_DATA & bd)
+        {
+        fd = bd.fd;
+        p = bd.p;
+        r = bd.r;
+        sum = bd.sum;
+        memcpy(buffer, bd.buffer, BUFF_LEN);
+        bh = bd.bh;
+        canRead = bd.canRead;
+        iface = bd.iface;
+        //memcpy(&polld, &bd.polld, sizeof(pollfd));
+        };
+
+int             fd;
+uint8_t *       p;
+int             r;
+int             sum;
+uint8_t         buffer[BUFF_LEN];
+struct bpf_hdr * bh;
+int             canRead;
+string          iface;
+//pollfd          polld;
+};
+//-----------------------------------------------------------------------------
+class BPF_CAP_SETTINGS
+{
+public:
+    virtual         ~BPF_CAP_SETTINGS(){};
+    const string&   GetStrError() const { return errorStr; }
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    string          GetIface(unsigned int num);
+
+private:
+    vector<string>  iface;
+    mutable string  errorStr;
+};
+//-----------------------------------------------------------------------------
+class BPF_CAP :public BASE_PLUGIN
+{
+public:
+                        BPF_CAP();
+    virtual             ~BPF_CAP(){};
+
+    void                SetUsers(USERS *){};
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER * tc);
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS *){};
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+private:
+    static void *       Run(void *);
+    int                 BPFCapOpen();
+    //int                 BPFCapOpen(int n);
+    int                 BPFCapOpen(BPF_DATA * bd);
+    int                 BPFCapClose();
+    int                 BPFCapRead(char * buffer, int blen, char ** iface);
+    int                 BPFCapRead(char * buffer, int blen, char ** iface, BPF_DATA * bd);
+
+    BPF_CAP_SETTINGS    capSettings;
+
+    mutable string      errorStr;
+
+    vector<BPF_DATA>    bpfData;
+    vector<pollfd>      polld;
+
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+    int                 capSock;
+    MODULE_SETTINGS     settings;
+
+    TRAFFCOUNTER *      traffCnt;
+};
+//-----------------------------------------------------------------------------
+
+#endif //ETHER_CAP_H
+
diff --git a/projects/stargazer/plugins/capture/ether_linux/Makefile b/projects/stargazer/plugins/capture/ether_linux/Makefile
new file mode 100644 (file)
index 0000000..f10886c
--- /dev/null
@@ -0,0 +1,15 @@
+###############################################################################
+# $Id: Makefile,v 1.9 2008/12/04 17:07:37 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_ether.so
+
+SRCS = ./ether_cap.cpp 
+
+LIBS += $(LIB_THREAD)
+STGLIBS = -lstg_common
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/ether_linux/ether_cap.cpp b/projects/stargazer/plugins/capture/ether_linux/ether_cap.cpp
new file mode 100644 (file)
index 0000000..5c76be9
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ *    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: 18.09.2002
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+
+/*
+$Revision: 1.23 $
+$Date: 2009/12/13 13:45:13 $
+*/
+
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <signal.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include "ether_cap.h"
+#include "common.h"
+#include "raw_ip_packet.h"
+
+//#define CAP_DEBUG 1
+
+
+//-----------------------------------------------------------------------------
+class ETHER_CAP_CREATOR
+{
+private:
+    ETHER_CAP * ec;
+
+public:
+    ETHER_CAP_CREATOR()
+        : ec(new ETHER_CAP())
+        {
+        };
+    ~ETHER_CAP_CREATOR()
+        {
+        delete ec;
+        };
+
+    ETHER_CAP * GetCapturer()
+        {
+        return ec;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+ETHER_CAP_CREATOR ecc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return ecc.GetCapturer();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------        
+const string ETHER_CAP::GetVersion() const
+{
+return "Ether_cap v.1.2";
+}
+//-----------------------------------------------------------------------------
+ETHER_CAP::ETHER_CAP()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void ETHER_CAP::SetTraffcounter(TRAFFCOUNTER * tc)
+{
+traffCnt = tc;
+}
+//-----------------------------------------------------------------------------
+const string & ETHER_CAP::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::Start()
+{
+if (isRunning)
+    return 0;
+
+if (EthCapOpen() < 0)
+    {
+    errorStr = "Cannot open socket!";
+    printfd(__FILE__, "Cannot open socket\n");
+    return -1;
+    }
+
+nonstop = true;
+
+if (pthread_create(&thread, NULL, Run, this) == 0)
+    {
+    return 0;
+    }
+
+errorStr = "Cannot create thread.";
+printfd(__FILE__, "Cannot create thread\n");
+return -1;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && isRunning; i++)
+    {
+    usleep(200000);
+    }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    if (pthread_kill(thread, SIGUSR1))
+        {
+        errorStr = "Cannot kill thread.";
+        return -1;
+        }
+    for (int i = 0; i < 25 && isRunning; ++i)
+        usleep(200000);
+    if (isRunning)
+        {
+        errorStr = "ETHER_CAP not stopped.";
+        printfd(__FILE__, "Cannot stop thread\n");
+        return -1;
+        }
+    else
+        {
+        pthread_join(thread, NULL);
+        }
+    }
+
+EthCapClose();
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool ETHER_CAP::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * ETHER_CAP::Run(void * d)
+{
+ETHER_CAP * dc = (ETHER_CAP *)d;
+dc->isRunning = true;
+
+struct ETH_IP
+{
+uint16_t    ethHdr[8];
+RAW_PACKET  rp;
+char        padding[4];
+char        padding1[8];
+};
+
+ETH_IP * ethIP;
+
+char ethip[sizeof(ETH_IP)];
+
+memset(&ethip, 0, sizeof(ETH_IP));
+
+ethIP = (ETH_IP *)&ethip;
+ethIP->rp.dataLen = -1;
+
+char * iface = NULL;
+
+while (dc->nonstop)
+    {
+    if (dc->EthCapRead(&ethip, 68 + 14, &iface))
+        {
+        continue;
+        }
+
+    if (ethIP->ethHdr[7] != 0x8)
+        continue;
+
+    dc->traffCnt->Process(ethIP->rp);
+    }
+
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t ETHER_CAP::GetStartPosition() const
+{
+return 10;
+}
+//-----------------------------------------------------------------------------
+uint16_t ETHER_CAP::GetStopPosition() const
+{
+return 10;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::EthCapOpen()
+{
+capSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+return capSock;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::EthCapClose()
+{
+close(capSock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int ETHER_CAP::EthCapRead(void * buffer, int blen, char **)
+{
+struct sockaddr_ll  addr;
+int addrLen, res;
+
+if (!WaitPackets(capSock))
+    {
+    return ENODATA;
+    }
+
+addrLen = sizeof(addr);
+
+res = recvfrom(capSock, ((char*)buffer) + 2, blen, 0, (struct sockaddr *)&addr, (socklen_t*)&addrLen);
+
+if (-1 == res)
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "Error on recvfrom: '%s'\n", strerror(errno));
+        }
+    return ENODATA;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool ETHER_CAP::WaitPackets(int sd) const
+{
+fd_set rfds;
+FD_ZERO(&rfds);
+FD_SET(sd, &rfds);
+
+struct timeval tv;
+tv.tv_sec = 0;
+tv.tv_usec = 500000;
+
+int res = select(sd + 1, &rfds, NULL, NULL, &tv);
+if (res == -1) // Error
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
+        }
+    return false;
+    }
+
+if (res == 0) // Timeout
+    {
+    return false;
+    }
+
+return true;
+}
diff --git a/projects/stargazer/plugins/capture/ether_linux/ether_cap.h b/projects/stargazer/plugins/capture/ether_linux/ether_cap.h
new file mode 100644 (file)
index 0000000..9643076
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *    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
+ */
+
+ /*
+ $Revision: 1.12 $
+ $Date: 2009/12/13 13:45:13 $
+ */
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+
+#ifndef ETHER_CAP_H
+#define ETHER_CAP_H
+
+#include <string>
+#include <pthread.h>
+
+#include "base_plugin.h"
+#include "base_settings.h"
+#include "../../../traffcounter.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+//-----------------------------------------------------------------------------
+class ETHER_CAP_SETTINGS
+{
+public:
+    const string& GetStrError() const { static string s; return s; }
+    int ParseSettings(const MODULE_SETTINGS &) { return 0; }
+};
+//-----------------------------------------------------------------------------
+class ETHER_CAP :public BASE_PLUGIN
+{
+public:
+    ETHER_CAP();
+    virtual ~ETHER_CAP(){};
+
+    void                SetUsers(USERS *){};
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER * tc);
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS *){};
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    void                SetSettings(const MODULE_SETTINGS &){};
+    int                 ParseSettings(){ return 0; };
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+private:
+    static void *       Run(void *);
+    int                 EthCapOpen();
+    int                 EthCapClose();
+    int                 EthCapRead(void * buffer, int blen, char ** iface);
+    bool                WaitPackets(int sd) const;
+
+    ETHER_CAP_SETTINGS  capSettings;
+
+    mutable string      errorStr;
+
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+    int                 capSock;
+
+    TRAFFCOUNTER *      traffCnt;
+};
+//-----------------------------------------------------------------------------
+
+#endif //ETHER_CAP_H
+
diff --git a/projects/stargazer/plugins/capture/ipq_linux/.#ipq_cap.cpp.1.3 b/projects/stargazer/plugins/capture/ipq_linux/.#ipq_cap.cpp.1.3
new file mode 100644 (file)
index 0000000..de2f39b
--- /dev/null
@@ -0,0 +1,190 @@
+#include <signal.h>
+#include <netinet/in.h>
+#include <linux/netfilter.h>
+
+#include "ipq_cap.h"
+#include "raw_ip_packet.h"
+#include "libipq.h"
+
+class IPQ_CAP_CREATOR
+{
+private:
+    IPQ_CAP * ic;
+
+public:
+    IPQ_CAP_CREATOR()
+        {
+        printf("constructor IPQ_CAP_CREATOR\n");
+        ic = new IPQ_CAP();
+        };
+    ~IPQ_CAP_CREATOR()
+        {
+        printf("destructor IPQ_CAP_CREATOR\n");
+        if (ic)
+            delete ic;
+        };
+
+    BASE_PLUGIN * GetCapturer()
+        {
+        return ic;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+IPQ_CAP_CREATOR icc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return icc.GetCapturer();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string IPQ_CAP::GetVersion() const
+{
+return "ipq_cap v.1.1";
+}
+//-----------------------------------------------------------------------------
+IPQ_CAP::IPQ_CAP()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void IPQ_CAP::SetTraffcounter(TRAFFCOUNTER * tc)
+{
+traffCnt = tc;
+}
+//-----------------------------------------------------------------------------
+const string & IPQ_CAP::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::Start()
+{
+if (isRunning)
+    return 0;
+printfd(__FILE__, "IPQ_CAP::Start()\n");
+if (IPQCapOpen() < 0)
+    {
+    errorStr = "Cannot open socket!";
+    return -1;
+    }
+nonstop = true;
+if (pthread_create(&thread, NULL, Run, this) == 0)
+    {
+    return 0;
+    }
+errorStr = "Cannot create thread.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+IPQCapClose();
+nonstop = false;
+//5 seconds to thread stops itself
+for (int i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+    usleep(200000);
+    }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        return -1;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool IPQ_CAP::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * IPQ_CAP::Run(void * d)
+{
+RAW_PACKET raw_packet;
+int status;
+
+sleep(2);
+IPQ_CAP * dc = (IPQ_CAP *)d;
+dc->isRunning = true;
+memset(&raw_packet, 0, sizeof(raw_packet));
+raw_packet.dataLen = -1;
+while (dc->nonstop)
+    {
+    status=dc->IPQCapRead(&raw_packet, 68);
+    if(status==-1||status==-2)
+        continue;
+    dc->traffCnt->Process(raw_packet);
+    }
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t IPQ_CAP::GetStartPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t IPQ_CAP::GetStopPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::IPQCapOpen()
+{
+int status;
+
+ipq_h = ipq_create_handle(0, PF_INET);
+if (ipq_h == NULL)
+    {
+    ipq_destroy_handle(ipq_h);
+    errorStr = "Cannot create ipq handle!";
+    return -1;
+    }
+status = ipq_set_mode(ipq_h, IPQ_COPY_PACKET, PAYLOAD_LEN);
+if (status < 0)
+    {
+    ipq_destroy_handle(ipq_h);
+    errorStr = "Cannot set IPQ_COPY_PACKET mode!";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::IPQCapClose()
+{
+ipq_destroy_handle(ipq_h);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::IPQCapRead(void * buffer, int blen)
+{
+int status;
+static ipq_packet_msg_t *m;
+
+memset(buf, 0, BUFSIZE);
+status = ipq_read(ipq_h, buf, BUFSIZE, 0);
+if (status < 0)
+    return -1;
+if (ipq_message_type(buf) != IPQM_PACKET)
+    return -2;
+m = ipq_get_packet(buf);
+memcpy(buffer, m->payload, blen);
+ipq_set_verdict(ipq_h, m->packet_id, NF_ACCEPT, 0, NULL);
+return 0;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/capture/ipq_linux/Makefile b/projects/stargazer/plugins/capture/ipq_linux/Makefile
new file mode 100644 (file)
index 0000000..7cf9299
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.6 2008/12/04 17:08:56 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_cap_ipq.so
+
+SRCS = ./ipq_cap.cpp \
+       ./libipq.c
+
+LIBS += $(LIB_THREAD)
+STGLIBS = -lstg_common
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/capture/ipq_linux/ipq_cap.cpp b/projects/stargazer/plugins/capture/ipq_linux/ipq_cap.cpp
new file mode 100644 (file)
index 0000000..9fc946c
--- /dev/null
@@ -0,0 +1,211 @@
+#include <signal.h>
+#include <cerrno>
+#include <netinet/in.h>
+#include <linux/netfilter.h>
+
+#include "ipq_cap.h"
+#include "raw_ip_packet.h"
+
+extern "C"
+    {
+    #include "libipq.h"
+    }
+
+class IPQ_CAP_CREATOR
+{
+private:
+    IPQ_CAP * ic;
+
+public:
+    IPQ_CAP_CREATOR()
+        : ic(new IPQ_CAP())
+        {
+        };
+    ~IPQ_CAP_CREATOR()
+        {
+        delete ic;
+        };
+
+    IPQ_CAP * GetCapturer()
+        {
+        return ic;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+IPQ_CAP_CREATOR icc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return icc.GetCapturer();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string IPQ_CAP::GetVersion() const
+{
+return "ipq_cap v.1.2";
+}
+//-----------------------------------------------------------------------------
+IPQ_CAP::IPQ_CAP()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void IPQ_CAP::SetTraffcounter(TRAFFCOUNTER * tc)
+{
+traffCnt = tc;
+}
+//-----------------------------------------------------------------------------
+const string & IPQ_CAP::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::Start()
+{
+if (isRunning)
+    return 0;
+if (IPQCapOpen() < 0)
+    {
+    errorStr = "Cannot open socket!";
+    printfd(__FILE__, "Cannot open socket\n");
+    return -1;
+    }
+nonstop = true;
+if (pthread_create(&thread, NULL, Run, this) == 0)
+    {
+    return 0;
+    }
+errorStr = "Cannot create thread.";
+printfd(__FILE__, "Cannot create thread\n");
+return -1;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::Stop()
+{
+if (!isRunning)
+    return 0;
+nonstop = false;
+//5 seconds to thread stops itself
+for (int i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+    usleep(200000);
+    }
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        return -1;
+        }
+    for (int i = 0; i < 25 && isRunning; ++i)
+        {
+        usleep(200000);
+        }
+    if (isRunning)
+        {
+        printfd(__FILE__, "Thread not stopped\n");
+        }
+    else
+        {
+        pthread_join(thread, NULL);
+        }
+    }
+IPQCapClose();
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool IPQ_CAP::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * IPQ_CAP::Run(void * d)
+{
+RAW_PACKET raw_packet;
+int status;
+
+IPQ_CAP * dc = (IPQ_CAP *)d;
+dc->isRunning = true;
+memset(&raw_packet, 0, sizeof(raw_packet));
+raw_packet.dataLen = -1;
+while (dc->nonstop)
+    {
+    status = dc->IPQCapRead(&raw_packet, 68);
+    if (status == -1 ||
+        status == -2 ||
+        status == -3 ||
+        status == -4)
+        continue;
+    dc->traffCnt->Process(raw_packet);
+    }
+dc->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t IPQ_CAP::GetStartPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t IPQ_CAP::GetStopPosition() const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::IPQCapOpen()
+{
+int status;
+
+ipq_h = ipq_create_handle(0, PF_INET);
+if (ipq_h == NULL)
+    {
+    ipq_destroy_handle(ipq_h);
+    errorStr = "Cannot create ipq handle!";
+    return -1;
+    }
+status = ipq_set_mode(ipq_h, IPQ_COPY_PACKET, PAYLOAD_LEN);
+if (status < 0)
+    {
+    ipq_destroy_handle(ipq_h);
+    errorStr = "Cannot set IPQ_COPY_PACKET mode!";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::IPQCapClose()
+{
+ipq_destroy_handle(ipq_h);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int IPQ_CAP::IPQCapRead(void * buffer, int blen)
+{
+int status;
+static ipq_packet_msg_t *m;
+
+memset(buf, 0, BUFSIZE);
+status = ipq_read(ipq_h, buf, BUFSIZE, 1);
+if (status == 0)
+    return -4;
+if (errno == EINTR)
+    return -3;
+if (status < 0)
+    return -1;
+if (ipq_message_type(buf) != IPQM_PACKET)
+    return -2;
+m = ipq_get_packet(buf);
+memcpy(buffer, m->payload, blen);
+ipq_set_verdict(ipq_h, m->packet_id, NF_ACCEPT, 0, NULL);
+return 0;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/capture/ipq_linux/ipq_cap.h b/projects/stargazer/plugins/capture/ipq_linux/ipq_cap.h
new file mode 100644 (file)
index 0000000..3b088ad
--- /dev/null
@@ -0,0 +1,56 @@
+#include <string>
+
+#include "base_plugin.h"
+#include "base_settings.h"
+#include "../../../traffcounter.h"
+
+#define BUFSIZE     (256)
+#define PAYLOAD_LEN (96)
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+//-----------------------------------------------------------------------------
+class IPQ_CAP :public BASE_PLUGIN
+{
+public:
+    IPQ_CAP();
+    virtual ~IPQ_CAP(){};
+
+    void SetUsers(USERS *){};
+    void SetTariffs(TARIFFS *){};
+    void SetAdmins(ADMINS *){};
+    void SetTraffcounter(TRAFFCOUNTER * tc);
+    void SetStore(BASE_STORE *){};
+    void SetStgSettings(const SETTINGS *){};
+
+    int Start();
+    int Stop();
+    int Reload() { return 0; };
+    bool IsRunning();
+
+    void  SetSettings(const MODULE_SETTINGS &){};
+    int  ParseSettings(){ return 0; };
+    const string & GetStrError() const;
+    const string GetVersion() const;
+    uint16_t GetStartPosition() const;
+    uint16_t GetStopPosition() const;
+
+private:
+    static void * Run(void *);
+    int IPQCapOpen();
+    int IPQCapClose();
+    int IPQCapRead(void * buffer, int blen);
+
+    struct ipq_handle *ipq_h;
+    mutable string errorStr;
+
+    pthread_t thread;
+    bool nonstop;
+    bool isRunning;
+    int capSock;
+
+    TRAFFCOUNTER * traffCnt;
+    unsigned char buf[BUFSIZE];
+};
diff --git a/projects/stargazer/plugins/capture/ipq_linux/libipq.c b/projects/stargazer/plugins/capture/ipq_linux/libipq.c
new file mode 100644 (file)
index 0000000..798faeb
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * libipq.c
+ *
+ * IPQ userspace library.
+ *
+ * Please note that this library is still developmental, and there may
+ * be some API changes.
+ *
+ * Author: James Morris <jmorris@intercode.com.au>
+ *
+ * 07-11-2001 Modified by Fernando Anton to add support for IPv6.
+ *
+ * Copyright (c) 2000-2001 Netfilter Core Team
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "libipq.h"
+
+/****************************************************************************
+ *
+ * Private interface
+ *
+ ****************************************************************************/
+
+enum
+    {
+    IPQ_ERR_NONE = 0,
+    IPQ_ERR_IMPL,
+    IPQ_ERR_HANDLE,
+    IPQ_ERR_SOCKET,
+    IPQ_ERR_BIND,
+    IPQ_ERR_BUFFER,
+    IPQ_ERR_RECV,
+    IPQ_ERR_NLEOF,
+    IPQ_ERR_ADDRLEN,
+    IPQ_ERR_STRUNC,
+    IPQ_ERR_RTRUNC,
+    IPQ_ERR_NLRECV,
+    IPQ_ERR_SEND,
+    IPQ_ERR_SUPP,
+    IPQ_ERR_RECVBUF,
+    IPQ_ERR_TIMEOUT,
+    IPQ_ERR_PROTOCOL
+    };
+#define IPQ_MAXERR IPQ_ERR_PROTOCOL
+
+/*struct ipq_errmap_t
+    {
+    int errcode;
+    char *message;
+    } ipq_errmap[] = {
+    { IPQ_ERR_NONE, "Unknown error"},
+    { IPQ_ERR_IMPL, "Implementation error"},
+    { IPQ_ERR_HANDLE, "Unable to create netlink handle"},
+    { IPQ_ERR_SOCKET, "Unable to create netlink socket"},
+    { IPQ_ERR_BIND, "Unable to bind netlink socket"},
+    { IPQ_ERR_BUFFER, "Unable to allocate buffer"},
+    { IPQ_ERR_RECV, "Failed to receive netlink message"},
+    { IPQ_ERR_NLEOF, "Received EOF on netlink socket"},
+    { IPQ_ERR_ADDRLEN, "Invalid peer address length"},
+    { IPQ_ERR_STRUNC, "Sent message truncated"},
+    { IPQ_ERR_RTRUNC, "Received message truncated"},
+    { IPQ_ERR_NLRECV, "Received error from netlink"},
+    { IPQ_ERR_SEND, "Failed to send netlink message"},
+    { IPQ_ERR_SUPP, "Operation not supported"},
+    { IPQ_ERR_RECVBUF, "Receive buffer size invalid"},
+    { IPQ_ERR_TIMEOUT, "Timeout"},
+    { IPQ_ERR_PROTOCOL, "Invalid protocol specified"}
+};*/
+
+static int ipq_errno = IPQ_ERR_NONE;
+
+static ssize_t ipq_netlink_sendto(const struct ipq_handle *h, 
+                                  const void *msg, size_t len);
+
+static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
+                                    unsigned char *buf, size_t len,
+                                    int timeout);
+
+static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h,
+                                   const struct msghdr *msg,
+                                   unsigned int flags);
+
+//static char *ipq_strerror(int errcode);
+//-----------------------------------------------------------------------------
+static ssize_t ipq_netlink_sendto(const struct ipq_handle *h,
+                                  const void *msg, size_t len)
+{
+    int status = sendto(h->fd, msg, len, 0,
+                        (struct sockaddr *)&h->peer, sizeof(h->peer));
+    if (status < 0)
+        ipq_errno = IPQ_ERR_SEND;
+    return status;
+}
+//-----------------------------------------------------------------------------
+static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h,
+                                   const struct msghdr *msg,
+                                   unsigned int flags)
+{
+    int status = sendmsg(h->fd, msg, flags);
+    if (status < 0)
+        ipq_errno = IPQ_ERR_SEND;
+    return status;
+}
+//-----------------------------------------------------------------------------
+static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
+                                    unsigned char *buf, size_t len,
+                                    int timeout)
+{
+    socklen_t addrlen;
+    int status;
+    struct nlmsghdr *nlh;
+
+    if (len < sizeof(struct nlmsgerr))
+        {
+        ipq_errno = IPQ_ERR_RECVBUF;
+        return -1;
+        }
+    addrlen = sizeof(h->peer);
+
+    if (timeout != 0)
+        {
+        int ret;
+        struct timeval tv;
+        fd_set read_fds;
+
+        if (timeout < 0)
+            {
+            /* non-block non-timeout */
+            tv.tv_sec = 0;
+            tv.tv_usec = 0;
+            }
+        else
+            {
+            tv.tv_sec = timeout / 1000000;
+            tv.tv_usec = timeout % 1000000;
+            }
+
+        FD_ZERO(&read_fds);
+        FD_SET(h->fd, &read_fds);
+        ret = select(h->fd+1, &read_fds, NULL, NULL, &tv);
+        if (ret < 0)
+            {
+            if (errno == EINTR)
+                {
+                return 0;
+                }
+            else
+                {
+                ipq_errno = IPQ_ERR_RECV;
+                return -1;
+                }
+            }
+        if (!FD_ISSET(h->fd, &read_fds))
+            {
+            ipq_errno = IPQ_ERR_TIMEOUT;
+            return 0;
+            }
+        }
+    status = recvfrom(h->fd, buf, len, 0,
+                      (struct sockaddr *)&h->peer, &addrlen);
+    if (status < 0)
+        {
+        ipq_errno = IPQ_ERR_RECV;
+        return status;
+        }
+    if (addrlen != sizeof(h->peer))
+        {
+        ipq_errno = IPQ_ERR_RECV;
+        return -1;
+        }
+    if (h->peer.nl_pid != 0)
+        {
+        ipq_errno = IPQ_ERR_RECV;
+        return -1;
+        }
+    if (status == 0)
+        {
+        ipq_errno = IPQ_ERR_NLEOF;
+        return -1;
+        }
+    nlh = (struct nlmsghdr *)buf;
+    if (nlh->nlmsg_flags & MSG_TRUNC || (int)nlh->nlmsg_len > status)
+        {
+        ipq_errno = IPQ_ERR_RTRUNC;
+        return -1;
+        }
+    return status;
+}
+//-----------------------------------------------------------------------------
+/*static char *ipq_strerror(int errcode)
+{
+    if (errcode < 0 || errcode > IPQ_MAXERR)
+        errcode = IPQ_ERR_IMPL;
+    return ipq_errmap[errcode].message;
+}*/
+
+/****************************************************************************
+ *
+ * Public interface
+ *
+ ****************************************************************************/
+
+/*
+ * Create and initialise an ipq handle.
+ */
+struct ipq_handle *ipq_create_handle(u_int32_t __attribute__((unused)) flags, u_int32_t protocol)
+    {
+    int status;
+    struct ipq_handle *h;
+
+    h = (struct ipq_handle *)malloc(sizeof(struct ipq_handle));
+    if (h == NULL)
+        {
+        ipq_errno = IPQ_ERR_HANDLE;
+        return NULL;
+        }
+
+    memset(h, 0, sizeof(struct ipq_handle));
+
+    if (protocol == PF_INET)
+        h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
+    else if (protocol == PF_INET6)
+        h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP6_FW);
+    else
+        {
+        ipq_errno = IPQ_ERR_PROTOCOL;
+        free(h);
+        return NULL;
+        }
+
+    if (h->fd == -1)
+        {
+        ipq_errno = IPQ_ERR_SOCKET;
+        close(h->fd);
+        free(h);
+        return NULL;
+        }
+    memset(&h->local, 0, sizeof(struct sockaddr_nl));
+    h->local.nl_family = AF_NETLINK;
+    h->local.nl_pid = getpid();
+    h->local.nl_groups = 0;
+    status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
+    if (status == -1)
+        {
+        ipq_errno = IPQ_ERR_BIND;
+        close(h->fd);
+        free(h);
+        return NULL;
+        }
+    memset(&h->peer, 0, sizeof(struct sockaddr_nl));
+    h->peer.nl_family = AF_NETLINK;
+    h->peer.nl_pid = 0;
+    h->peer.nl_groups = 0;
+    return h;
+    }
+//-----------------------------------------------------------------------------
+/*
+ * No error condition is checked here at this stage, but it may happen
+ * if/when reliable messaging is implemented.
+ */
+int ipq_destroy_handle(struct ipq_handle *h)
+{
+    if (h)
+        {
+        close(h->fd);
+        free(h);
+        }
+    return 0;
+}
+//-----------------------------------------------------------------------------
+int ipq_set_mode(const struct ipq_handle *h,
+                 u_int8_t mode, size_t range)
+{
+    #define FAKE_ARRAY_SIZE 16
+    struct
+        {
+        struct nlmsghdr nlh;
+        ipq_peer_msg_t pm;
+        char s[FAKE_ARRAY_SIZE];
+        } req;
+    
+    memset(&req, 0, sizeof(req));
+    req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req)-FAKE_ARRAY_SIZE);
+    req.nlh.nlmsg_flags = NLM_F_REQUEST;
+    req.nlh.nlmsg_type = IPQM_MODE;
+    req.nlh.nlmsg_pid = h->local.nl_pid;
+    req.pm.msg.mode.value = mode;
+    req.pm.msg.mode.range = range;
+    return ipq_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
+    //return ipq_netlink_sendto(h, (void *)&req, sizeof(req));
+}
+//-----------------------------------------------------------------------------
+/*
+ * timeout is in microseconds (1 second is 1000000 (1 million) microseconds)
+ *
+ */
+ssize_t ipq_read(const struct ipq_handle *h,
+                 unsigned char *buf, size_t len, int timeout)
+{
+    return ipq_netlink_recvfrom(h, buf, len, timeout);
+}
+//-----------------------------------------------------------------------------
+int ipq_message_type(const unsigned char *buf)
+{
+    return((struct nlmsghdr*)buf)->nlmsg_type;
+}
+//-----------------------------------------------------------------------------
+int ipq_get_msgerr(const unsigned char *buf)
+{
+    struct nlmsghdr *h = (struct nlmsghdr *)buf;
+    struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+    return -err->error;
+}
+//-----------------------------------------------------------------------------
+ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf)
+{
+    return(ipq_packet_msg_t *)(NLMSG_DATA((struct nlmsghdr *)(buf)));
+}
+//-----------------------------------------------------------------------------
+int ipq_set_verdict(const struct ipq_handle *h,
+                    ipq_id_t id,
+                    unsigned int verdict,
+                    size_t data_len,
+                    unsigned char *buf)
+{
+    unsigned char nvecs;
+    size_t tlen;
+    struct nlmsghdr nlh;
+    ipq_peer_msg_t pm;
+    struct iovec iov[3];
+    struct msghdr msg;
+
+    memset(&nlh, 0, sizeof(nlh));
+    nlh.nlmsg_flags = NLM_F_REQUEST;
+    nlh.nlmsg_type = IPQM_VERDICT;
+    nlh.nlmsg_pid = h->local.nl_pid;
+    memset(&pm, 0, sizeof(pm));
+    pm.msg.verdict.value = verdict;
+    pm.msg.verdict.id = id;
+    pm.msg.verdict.data_len = data_len;
+    iov[0].iov_base = &nlh;
+    iov[0].iov_len = sizeof(nlh);
+    iov[1].iov_base = &pm;
+    iov[1].iov_len = sizeof(pm);
+    tlen = sizeof(nlh) + sizeof(pm);
+    nvecs = 2;
+    if (data_len && buf)
+        {
+        iov[2].iov_base = buf;
+        iov[2].iov_len = data_len;
+        tlen += data_len;
+        nvecs++;
+        }
+    msg.msg_name = (void *)&h->peer;
+    msg.msg_namelen = sizeof(h->peer);
+    msg.msg_iov = iov;
+    msg.msg_iovlen = nvecs;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_flags = 0;
+    nlh.nlmsg_len = tlen;
+    return ipq_netlink_sendmsg(h, &msg, 0);
+}
+//-----------------------------------------------------------------------------
+/* Not implemented yet */
+int ipq_ctl(const struct ipq_handle __attribute__((unused)) * handle, int __attribute__((unused)) request, ...)
+{
+    return 1;
+}
+//-----------------------------------------------------------------------------
+/*char *ipq_errstr(void)
+{
+    return ipq_strerror(ipq_errno);
+}*/
+//-----------------------------------------------------------------------------
+/*void ipq_perror(const char *s)
+{
+    if (s)
+        fputs(s, stderr);
+    else
+        fputs("ERROR", stderr);
+    if (ipq_errno)
+        fprintf(stderr, ": %s", ipq_errstr());
+    if (errno)
+        fprintf(stderr, ": %s", strerror(errno));
+    fputc('\n', stderr);
+}*/
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/plugins/capture/ipq_linux/libipq.h b/projects/stargazer/plugins/capture/ipq_linux/libipq.h
new file mode 100644 (file)
index 0000000..41cca57
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * libipq.h
+ *
+ * IPQ library for userspace.
+ *
+ * Author: James Morris <jmorris@intercode.com.au>
+ *
+ * Copyright (c) 2000-2001 Netfilter Core Team
+ *
+ * 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.
+ *
+ */
+#ifndef _LIBIPQ_H
+#define _LIBIPQ_H
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+
+#ifdef KERNEL_64_USERSPACE_32
+#include "ip_queue_64.h"
+typedef u_int64_t ipq_id_t;
+#else
+#include <linux/netfilter_ipv4/ip_queue.h>
+typedef unsigned long ipq_id_t;
+#endif
+
+#ifdef DEBUG_LIBIPQ
+#include <stdio.h>
+#define LDEBUG(x...) fprintf(stderr, ## x)
+#else
+#define LDEBUG(x...)
+#endif /* DEBUG_LIBIPQ */
+
+/* FIXME: glibc sucks */
+#ifndef MSG_TRUNC
+#define MSG_TRUNC 0x20
+#endif
+
+struct ipq_handle
+{
+       int fd;
+       u_int8_t blocking;
+       struct sockaddr_nl local;
+       struct sockaddr_nl peer;
+};
+
+struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol);
+
+int ipq_destroy_handle(struct ipq_handle *h);
+
+ssize_t ipq_read(const struct ipq_handle *h,
+                unsigned char *buf, size_t len, int timeout);
+
+int ipq_set_mode(const struct ipq_handle *h, u_int8_t mode, size_t len);
+
+ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf);
+
+int ipq_message_type(const unsigned char *buf);
+
+int ipq_get_msgerr(const unsigned char *buf);
+
+int ipq_set_verdict(const struct ipq_handle *h,
+                    ipq_id_t id,
+                    unsigned int verdict,
+                    size_t data_len,
+                    unsigned char *buf);
+
+int ipq_ctl(const struct ipq_handle *h, int request, ...);
+
+/*char *ipq_errstr(void);
+void ipq_perror(const char *s);*/
+
+#endif /* _LIBIPQ_H */
+
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/Makefile b/projects/stargazer/plugins/configuration/rpcconfig/Makefile
new file mode 100644 (file)
index 0000000..c2fb03d
--- /dev/null
@@ -0,0 +1,30 @@
+###############################################################################
+# $Id: Makefile,v 1.10 2009/08/03 10:25:40 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_conf_rpc.so
+
+SRCS = ./rpcconfig.cpp \
+       ./user_helper.cpp \
+       ./tariff_helper.cpp \
+       ./info_methods.cpp \
+       ./users_methods.cpp \
+       ./tariffs_methods.cpp \
+       ./admins_methods.cpp \
+       ./messages_methods.cpp
+
+XMLRPC_C_LIBS = $(shell xmlrpc-c-config c++2 abyss-server --libs)
+
+LIBS += $(XMLRPC_C_LIBS) \
+       $(LIB_THREAD)
+
+ifneq ($(OS),linux)
+LIBS += -liconv
+endif
+
+STGLIBS = -lstg_common -lstg_logger
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/admins_methods.cpp b/projects/stargazer/plugins/configuration/rpcconfig/admins_methods.cpp
new file mode 100644 (file)
index 0000000..4eae81f
--- /dev/null
@@ -0,0 +1,256 @@
+#include "admins_methods.h"
+
+#include "rpcconfig.h"
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_GET::execute(xmlrpc_c::paramList const & paramList,
+                               xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(login, &admin))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+structVal["result"] = xmlrpc_c::value_boolean(true);
+structVal["login"] = xmlrpc_c::value_string(admin.GetLogin());
+structVal["password"] = xmlrpc_c::value_string(admin.GetPassword());
+
+const PRIV * priv = admin.GetPriv();
+
+structVal["user_stat"] = xmlrpc_c::value_boolean(priv->userStat);
+structVal["user_conf"] = xmlrpc_c::value_boolean(priv->userConf);
+structVal["user_cash"] = xmlrpc_c::value_boolean(priv->userCash);
+structVal["user_passwd"] = xmlrpc_c::value_boolean(priv->userPasswd);
+structVal["user_add_del"] = xmlrpc_c::value_boolean(priv->userAddDel);
+structVal["admin_chg"] = xmlrpc_c::value_boolean(priv->adminChg);
+structVal["tariff_chg"] = xmlrpc_c::value_boolean(priv->tariffChg);
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_ADD::execute(xmlrpc_c::paramList const & paramList,
+                               xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Not logged or cookie timeout'\n");
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Invalid admin (logged)'\n");
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (admins->Add(login, admin))
+    {
+    printfd(__FILE__, "METHOD_ADMIN_ADD::execute(): 'Failed to add admin'\n");
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_DEL::execute(xmlrpc_c::paramList const & paramList,
+                               xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (admins->Del(login, admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMIN_CHG::execute(xmlrpc_c::paramList const & paramList,
+                               xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+xmlrpc_c::value_struct info(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN loggedAdmin;
+
+if (admins->FindAdmin(adminInfo.admin, &loggedAdmin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(login, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN_CONF conf;
+
+conf.priv = *admin.GetPriv();
+conf.password = admin.GetPassword();
+conf.login = login;
+
+std::map<std::string, xmlrpc_c::value> structVal(
+    static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
+    );
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = structVal.find("password")) != structVal.end())
+    {
+    conf.password = xmlrpc_c::value_string(it->second);
+    }
+
+if ((it = structVal.find("user_stat")) != structVal.end())
+    {
+    conf.priv.userStat = xmlrpc_c::value_boolean(it->second);
+    }
+
+if ((it = structVal.find("user_conf")) != structVal.end())
+    {
+    conf.priv.userConf = xmlrpc_c::value_boolean(it->second);
+    }
+
+if ((it = structVal.find("user_cash")) != structVal.end())
+    {
+    conf.priv.userCash = xmlrpc_c::value_boolean(it->second);
+    }
+
+if ((it = structVal.find("user_passwd")) != structVal.end())
+    {
+    conf.priv.userPasswd = xmlrpc_c::value_boolean(it->second);
+    }
+
+if ((it = structVal.find("user_add_del")) != structVal.end())
+    {
+    conf.priv.userAddDel = xmlrpc_c::value_boolean(it->second);
+    }
+
+if ((it = structVal.find("admin_chg")) != structVal.end())
+    {
+    conf.priv.adminChg = xmlrpc_c::value_boolean(it->second);
+    }
+
+if ((it = structVal.find("tariff_chg")) != structVal.end())
+    {
+    conf.priv.tariffChg = xmlrpc_c::value_boolean(it->second);
+    }
+
+if (admins->Change(conf, loggedAdmin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_ADMINS_GET::execute(xmlrpc_c::paramList const & paramList,
+                                xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+std::vector<xmlrpc_c::value> retval;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+ADMIN_CONF ac;
+int h = admins->OpenSearch();
+
+while (admins->SearchNext(h, &ac) == 0)
+    {
+    std::map<std::string, xmlrpc_c::value> structVal;
+    structVal["result"] = xmlrpc_c::value_boolean(true);
+    structVal["login"] = xmlrpc_c::value_string(ac.login);
+    structVal["password"] = xmlrpc_c::value_string(ac.password);
+    structVal["user_stat"] = xmlrpc_c::value_boolean(ac.priv.userStat);
+    structVal["user_conf"] = xmlrpc_c::value_boolean(ac.priv.userConf);
+    structVal["user_cash"] = xmlrpc_c::value_boolean(ac.priv.userCash);
+    structVal["user_passwd"] = xmlrpc_c::value_boolean(ac.priv.userPasswd);
+    structVal["user_add_del"] = xmlrpc_c::value_boolean(ac.priv.userAddDel);
+    structVal["admin_chg"] = xmlrpc_c::value_boolean(ac.priv.adminChg);
+    structVal["tariff_chg"] = xmlrpc_c::value_boolean(ac.priv.tariffChg);
+
+    retval.push_back(xmlrpc_c::value_struct(structVal));
+    }
+
+*retvalPtr = xmlrpc_c::value_array(retval);
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/admins_methods.h b/projects/stargazer/plugins/configuration/rpcconfig/admins_methods.h
new file mode 100644 (file)
index 0000000..7c5ceb1
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __ADMINS_METHODS_H__
+#define __ADMINS_METHODS_H__
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+#include "../../../admins.h"
+#include "../../../admin.h"
+
+class RPC_CONFIG;
+
+class METHOD_ADMIN_GET : public xmlrpc_c::method {
+public:
+    METHOD_ADMIN_GET(RPC_CONFIG * c,
+                     ADMINS * a)
+        : config(c),
+          admins(a)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value * const retvalPtr);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+};
+
+class METHOD_ADMIN_ADD : public xmlrpc_c::method {
+public:
+    METHOD_ADMIN_ADD(RPC_CONFIG * c,
+                     ADMINS * a)
+        : config(c),
+          admins(a)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value * const retvalPtr);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+};
+
+class METHOD_ADMIN_DEL : public xmlrpc_c::method {
+public:
+    METHOD_ADMIN_DEL(RPC_CONFIG * c,
+                     ADMINS * a)
+        : config(c),
+          admins(a)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value * const retvalPtr);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+};
+
+class METHOD_ADMIN_CHG : public xmlrpc_c::method {
+public:
+    METHOD_ADMIN_CHG(RPC_CONFIG * c,
+                     ADMINS * a)
+        : config(c),
+          admins(a)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value * const retvalPtr);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+};
+
+class METHOD_ADMINS_GET : public xmlrpc_c::method {
+public:
+    METHOD_ADMINS_GET(RPC_CONFIG * c,
+                      ADMINS * a)
+        : config(c),
+          admins(a)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value * const retvalPtr);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/deps b/projects/stargazer/plugins/configuration/rpcconfig/deps
new file mode 100644 (file)
index 0000000..65b198a
--- /dev/null
@@ -0,0 +1,362 @@
+rpcconfig.o: rpcconfig.cpp rpcconfig.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ ../../../admins.h ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../users.h ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ ../../../user.h ../../../tariff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h ../../../tariffs.h ../../../traffcounter.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/raw_ip_packet.h \
+ ../../../users.h ../../../settings.h info_methods.h users_methods.h \
+ ../../../user.h tariffs_methods.h admins_methods.h messages_methods.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+user_helper.o: user_helper.cpp user_helper.h ../../../users.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../user.h ../../../tariff.h ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h ../../../admin.h utils.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+tariff_helper.o: tariff_helper.cpp tariff_helper.h ../../../tariff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+info_methods.o: info_methods.cpp info_methods.h ../../../users.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../user.h ../../../tariff.h ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h ../../../tariffs.h ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/version.h \
+ rpcconfig.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ ../../../admin.h ../../../admins.h ../../../traffcounter.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/raw_ip_packet.h \
+ ../../../users.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+users_methods.o: users_methods.cpp users_methods.h ../../../users.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../user.h ../../../tariff.h ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h ../../../user.h rpcconfig.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ ../../../admin.h ../../../admins.h ../../../tariffs.h \
+ ../../../traffcounter.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/raw_ip_packet.h \
+ ../../../users.h ../../../settings.h user_helper.h utils.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+tariffs_methods.o: tariffs_methods.cpp rpcconfig.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ ../../../admins.h ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../users.h ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ ../../../user.h ../../../tariff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h ../../../tariffs.h ../../../traffcounter.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/raw_ip_packet.h \
+ ../../../users.h ../../../settings.h tariffs_methods.h tariff_helper.h \
+ ../../../tariff.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+admins_methods.o: admins_methods.cpp admins_methods.h ../../../admins.h \
+ ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../admin.h rpcconfig.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ ../../../users.h ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ ../../../user.h ../../../tariff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h ../../../tariffs.h ../../../traffcounter.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/raw_ip_packet.h \
+ ../../../users.h ../../../settings.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
+messages_methods.o: messages_methods.cpp messages_methods.h \
+ ../../../users.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ../../../settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/dotconfpp.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/mempool.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_logger.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../user.h ../../../tariff.h ../../../admin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.inc.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ ../../../curr_ip.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ ../../../user_property.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/notifer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ ../../../script_executer.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_auth.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ ../../../tariffs.h ../../../actions.h ../../../actions.inl.h \
+ ../../../eventloop.h rpcconfig.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/base_plugin.h \
+ ../../../admin.h ../../../admins.h ../../../tariffs.h \
+ ../../../traffcounter.h \
+ /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include/raw_ip_packet.h \
+ ../../../users.h ../../../settings.h utils.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /home/faust/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/info_methods.cpp b/projects/stargazer/plugins/configuration/rpcconfig/info_methods.cpp
new file mode 100644 (file)
index 0000000..fdb5604
--- /dev/null
@@ -0,0 +1,89 @@
+#include "info_methods.h"
+
+#include <sys/utsname.h>
+#include "version.h"
+#include "rpcconfig.h"
+
+void METHOD_INFO::execute(xmlrpc_c::paramList const & paramList,
+                          xmlrpc_c::value *   const   retvalPtr)
+{
+paramList.verifyEnd(0);
+std::map<std::string, xmlrpc_c::value> structVal;
+
+std::string un;
+struct utsname utsn;
+
+uname(&utsn);
+un[0] = 0;
+
+un += utsn.sysname;
+un += " ";
+un += utsn.release;
+un += " ";
+un += utsn.machine;
+un += " ";
+un += utsn.nodename;
+
+structVal["version"] = xmlrpc_c::value_string(SERVER_VERSION);
+structVal["tariff_num"] = xmlrpc_c::value_int(tariffs->GetTariffsNum());
+structVal["tariff"] = xmlrpc_c::value_int(2);
+structVal["users_num"] = xmlrpc_c::value_int(users->GetUserNum());
+structVal["uname"] = xmlrpc_c::value_string(un);
+structVal["dir_num"] = xmlrpc_c::value_int(DIR_NUM);
+structVal["day_fee"] = xmlrpc_c::value_int(settings->GetDayFee());
+
+std::vector<xmlrpc_c::value> dirnameVal;
+
+for (int i = 0; i< DIR_NUM; i++)
+    {
+    string dn2e;
+    Encode12str(dn2e, settings->GetDirName(i));
+    dirnameVal.push_back(xmlrpc_c::value_string(dn2e));
+    }
+
+structVal["dir_names"] = xmlrpc_c::value_array(dirnameVal);
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+void METHOD_LOGIN::execute(xmlrpc_c::paramList const & paramList,
+                           xmlrpc_c::value *   const   retvalPtr)
+{
+std::string login = paramList.getString(0);
+std::string password = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+
+std::string cookie;
+if (config->CheckAdmin(login, password, &cookie))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    structVal["cookie"] = xmlrpc_c::value_string("");
+    }
+else
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(true);
+    structVal["cookie"] = xmlrpc_c::value_string(cookie);
+    }
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+void METHOD_LOGOUT::execute(xmlrpc_c::paramList const & paramList,
+                            xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+
+if (config->LogoutAdmin(cookie))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    }
+else
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(true);
+    }
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/info_methods.h b/projects/stargazer/plugins/configuration/rpcconfig/info_methods.h
new file mode 100644 (file)
index 0000000..37bbb40
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __INFO_METHODS_H__
+#define __INFO_METHODS_H__
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+#include "../../../users.h"
+#include "../../../tariffs.h"
+#include "../../../settings.h"
+
+// Forward declaration
+class RPC_CONFIG;
+
+class METHOD_INFO : public xmlrpc_c::method
+{
+public:
+    METHOD_INFO(TARIFFS * t,
+                USERS * u,
+                const SETTINGS * s)
+        : tariffs(t),
+          users(u),
+          settings(s)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    TARIFFS * tariffs;
+    USERS * users;
+    const SETTINGS * settings;
+};
+
+class METHOD_LOGIN : public xmlrpc_c::method
+{
+public:
+    METHOD_LOGIN(RPC_CONFIG * c)
+        : config(c)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+};
+
+class METHOD_LOGOUT : public xmlrpc_c::method
+{
+public:
+    METHOD_LOGOUT(RPC_CONFIG * c)
+        : config(c)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/messages_methods.cpp b/projects/stargazer/plugins/configuration/rpcconfig/messages_methods.cpp
new file mode 100644 (file)
index 0000000..281041e
--- /dev/null
@@ -0,0 +1,93 @@
+#include "messages_methods.h"
+
+#include "rpcconfig.h"
+#include "stg_message.h"
+#include "utils.h"
+
+//------------------------------------------------------------------------------
+
+void METHOD_MESSAGE_SEND::execute(xmlrpc_c::paramList const & paramList,
+                                  xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::vector<xmlrpc_c::value> logins(paramList.getArray(1));
+std::map<std::string, xmlrpc_c::value> msgInfo(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+STG_MSG message;
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = msgInfo.find("version")) == msgInfo.end())
+    {
+    message.header.ver = 1; // Default value
+    }
+else
+    {
+    message.header.ver = xmlrpc_c::value_int(it->second);
+    }
+
+if ((it = msgInfo.find("type")) == msgInfo.end())
+    {
+    message.header.type = 1; // default value
+    }
+else
+    {
+    message.header.type = xmlrpc_c::value_int(it->second);
+    }
+
+if ((it = msgInfo.find("repeat")) == msgInfo.end())
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+message.header.repeat = xmlrpc_c::value_int(it->second);
+
+if ((it = msgInfo.find("repeat_period")) == msgInfo.end())
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+message.header.repeatPeriod = xmlrpc_c::value_int(it->second);
+
+if ((it = msgInfo.find("show_time")) == msgInfo.end())
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+message.header.showTime = xmlrpc_c::value_int(it->second);
+
+if ((it = msgInfo.find("text")) == msgInfo.end())
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+message.text = IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "CP1251");
+
+message.header.creationTime = stgTime;
+message.header.lastSendTime = 0;
+
+std::vector<xmlrpc_c::value>::iterator lit;
+for (lit = logins.begin(); lit != logins.end(); ++lit)
+    {
+    user_iter ui;
+    if (users->FindByName(xmlrpc_c::value_string(*lit), &ui))
+        {
+        printfd(__FILE__, "METHOD_MESSAGE_SEND::execute(): 'User '%s' not found'\n", std::string(xmlrpc_c::value_string(*lit)).c_str());
+        }
+    else
+        {
+        ui->AddMessage(&message);
+        }
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/messages_methods.h b/projects/stargazer/plugins/configuration/rpcconfig/messages_methods.h
new file mode 100644 (file)
index 0000000..c82ad13
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __MESSAGES_METHODS_H__
+#define __MESSAGES_METHODS_H__
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+#include "../../../users.h"
+
+class RPC_CONFIG;
+
+class METHOD_MESSAGE_SEND : public xmlrpc_c::method {
+public:
+    METHOD_MESSAGE_SEND(RPC_CONFIG * c,
+                     USERS * u)
+        : config(c),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value * const retvalPtr);
+private:
+    RPC_CONFIG * config;
+    USERS * users;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.cpp b/projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.cpp
new file mode 100644 (file)
index 0000000..c059ba6
--- /dev/null
@@ -0,0 +1,420 @@
+#include "rpcconfig.h"
+
+#include <cstdlib>
+#include <csignal>
+#include "info_methods.h"
+#include "users_methods.h"
+#include "tariffs_methods.h"
+#include "admins_methods.h"
+#include "messages_methods.h"
+
+class RPC_CONFIG_CREATOR
+{
+private:
+    RPC_CONFIG * rpcconfig;
+
+public:
+    RPC_CONFIG_CREATOR()
+        : rpcconfig(new RPC_CONFIG())
+        {
+        };
+    ~RPC_CONFIG_CREATOR()
+        {
+        delete rpcconfig;
+        };
+
+    RPC_CONFIG * GetPlugin()
+        {
+        return rpcconfig;
+        };
+};
+
+RPC_CONFIG_CREATOR rpcc;
+
+RPC_CONFIG_SETTINGS::RPC_CONFIG_SETTINGS()
+    : errorStr(),
+      port(0),
+      cookieTimeout(0)
+{
+}
+
+int RPC_CONFIG_SETTINGS::ParseIntInRange(const string & str,
+                                         int min,
+                                         int max,
+                                         int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+
+int RPC_CONFIG_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    printfd(__FILE__, "Parameter 'Port' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+    return -1;
+    }
+port = p;
+
+pv.param = "CookieTimeout";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    cookieTimeout = 1800; // 30 * 60
+    }
+else
+    {
+    if (str2x(pvi->value[0], cookieTimeout))
+        {
+        errorStr = "Incorrect value of CookieTimeout: \'" + pvi->value[0] + "\'";
+        printfd(__FILE__, "Incorrect value of 'CookieTimeout'\n");
+        return -1;
+        }
+    }
+
+return 0;
+}
+
+BASE_PLUGIN * GetPlugin()
+{
+return rpcc.GetPlugin();
+}
+
+RPC_CONFIG::RPC_CONFIG()
+    : rpcServer(NULL)
+{
+
+}
+
+RPC_CONFIG::~RPC_CONFIG()
+{
+// delete server
+delete rpcServer;
+}
+
+int RPC_CONFIG::ParseSettings()
+{
+int ret = rpcConfigSettings.ParseSettings(settings);
+
+if (ret)
+    errorStr = rpcConfigSettings.GetStrError();
+
+return ret;
+}
+
+int RPC_CONFIG::Start()
+{
+InitiateRegistry();
+running = true;
+rpcServer = new xmlrpc_c::serverAbyss(
+        rpcRegistry,
+        rpcConfigSettings.GetPort(),
+        "/var/log/stargazer_rpc.log"
+        );
+if (pthread_create(&tid, NULL, Run, this))
+    {
+    errorStr = "Failed to create RPC thread";
+    printfd(__FILE__, "Failed to crate RPC thread\n");
+    return -1;
+    }
+return 0;
+}
+
+int RPC_CONFIG::Stop()
+{
+running = false;
+for (int i = 0; i < 5 && !stopped; ++i)
+    usleep(200000);
+//rpcServer->terminate();
+if (!stopped)
+    {
+    if (pthread_kill(tid, SIGTERM))
+        {
+        errorStr = "Failed to kill thread";
+        printfd(__FILE__, "Failed to kill thread\n");
+        }
+    for (int i = 0; i < 25 && !stopped; ++i)
+        usleep(200000);
+    if (!stopped)
+        {
+        printfd(__FILE__, "Failed to stop RPC thread\n");
+        errorStr = "Failed to stop RPC thread";
+        return -1;
+        }
+    else
+        {
+        pthread_join(tid, NULL);
+        }
+    }
+return 0;
+}
+
+void * RPC_CONFIG::Run(void * rc)
+{
+RPC_CONFIG * config = static_cast<RPC_CONFIG *>(rc);
+
+config->stopped = false;
+while (config->running)
+    {
+    config->rpcServer->runOnce();
+    }
+config->stopped = true;
+
+return NULL;
+}
+
+bool RPC_CONFIG::GetAdminInfo(const std::string & cookie,
+                              ADMIN_INFO * info)
+{
+std::map<std::string,
+         ADMIN_INFO>::iterator it;
+
+it = cookies.find(cookie);
+
+if (it == cookies.end())
+    {
+    return true;
+    }
+
+if (difftime(it->second.accessTime, time(NULL)) >
+    rpcConfigSettings.GetCookieTimeout())
+    {
+    cookies.erase(it);
+    return true;
+    }
+
+// Update access time
+time(&it->second.accessTime);
+*info = it->second;
+return false;
+}
+
+bool RPC_CONFIG::CheckAdmin(const std::string & login,
+                            const std::string & password,
+                            std::string * cookie)
+{
+ADMIN admin;
+
+if (!admins->AdminCorrect(login, password, &admin))
+    {
+    return true;
+    }
+
+ADMIN_INFO info;
+time(&info.accessTime);
+info.admin = login;
+info.priviledges = *admin.GetPriv();
+*cookie = GetCookie();
+cookies[*cookie] = info;
+
+return false;
+}
+
+bool RPC_CONFIG::LogoutAdmin(const std::string & cookie)
+{
+std::map<std::string,
+         ADMIN_INFO>::iterator it;
+
+it = cookies.find(cookie);
+
+if (it == cookies.end())
+    {
+    return true;
+    }
+
+cookies.erase(it);
+
+return false;
+}
+
+std::string RPC_CONFIG::GetCookie() const
+{
+std::string charset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
+std::string cookie;
+
+for (int i = 0; i < 64; ++i)
+    {
+    cookie += charset[rand() % charset.length()];
+    };
+
+return cookie;
+}
+
+void RPC_CONFIG::InitiateRegistry()
+{
+// manage registry
+xmlrpc_c::methodPtr const methodInfoPtr(new METHOD_INFO(
+            tariffs,
+            users,
+            stgSettings
+            ));
+rpcRegistry.addMethod("stargazer.info", methodInfoPtr);
+
+xmlrpc_c::methodPtr const methodLoginPtr(new METHOD_LOGIN(
+            this
+            ));
+rpcRegistry.addMethod("stargazer.login", methodLoginPtr);
+
+xmlrpc_c::methodPtr const methodLogoutPtr(new METHOD_LOGOUT(
+            this
+            ));
+rpcRegistry.addMethod("stargazer.logout", methodLogoutPtr);
+
+xmlrpc_c::methodPtr const methodGetUserPtr(new METHOD_USER_GET(
+            this,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.get_user", methodGetUserPtr);
+
+xmlrpc_c::methodPtr const methodAddUserPtr(new METHOD_USER_ADD(
+            this,
+            admins,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.add_user", methodAddUserPtr);
+
+xmlrpc_c::methodPtr const methodDelUserPtr(new METHOD_USER_DEL(
+            this,
+            admins,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.del_user", methodDelUserPtr);
+
+xmlrpc_c::methodPtr const methodGetUsersPtr(new METHOD_USERS_GET(
+            this,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.get_users", methodGetUsersPtr);
+
+xmlrpc_c::methodPtr const methodChgUserPtr(new METHOD_USER_CHG(
+            this,
+            admins,
+            store,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.chg_user", methodChgUserPtr);
+
+xmlrpc_c::methodPtr const methodAddCashPtr(new METHOD_USER_CASH_ADD(
+            this,
+            admins,
+            store,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.add_cash", methodAddCashPtr);
+
+xmlrpc_c::methodPtr const methodSetCashPtr(new METHOD_USER_CASH_SET(
+            this,
+            admins,
+            store,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.set_cash", methodSetCashPtr);
+
+xmlrpc_c::methodPtr const methodTariffChangePtr(new METHOD_USER_TARIFF_CHANGE(
+            this,
+            admins,
+            tariffs,
+            store,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.tariff_change", methodTariffChangePtr);
+
+xmlrpc_c::methodPtr const methodGetTariffPtr(new METHOD_TARIFF_GET(
+            this,
+            tariffs
+            ));
+rpcRegistry.addMethod("stargazer.get_tariff", methodGetTariffPtr);
+
+xmlrpc_c::methodPtr const methodChgTariffPtr(new METHOD_TARIFF_CHG(
+            this,
+            admins,
+            tariffs
+            ));
+rpcRegistry.addMethod("stargazer.chg_tariff", methodChgTariffPtr);
+
+xmlrpc_c::methodPtr const methodGetTariffsPtr(new METHOD_TARIFFS_GET(
+            this,
+            tariffs
+            ));
+rpcRegistry.addMethod("stargazer.get_tariffs", methodGetTariffsPtr);
+
+xmlrpc_c::methodPtr const methodAddTariffPtr(new METHOD_TARIFF_ADD(
+            this,
+            admins,
+            tariffs
+            ));
+rpcRegistry.addMethod("stargazer.add_tariff", methodAddTariffPtr);
+
+xmlrpc_c::methodPtr const methodDelTariffPtr(new METHOD_TARIFF_DEL(
+            this,
+            admins,
+            tariffs,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.del_tariff", methodDelTariffPtr);
+
+xmlrpc_c::methodPtr const methodGetAdminPtr(new METHOD_ADMIN_GET(
+            this,
+            admins
+            ));
+rpcRegistry.addMethod("stargazer.get_admin", methodGetAdminPtr);
+
+xmlrpc_c::methodPtr const methodAddAdminPtr(new METHOD_ADMIN_ADD(
+            this,
+            admins
+            ));
+rpcRegistry.addMethod("stargazer.add_admin", methodAddAdminPtr);
+
+xmlrpc_c::methodPtr const methodDelAdminPtr(new METHOD_ADMIN_DEL(
+            this,
+            admins
+            ));
+rpcRegistry.addMethod("stargazer.del_admin", methodDelAdminPtr);
+
+xmlrpc_c::methodPtr const methodChgAdminPtr(new METHOD_ADMIN_CHG(
+            this,
+            admins
+            ));
+rpcRegistry.addMethod("stargazer.chg_admin", methodChgAdminPtr);
+
+xmlrpc_c::methodPtr const methodGetAdminsPtr(new METHOD_ADMINS_GET(
+            this,
+            admins
+            ));
+rpcRegistry.addMethod("stargazer.get_admins", methodGetAdminsPtr);
+
+xmlrpc_c::methodPtr const methodSendMessagePtr(new METHOD_MESSAGE_SEND(
+            this,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.send_message", methodSendMessagePtr);
+
+xmlrpc_c::methodPtr const methodGetOnlinIPsPtr(new METHOD_GET_ONLINE_IPS(
+            this,
+            users
+            ));
+rpcRegistry.addMethod("stargazer.get_online_ips", methodGetOnlinIPsPtr);
+}
+
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.h b/projects/stargazer/plugins/configuration/rpcconfig/rpcconfig.h
new file mode 100644 (file)
index 0000000..64f1182
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef __RPC_CONFIG_H__
+#define __RPC_CONFIG_H__
+
+#include <string>
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+#include <xmlrpc-c/server_abyss.hpp>
+
+#include <pthread.h>
+
+#include "base_plugin.h"
+#include "base_store.h"
+#include "base_settings.h"
+#include "admin_conf.h"
+#include "../../../admin.h"
+#include "../../../admins.h"
+#include "../../../users.h"
+#include "../../../tariffs.h"
+#include "../../../traffcounter.h"
+#include "../../../settings.h"
+
+#define RPC_CONFIG_VERSION "Stargazer RPC v. 0.2"
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class RPC_CONFIG_SETTINGS
+{
+public:
+                         RPC_CONFIG_SETTINGS();
+    virtual              ~RPC_CONFIG_SETTINGS() {};
+    const std::string &  GetStrError() const { return errorStr; };
+    int                  ParseSettings(const MODULE_SETTINGS & s);
+    uint16_t             GetPort() const { return port; };
+    double               GetCookieTimeout() const { return cookieTimeout; };
+private:
+    int     ParseIntInRange(const std::string & str,
+                            int min,
+                            int max,
+                            int * val);
+    std::string  errorStr;
+    int          port;
+    double       cookieTimeout;
+};
+
+struct ADMIN_INFO
+{
+    std::string admin;
+    time_t      accessTime;
+    PRIV        priviledges;
+};
+
+class RPC_CONFIG :public BASE_PLUGIN
+{
+public:
+    RPC_CONFIG();
+    virtual ~RPC_CONFIG();
+
+    void                SetUsers(USERS * u) { users = u; };
+    void                SetTariffs(TARIFFS * t) { tariffs = t; };
+    void                SetAdmins(ADMINS * a) { admins = a; };
+    void                SetStore(BASE_STORE * s) { store = s; };
+    void                SetTraffcounter(TRAFFCOUNTER *) {};
+    void                SetStgSettings(const SETTINGS * s) { stgSettings = s; };
+    void                SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning() { return running && !stopped; };
+
+    const string      & GetStrError() const { return errorStr; };
+    const string        GetVersion() const { return RPC_CONFIG_VERSION; };
+    uint16_t            GetStartPosition() const { return 220; };
+    uint16_t            GetStopPosition() const { return 220; };
+
+    bool                GetAdminInfo(const std::string & cookie,
+                                     ADMIN_INFO * info);
+    bool                CheckAdmin(const std::string & login,
+                                   const std::string & password,
+                                   std::string * cookie);
+    bool                LogoutAdmin(const std::string & cookie);
+
+private:
+    mutable string          errorStr;
+    RPC_CONFIG_SETTINGS     rpcConfigSettings;
+    USERS *                 users;
+    ADMINS *                admins;
+    TARIFFS *               tariffs;
+    BASE_STORE *            store;
+    MODULE_SETTINGS         settings;
+    const SETTINGS *        stgSettings;
+    xmlrpc_c::registry      rpcRegistry;
+    xmlrpc_c::serverAbyss * rpcServer;
+    bool                    running;
+    bool                    stopped;
+    pthread_t               tid;
+    std::map<std::string,
+             ADMIN_INFO>    cookies;
+
+    static void *           Run(void *);
+    std::string             GetCookie() const;
+    void                    InitiateRegistry();
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp b/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp
new file mode 100644 (file)
index 0000000..91f6006
--- /dev/null
@@ -0,0 +1,92 @@
+#include "tariff_helper.h"
+
+void TARIFF_HELPER::GetTariffInfo(xmlrpc_c::value * info) const
+{
+std::map<std::string, xmlrpc_c::value> structVal;
+
+structVal["result"] = xmlrpc_c::value_boolean(true);
+structVal["name"] = xmlrpc_c::value_string(data.tariffConf.name);
+structVal["fee"] = xmlrpc_c::value_double(data.tariffConf.fee);
+structVal["freemb"] = xmlrpc_c::value_double(data.tariffConf.free);
+structVal["passivecost"] = xmlrpc_c::value_double(data.tariffConf.passiveCost);
+structVal["traffType"] = xmlrpc_c::value_int(data.tariffConf.traffType);
+
+std::vector<xmlrpc_c::value> prices(DIR_NUM);
+
+for (unsigned i = 0; i < DIR_NUM; ++i)
+    {
+    std::map<std::string, xmlrpc_c::value> dirPrice;
+    dirPrice["hday"] = xmlrpc_c::value_int(data.dirPrice[i].hDay);
+    dirPrice["mday"] = xmlrpc_c::value_int(data.dirPrice[i].mDay);
+    dirPrice["hnight"] = xmlrpc_c::value_int(data.dirPrice[i].hNight);
+    dirPrice["mnight"] = xmlrpc_c::value_int(data.dirPrice[i].mNight);
+    dirPrice["pricedaya"] = xmlrpc_c::value_double(data.dirPrice[i].priceDayA * 1024 * 1024);
+    dirPrice["pricedayb"] = xmlrpc_c::value_double(data.dirPrice[i].priceDayB * 1024 * 1024);
+    dirPrice["pricenighta"] = xmlrpc_c::value_double(data.dirPrice[i].priceNightA * 1024 * 1024);
+    dirPrice["pricenightb"] = xmlrpc_c::value_double(data.dirPrice[i].priceNightB * 1024 * 1024);
+    dirPrice["threshold"] = xmlrpc_c::value_int(data.dirPrice[i].threshold);
+    dirPrice["singleprice"] = xmlrpc_c::value_boolean(data.dirPrice[i].singlePrice);
+    dirPrice["nodiscount"] = xmlrpc_c::value_boolean(data.dirPrice[i].noDiscount);
+    prices[i] = xmlrpc_c::value_struct(dirPrice);
+    }
+
+structVal["dirprices"] = xmlrpc_c::value_array(prices);
+
+*info = xmlrpc_c::value_struct(structVal);
+}
+
+bool TARIFF_HELPER::SetTariffInfo(const xmlrpc_c::value & info)
+{
+std::map<std::string, xmlrpc_c::value> structVal(
+    static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
+    );
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = structVal.find("fee")) != structVal.end())
+    {
+    data.tariffConf.fee = xmlrpc_c::value_double(it->second);
+    }
+
+if ((it = structVal.find("freemb")) != structVal.end())
+    {
+    data.tariffConf.free = xmlrpc_c::value_double(it->second);
+    }
+
+if ((it = structVal.find("passivecost")) != structVal.end())
+    {
+    data.tariffConf.passiveCost = xmlrpc_c::value_double(it->second);
+    }
+
+if ((it = structVal.find("traffType")) != structVal.end())
+    {
+    data.tariffConf.traffType = xmlrpc_c::value_int(it->second);
+    }
+
+if ((it = structVal.find("dirprices")) != structVal.end())
+    {
+    std::vector<xmlrpc_c::value> prices(
+            xmlrpc_c::value_array(it->second).vectorValueValue()
+            );
+
+    for (unsigned i = 0; i < DIR_NUM; ++i)
+        {
+        std::map<std::string, xmlrpc_c::value> dirPrice(
+            static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(prices[i]))
+            );
+        data.dirPrice[i].mDay = xmlrpc_c::value_int(dirPrice["mday"]);
+        data.dirPrice[i].hDay = xmlrpc_c::value_int(dirPrice["hday"]);
+        data.dirPrice[i].mNight = xmlrpc_c::value_int(dirPrice["mnight"]);
+        data.dirPrice[i].hNight = xmlrpc_c::value_int(dirPrice["hnight"]);
+        data.dirPrice[i].priceDayA = xmlrpc_c::value_double(dirPrice["pricedaya"]) / 1024 / 1024;
+        data.dirPrice[i].priceDayB = xmlrpc_c::value_double(dirPrice["pricedayb"]) / 1024 / 1024;
+        data.dirPrice[i].priceNightA = xmlrpc_c::value_double(dirPrice["pricenighta"]) / 1024 / 1024;
+        data.dirPrice[i].priceNightB = xmlrpc_c::value_double(dirPrice["pricenightb"]) / 1024 / 1024;
+        data.dirPrice[i].threshold = xmlrpc_c::value_int(dirPrice["threshold"]);
+        data.dirPrice[i].singlePrice = xmlrpc_c::value_boolean(dirPrice["singleprice"]);
+        data.dirPrice[i].noDiscount = xmlrpc_c::value_boolean(dirPrice["nodiscount"]);
+        }
+    }
+
+return false;
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.h b/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.h
new file mode 100644 (file)
index 0000000..e7b1c6d
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __TARIFF_HELPER_H__
+#define __TARIFF_HELPER_H__
+
+#include <xmlrpc-c/base.hpp>
+#include "../../../tariff.h"
+#include "tariff_conf.h"
+
+class TARIFF_HELPER
+{
+public:
+    TARIFF_HELPER(TARIFF_DATA & td)
+        : data(td)
+    {}
+
+    void GetTariffInfo(xmlrpc_c::value * info) const;
+    bool SetTariffInfo(const xmlrpc_c::value & info);
+private:
+    TARIFF_DATA & data;
+};
+
+#endif
+
+
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/tariffs_methods.cpp b/projects/stargazer/plugins/configuration/rpcconfig/tariffs_methods.cpp
new file mode 100644 (file)
index 0000000..36194e3
--- /dev/null
@@ -0,0 +1,192 @@
+#include "rpcconfig.h"
+#include "tariffs_methods.h"
+#include "tariff_helper.h"
+
+void METHOD_TARIFF_GET::execute(xmlrpc_c::paramList const & paramList,
+                                xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string name = paramList.getString(1);
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+const TARIFF * tariff = tariffs->FindByName(name);
+
+if (!tariff)
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+TARIFF_DATA td;
+
+tariff->GetTariffData(&td);
+
+TARIFF_HELPER helper(td);
+
+helper.GetTariffInfo(retvalPtr);
+}
+
+void METHOD_TARIFF_CHG::execute(xmlrpc_c::paramList const & paramList,
+                                xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string name = paramList.getString(1);
+xmlrpc_c::value_struct info(paramList.getStruct(2));
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+const TARIFF * tariff = tariffs->FindByName(name);
+
+if (!tariff)
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+TARIFF_DATA td;
+
+tariff->GetTariffData(&td);
+
+TARIFF_HELPER helper(td);
+
+helper.SetTariffInfo(info);
+
+if (tariffs->Chg(td, admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+void METHOD_TARIFFS_GET::execute(xmlrpc_c::paramList const & paramList,
+                                 xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+std::vector<xmlrpc_c::value> tariffsInfo;
+
+
+std::list<TARIFF_DATA> dataList;
+tariffs->GetTariffsData(&dataList);
+std::list<TARIFF_DATA>::const_iterator it = dataList.begin();
+for (; it != dataList.end(); ++it)
+    {
+    xmlrpc_c::value info;
+    TARIFF_DATA td(*it); // 'cause TARIFF_HELPER work in both ways and take not const referense
+    TARIFF_HELPER helper(td);
+    helper.GetTariffInfo(&info);
+    tariffsInfo.push_back(info);
+    }
+
+*retvalPtr = xmlrpc_c::value_array(tariffsInfo);
+}
+
+void METHOD_TARIFF_ADD::execute(xmlrpc_c::paramList const & paramList,
+                                xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string tariff = paramList.getString(1);
+std::string enc;
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (tariffs->Add(tariff, admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+void METHOD_TARIFF_DEL::execute(xmlrpc_c::paramList const & paramList,
+                                xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string tariff = paramList.getString(1);
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (users->TariffInUse(tariff))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (tariffs->Del(tariff, admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/tariffs_methods.h b/projects/stargazer/plugins/configuration/rpcconfig/tariffs_methods.h
new file mode 100644 (file)
index 0000000..fdd788d
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __TARIFFS_METHODS_H__
+#define __TARIFFS_METHODS_H__
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+#include "../../../tariffs.h"
+
+class RPC_CONFIG;
+
+class METHOD_TARIFF_GET : public xmlrpc_c::method {
+public:
+    METHOD_TARIFF_GET(RPC_CONFIG * c,
+                      TARIFFS * t)
+        : config(c),
+          tariffs(t)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalPtr);
+private:
+    RPC_CONFIG * config;
+    TARIFFS * tariffs;
+};
+
+class METHOD_TARIFF_CHG : public xmlrpc_c::method {
+public:
+    METHOD_TARIFF_CHG(RPC_CONFIG * c,
+                      ADMINS * a,
+                      TARIFFS * t)
+        : config(c),
+          admins(a),
+          tariffs(t)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalPtr);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    TARIFFS * tariffs;
+};
+
+class METHOD_TARIFFS_GET : public xmlrpc_c::method {
+public:
+    METHOD_TARIFFS_GET(RPC_CONFIG * c,
+                      TARIFFS * t)
+        : config(c),
+          tariffs(t)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalPtr);
+private:
+    RPC_CONFIG * config;
+    TARIFFS * tariffs;
+};
+
+class METHOD_TARIFF_ADD : public xmlrpc_c::method {
+public:
+    METHOD_TARIFF_ADD(RPC_CONFIG * c,
+                      ADMINS * a,
+                      TARIFFS * t)
+        : config(c),
+          admins(a),
+          tariffs(t)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    TARIFFS * tariffs;
+};
+
+class METHOD_TARIFF_DEL : public xmlrpc_c::method {
+public:
+    METHOD_TARIFF_DEL(RPC_CONFIG * c,
+                      ADMINS * a,
+                      TARIFFS * t,
+                      USERS * u)
+        : config(c),
+          admins(a),
+          tariffs(t),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    TARIFFS * tariffs;
+    USERS * users;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp b/projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp
new file mode 100644 (file)
index 0000000..62dcd1a
--- /dev/null
@@ -0,0 +1,412 @@
+#include "user_helper.h"
+
+#include "user_ips.h"
+#include "utils.h"
+
+//------------------------------------------------------------------------------
+
+void USER_HELPER::GetUserInfo(xmlrpc_c::value * info,
+                              bool hidePassword)
+{
+std::string enc;
+
+std::map<std::string, xmlrpc_c::value> structVal;
+
+structVal["result"] = xmlrpc_c::value_boolean(true);
+structVal["login"] = xmlrpc_c::value_string(iter->GetLogin());
+
+if (!hidePassword)
+    {
+    structVal["password"] = xmlrpc_c::value_string(iter->property.password.Get());
+    }
+else
+    {
+    structVal["password"] = xmlrpc_c::value_string("++++++++");
+    }
+
+structVal["cash"] = xmlrpc_c::value_double(iter->property.cash.Get());
+structVal["freemb"] = xmlrpc_c::value_double(iter->property.freeMb.Get());
+structVal["credit"] = xmlrpc_c::value_double(iter->property.credit.Get());
+
+if (iter->property.nextTariff.Get() != "")
+    {
+    structVal["tariff"] = xmlrpc_c::value_string(
+            iter->property.tariffName.Get() +
+            "/" +
+            iter->property.nextTariff.Get()
+            );
+    }
+else
+    {
+    structVal["tariff"] = xmlrpc_c::value_string(iter->property.tariffName.Get());
+    }
+
+structVal["note"] = xmlrpc_c::value_string(IconvString(iter->property.note, "KOI8-R", "UTF-8"));
+
+structVal["phone"] = xmlrpc_c::value_string(IconvString(iter->property.phone, "KOI8-R", "UTF-8"));
+
+structVal["address"] = xmlrpc_c::value_string(IconvString(iter->property.address, "KOI8-R", "UTF-8"));
+
+structVal["email"] = xmlrpc_c::value_string(IconvString(iter->property.email, "KOI8-R", "UTF-8"));
+
+std::vector<xmlrpc_c::value> userdata;
+
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata0.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata1.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata2.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata3.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata4.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata5.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata6.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata7.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata8.Get(), "KOI8-R", "UTF-8")));
+userdata.push_back(xmlrpc_c::value_string(IconvString(iter->property.userdata9.Get(), "KOI8-R", "UTF-8")));
+
+structVal["userdata"] = xmlrpc_c::value_array(userdata);
+
+structVal["name"] = xmlrpc_c::value_string(IconvString(iter->property.realName, "KOI8-R", "UTF-8"));
+
+structVal["group"] = xmlrpc_c::value_string(IconvString(iter->property.group, "KOI8-R", "UTF-8"));
+
+structVal["status"] = xmlrpc_c::value_boolean(iter->GetConnected());
+structVal["aonline"] = xmlrpc_c::value_boolean(iter->property.alwaysOnline.Get());
+structVal["currip"] = xmlrpc_c::value_string(inet_ntostring(iter->GetCurrIP()));
+structVal["pingtime"] = xmlrpc_c::value_int(iter->GetPingTime());
+structVal["ips"] = xmlrpc_c::value_string(iter->property.ips.Get().GetIpStr());
+
+std::map<std::string, xmlrpc_c::value> traffInfo;
+std::vector<xmlrpc_c::value> mu(DIR_NUM);
+std::vector<xmlrpc_c::value> md(DIR_NUM);
+std::vector<xmlrpc_c::value> su(DIR_NUM);
+std::vector<xmlrpc_c::value> sd(DIR_NUM);
+
+DIR_TRAFF upload;
+DIR_TRAFF download;
+DIR_TRAFF supload;
+DIR_TRAFF sdownload;
+download = iter->property.down.Get();
+upload = iter->property.up.Get();
+sdownload = iter->GetSessionUpload();
+supload = iter->GetSessionDownload();
+
+for (int j = 0; j < DIR_NUM; j++)
+    {
+    std::string value;
+    x2str(upload[j], value);
+    mu[j] = xmlrpc_c::value_string(value);
+    x2str(download[j], value);
+    md[j] = xmlrpc_c::value_string(value);
+    x2str(supload[j], value);
+    su[j] = xmlrpc_c::value_string(value);
+    x2str(sdownload[j], value);
+    sd[j] = xmlrpc_c::value_string(value);
+    }
+
+traffInfo["mu"] = xmlrpc_c::value_array(mu);
+traffInfo["md"] = xmlrpc_c::value_array(md);
+traffInfo["su"] = xmlrpc_c::value_array(su);
+traffInfo["sd"] = xmlrpc_c::value_array(sd);
+
+structVal["traff"] = xmlrpc_c::value_struct(traffInfo);
+
+structVal["down"] = xmlrpc_c::value_boolean(iter->property.disabled.Get());
+structVal["disableddetailstat"] = xmlrpc_c::value_boolean(iter->property.disabledDetailStat.Get());
+structVal["passive"] = xmlrpc_c::value_boolean(iter->property.passive.Get());
+structVal["lastcash"] = xmlrpc_c::value_double(iter->property.lastCashAdd.Get());
+structVal["lasttimecash"] = xmlrpc_c::value_int(iter->property.lastCashAddTime.Get());
+structVal["lastactivitytime"] = xmlrpc_c::value_int(iter->property.lastActivityTime.Get());
+structVal["creditexpire"] = xmlrpc_c::value_int(iter->property.creditExpire.Get());
+
+*info = xmlrpc_c::value_struct(structVal);
+}
+
+//------------------------------------------------------------------------------
+
+bool USER_HELPER::SetUserInfo(const xmlrpc_c::value & info,
+                              const ADMIN & admin,
+                              const std::string & login,
+                              const BASE_STORE & store)
+{
+std::map<std::string, xmlrpc_c::value> structVal(
+    static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(info))
+    );
+
+std::map<std::string, xmlrpc_c::value>::iterator it;
+
+if ((it = structVal.find("password")) != structVal.end())
+    {
+    bool res = iter->property.password.Set(xmlrpc_c::value_string(it->second),
+                                           admin,
+                                           login,
+                                           &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("ips")) != structVal.end())
+    {
+    USER_IPS ips;
+    ips = StrToIPS(xmlrpc_c::value_string(it->second));
+    bool res = iter->property.ips.Set(ips,
+                                      admin,
+                                      login,
+                                      &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("address")) != structVal.end())
+    {
+    bool res = iter->property.address.Set(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-R"),
+                                          admin,
+                                          login,
+                                          &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("phone")) != structVal.end())
+    {
+    bool res = iter->property.phone.Set(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-R"),
+                                        admin,
+                                        login,
+                                        &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("email")) != structVal.end())
+    {
+    bool res = iter->property.email.Set(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-R"),
+                                        admin,
+                                        login,
+                                        &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("creditexpire")) != structVal.end())
+    {
+    bool res = iter->property.creditExpire.Set(xmlrpc_c::value_int(it->second),
+                                               admin,
+                                               login,
+                                               &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("credit")) != structVal.end())
+    {
+    bool res = iter->property.credit.Set(xmlrpc_c::value_double(it->second),
+                                         admin,
+                                         login,
+                                         &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("freemb")) != structVal.end())
+    {
+    bool res = iter->property.freeMb.Set(xmlrpc_c::value_double(it->second),
+                                         admin,
+                                         login,
+                                         &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("disabled")) != structVal.end())
+    {
+    bool res = iter->property.disabled.Set(xmlrpc_c::value_boolean(it->second),
+                                           admin,
+                                           login,
+                                           &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("passive")) != structVal.end())
+    {
+    bool res = iter->property.passive.Set(xmlrpc_c::value_boolean(it->second),
+                                          admin,
+                                          login,
+                                          &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("aonline")) != structVal.end())
+    {
+    bool res = iter->property.alwaysOnline.Set(xmlrpc_c::value_boolean(it->second),
+                                               admin,
+                                               login,
+                                               &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("disableddetailstat")) != structVal.end())
+    {
+    bool res = iter->property.disabledDetailStat.Set(xmlrpc_c::value_boolean(it->second),
+                                                     admin,
+                                                     login,
+                                                     &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("name")) != structVal.end())
+    {
+    bool res = iter->property.realName.Set(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-R"),
+                                           admin,
+                                           login,
+                                           &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("group")) != structVal.end())
+    {
+    bool res = iter->property.group.Set(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-R"),
+                                        admin,
+                                        login,
+                                        &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("note")) != structVal.end())
+    {
+    bool res = iter->property.note.Set(IconvString(xmlrpc_c::value_string(it->second), "UTF-8", "KOI8-R"),
+                                       admin,
+                                       login,
+                                       &store);
+    if (!res)
+        {
+        return true;
+        }
+    }
+
+if ((it = structVal.find("userdata")) != structVal.end())
+    {
+    std::vector<USER_PROPERTY_LOGGED<string> *> userdata;
+    userdata.push_back(iter->property.userdata0.GetPointer());
+    userdata.push_back(iter->property.userdata1.GetPointer());
+    userdata.push_back(iter->property.userdata2.GetPointer());
+    userdata.push_back(iter->property.userdata3.GetPointer());
+    userdata.push_back(iter->property.userdata4.GetPointer());
+    userdata.push_back(iter->property.userdata5.GetPointer());
+    userdata.push_back(iter->property.userdata6.GetPointer());
+    userdata.push_back(iter->property.userdata7.GetPointer());
+    userdata.push_back(iter->property.userdata8.GetPointer());
+    userdata.push_back(iter->property.userdata9.GetPointer());
+
+    std::vector<xmlrpc_c::value> udata(
+        xmlrpc_c::value_array(it->second).vectorValueValue()
+        );
+
+    for (unsigned i = 0; i < userdata.size(); ++i)
+        {
+        bool res = userdata[i]->Set(IconvString(xmlrpc_c::value_string(udata[i]), "UTF-8", "KOI8-R"),
+                                    admin,
+                                    login,
+                                    &store);
+        if (!res)
+            {
+            return true;
+            }
+        }
+    }
+
+if ((it = structVal.find("traff")) != structVal.end())
+    {
+    std::map<std::string, xmlrpc_c::value> traff(
+        static_cast<std::map<std::string, xmlrpc_c::value> >(xmlrpc_c::value_struct(it->second))
+        );
+
+    std::vector<xmlrpc_c::value> data;
+    DIR_TRAFF dtData;
+    dtData = iter->property.up.Get();
+    if ((it = traff.find("mu")) != traff.end())
+        {
+        data = xmlrpc_c::value_array(it->second).vectorValueValue();
+
+        for (int i = 0; i < std::min(DIR_NUM, static_cast<int>(data.size())); ++i)
+            {
+            int64_t value;
+            if (str2x(xmlrpc_c::value_string(data[i]), value))
+                {
+                printfd(__FILE__, "USER_HELPER::SetUserInfo(): 'Invalid month upload value'\n");
+                }
+            else
+                {
+                dtData[i] = value;
+                }
+            }
+        bool res = iter->property.up.Set(dtData,
+                                         admin,
+                                         login,
+                                         &store);
+        if (!res)
+            {
+            return true;
+            }
+        }
+    dtData = iter->property.down.Get();
+    if ((it = traff.find("md")) != traff.end())
+        {
+        data = xmlrpc_c::value_array(it->second).vectorValueValue();
+
+        for (int i = 0; i < std::min(DIR_NUM, static_cast<int>(data.size())); ++i)
+            {
+            int64_t value;
+            if (str2x(xmlrpc_c::value_string(data[i]), value))
+                {
+                printfd(__FILE__, "USER_HELPER::SetUserInfo(): 'Invalid month download value'\n");
+                }
+            else
+                {
+                dtData[i] = value;
+                }
+            }
+        bool res = iter->property.down.Set(dtData,
+                                           admin,
+                                           login,
+                                           &store);
+        if (!res)
+            {
+            return true;
+            }
+        }
+    }
+
+return false;
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/user_helper.h b/projects/stargazer/plugins/configuration/rpcconfig/user_helper.h
new file mode 100644 (file)
index 0000000..6421a46
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __USER_HELPER_H__
+#define __USER_HELPER_H__
+
+#include <string>
+
+#include <xmlrpc-c/base.hpp>
+#include "../../../users.h"
+#include "../../../admin.h"
+#include "base_store.h"
+
+class USER_HELPER
+{
+public:
+    USER_HELPER(user_iter & it)
+        : iter(it)
+    {
+    }
+
+    void GetUserInfo(xmlrpc_c::value * info,
+                     bool hidePassword = false);
+    bool SetUserInfo(const xmlrpc_c::value & info,
+                     const ADMIN & admin,
+                     const std::string & login,
+                     const BASE_STORE & store);
+private:
+    user_iter & iter;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp b/projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp
new file mode 100644 (file)
index 0000000..d6812f5
--- /dev/null
@@ -0,0 +1,511 @@
+#include "users_methods.h"
+
+#include "rpcconfig.h"
+#include "user_helper.h"
+#include "user_ips.h"
+#include "utils.h"
+
+#include "common.h"
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_GET::execute(xmlrpc_c::paramList const & paramList,
+                              xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+std::string enc;
+paramList.verifyEnd(2);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+USER_HELPER uhelper(u);
+
+if (!adminInfo.priviledges.userConf || !adminInfo.priviledges.userPasswd)
+    {
+    uhelper.GetUserInfo(retvalPtr, true);
+    return;
+    }
+
+uhelper.GetUserInfo(retvalPtr);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_ADD::execute(xmlrpc_c::paramList const & paramList,
+                              xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+std::string enc;
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    if (users->Add(login, admin))
+        {
+        *retvalPtr = xmlrpc_c::value_boolean(false);
+        return;
+        }
+
+    *retvalPtr = xmlrpc_c::value_boolean(true);
+    return;
+    }
+    
+*retvalPtr = xmlrpc_c::value_boolean(false);
+return;
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_DEL::execute(xmlrpc_c::paramList const & paramList,
+                              xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+std::string enc;
+paramList.verifyEnd(2);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    users->Del(login, admin);
+    *retvalPtr = xmlrpc_c::value_boolean(true);
+    return;
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(false);
+return;
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USERS_GET::execute(xmlrpc_c::paramList const & paramList,
+                               xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string enc;
+paramList.verifyEnd(1);
+
+std::map<std::string, xmlrpc_c::value> structVal;
+std::vector<xmlrpc_c::value> retval;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+bool hidePassword = !adminInfo.priviledges.userConf ||
+                    !adminInfo.priviledges.userPasswd;
+
+user_iter u;
+
+int h = users->OpenSearch();
+if (!h)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    users->CloseSearch(h);
+    return;
+    }
+
+while (1)
+    {
+    if (users->SearchNext(h, &u))
+        {
+        break;
+        }
+
+    xmlrpc_c::value info;
+
+    USER_HELPER uhelper(u);
+
+    uhelper.GetUserInfo(&info, hidePassword);
+
+    retval.push_back(info);
+    }
+
+*retvalPtr = xmlrpc_c::value_array(retval);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_CHG::execute(xmlrpc_c::paramList const & paramList,
+                              xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+xmlrpc_c::value_struct info(paramList.getStruct(2));
+std::string enc;
+paramList.verifyEnd(3);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+USER_HELPER uhelper(u);
+
+if (!adminInfo.priviledges.userConf || !adminInfo.priviledges.userPasswd)
+    {
+    uhelper.SetUserInfo(info, admin, login, *store);
+    }
+else
+    {
+    uhelper.SetUserInfo(info, admin, login, *store);
+    }
+
+u->WriteConf();
+u->WriteStat();
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_CASH_ADD::execute(xmlrpc_c::paramList const & paramList,
+                                   xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+double amount = paramList.getDouble(2);
+std::string comment = IconvString(paramList.getString(3), "UTF-8", "KOI8-R");
+std::string enc;
+paramList.verifyEnd(4);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+double cash = u->property.cash.Get();
+cash += amount;
+
+if (!u->property.cash.Set(cash, admin, login, store, comment))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+u->WriteStat();
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_CASH_SET::execute(xmlrpc_c::paramList const & paramList,
+                                   xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+double cash = paramList.getDouble(2);
+std::string comment = IconvString(paramList.getString(3), "UTF-8", "KOI8-R");
+std::string enc;
+paramList.verifyEnd(4);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (!u->property.cash.Set(cash, admin, login, store, comment))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+u->WriteStat();
+
+*retvalPtr = xmlrpc_c::value_boolean(true);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_USER_TARIFF_CHANGE::execute(xmlrpc_c::paramList const & paramList,
+                                        xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::string login = paramList.getString(1);
+std::string tariff = paramList.getString(2);
+bool delayed = paramList.getBoolean(3);
+std::string comment = IconvString(paramList.getString(4), "UTF-8", "KOI8-R");
+std::string enc;
+paramList.verifyEnd(5);
+
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+ADMIN admin;
+
+if (admins->FindAdmin(adminInfo.admin, &admin))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+user_iter u;
+
+if (users->FindByName(login, &u))
+    {
+    *retvalPtr = xmlrpc_c::value_boolean(false);
+    return;
+    }
+
+if (tariffs->FindByName(tariff))
+    {
+    if (delayed)
+        {
+        if (u->property.nextTariff.Set(tariff,
+                                       admin,
+                                       login,
+                                       store))
+            {
+            u->WriteConf();
+            *retvalPtr = xmlrpc_c::value_boolean(true);
+            return;
+            }
+        }
+    if (u->property.tariffName.Set(tariff,
+                                   admin,
+                                   login,
+                                   store))
+        {
+        u->WriteConf();
+        *retvalPtr = xmlrpc_c::value_boolean(true);
+        return;
+        }
+    }
+
+*retvalPtr = xmlrpc_c::value_boolean(false);
+}
+
+//------------------------------------------------------------------------------
+
+void METHOD_GET_ONLINE_IPS::execute(xmlrpc_c::paramList const & paramList,
+                                    xmlrpc_c::value *   const   retvalPtr)
+{
+std::string cookie = paramList.getString(0);
+std::vector<xmlrpc_c::value> subnetsStr = paramList.getArray(1);
+paramList.verifyEnd(2);
+
+std::vector<IP_MASK> subnets;
+
+std::vector<xmlrpc_c::value>::iterator it;
+
+for (it = subnetsStr.begin(); it != subnetsStr.end(); ++it)
+    {
+    IP_MASK ipm;
+    if (ParseNet(xmlrpc_c::value_string(*it), ipm))
+        {
+        printfd(__FILE__, "METHOD_GET_ONLINE_IPS::execute(): Failed to parse subnet ('%s')\n", std::string(xmlrpc_c::value_string(*it)).c_str());
+        }
+    else
+        {
+        subnets.push_back(ipm);
+        }
+    }
+
+std::map<std::string, xmlrpc_c::value> structVal;
+ADMIN_INFO adminInfo;
+
+if (config->GetAdminInfo(cookie, &adminInfo))
+    {
+    structVal["result"] = xmlrpc_c::value_boolean(false);
+    *retvalPtr = xmlrpc_c::value_struct(structVal);
+    return;
+    }
+
+std::vector<xmlrpc_c::value> ips;
+
+user_iter u;
+
+int handle = users->OpenSearch();
+if (!handle)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    users->CloseSearch(handle);
+    return;
+    }
+
+while (1)
+    {
+    if (users->SearchNext(handle, &u))
+        {
+        break;
+        }
+
+    if (u->GetAuthorized())
+        {
+        uint32_t ip = u->GetCurrIP();
+
+        std::vector<IP_MASK>::iterator it;
+        for (it = subnets.begin(); it != subnets.end(); ++it)
+            {
+            if ((it->ip & it->mask) == (ip & it->mask))
+                {
+                ips.push_back(xmlrpc_c::value_string(inet_ntostring(u->GetCurrIP())));
+                break;
+                }
+            }
+        }
+    }
+
+structVal["ips"] = xmlrpc_c::value_array(ips);
+
+*retvalPtr = xmlrpc_c::value_struct(structVal);
+}
+
+bool METHOD_GET_ONLINE_IPS::ParseNet(const std::string & net, IP_MASK & ipm) const
+{
+size_t pos = net.find_first_of('/');
+
+if (pos == std::string::npos)
+    {
+    printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Network address is not in CIDR-notation\n");
+    return true;
+    }
+
+int res = inet_pton(AF_INET, net.substr(0, pos).c_str(), &ipm.ip);
+
+if (res < 0)
+    {
+    printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): '%s'\n", strerror(errno));
+    return true;
+    }
+else if (res == 0)
+    {
+    printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Invalid network address\n", strerror(errno));
+    return true;
+    }
+
+if (str2x(net.substr(pos + 1, net.length() - pos - 1), ipm.mask))
+    {
+    printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Invalid network mask\n");
+    return true;
+    }
+if (ipm.mask > 32)
+    {
+    printfd(__FILE__, "METHOD_GET_ONLINE_IPS::ParseNet(): Network mask is out of range\n");
+    return true;
+    }
+ipm.mask = htonl(0xffFFffFF << (32 - ipm.mask));
+
+return false;
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/users_methods.h b/projects/stargazer/plugins/configuration/rpcconfig/users_methods.h
new file mode 100644 (file)
index 0000000..ee8e656
--- /dev/null
@@ -0,0 +1,191 @@
+#ifndef __USERS_METHODS_H__
+#define __USERS_METHODS_H__
+
+#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/registry.hpp>
+
+#include "../../../users.h"
+#include "../../../user.h"
+
+class RPC_CONFIG;
+
+class METHOD_USER_GET : public xmlrpc_c::method {
+public:
+    METHOD_USER_GET(RPC_CONFIG * c,
+                    USERS * u)
+        : config(c),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    USERS * users;
+};
+
+class METHOD_USER_ADD : public xmlrpc_c::method {
+public:
+    METHOD_USER_ADD(RPC_CONFIG * c,
+                    ADMINS * a,
+                    USERS * u)
+        : config(c),
+          admins(a),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    USERS * users;
+};
+
+class METHOD_USER_DEL : public xmlrpc_c::method {
+public:
+    METHOD_USER_DEL(RPC_CONFIG * c,
+                    ADMINS * a,
+                    USERS * u)
+        : config(c),
+          admins(a),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    USERS * users;
+};
+
+class METHOD_USERS_GET : public xmlrpc_c::method {
+public:
+    METHOD_USERS_GET(RPC_CONFIG * c,
+                     USERS * u)
+        : config(c),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    USERS * users;
+};
+
+class METHOD_USER_CHG : public xmlrpc_c::method {
+public:
+    METHOD_USER_CHG(RPC_CONFIG * c,
+                    ADMINS * a,
+                    BASE_STORE * s,
+                    USERS * u)
+        : config(c),
+          admins(a),
+          store(s),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    BASE_STORE * store;
+    USERS * users;
+};
+
+class METHOD_USER_CASH_ADD : public xmlrpc_c::method {
+public:
+    METHOD_USER_CASH_ADD(RPC_CONFIG * c,
+                         ADMINS * a,
+                         BASE_STORE * s,
+                         USERS * u)
+        : config(c),
+          admins(a),
+          store(s),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    BASE_STORE * store;
+    USERS * users;
+};
+
+class METHOD_USER_CASH_SET : public xmlrpc_c::method {
+public:
+    METHOD_USER_CASH_SET(RPC_CONFIG * c,
+                         ADMINS * a,
+                         BASE_STORE * s,
+                         USERS * u)
+        : config(c),
+          admins(a),
+          store(s),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    BASE_STORE * store;
+    USERS * users;
+};
+
+class METHOD_USER_TARIFF_CHANGE : public xmlrpc_c::method {
+public:
+    METHOD_USER_TARIFF_CHANGE(RPC_CONFIG * c,
+                              ADMINS * a,
+                              TARIFFS * t,
+                              BASE_STORE * s,
+                              USERS * u)
+        : config(c),
+          admins(a),
+          tariffs(t),
+          store(s),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    ADMINS * admins;
+    TARIFFS * tariffs;
+    BASE_STORE * store;
+    USERS * users;
+};
+
+class METHOD_GET_ONLINE_IPS : public xmlrpc_c::method {
+public:
+    METHOD_GET_ONLINE_IPS(RPC_CONFIG * c,
+                          USERS * u)
+        : config(c),
+          users(u)
+    {
+    }
+
+    void execute(xmlrpc_c::paramList const & paramList,
+                 xmlrpc_c::value *   const   retvalP);
+private:
+    RPC_CONFIG * config;
+    USERS * users;
+
+    bool ParseNet(const std::string & net, IP_MASK & ipm) const;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/utils.cpp b/projects/stargazer/plugins/configuration/rpcconfig/utils.cpp
new file mode 100644 (file)
index 0000000..18999aa
--- /dev/null
@@ -0,0 +1,78 @@
+#include <string>
+#include <cerrno>
+#include <cstring>
+#include <iconv.h>
+
+#include "utils.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+std::string IconvString(const std::string & src,
+                        const std::string & from,
+                        const std::string & to)
+{
+if (src.empty())
+    return std::string();
+
+size_t inBytesLeft = src.length() + 1;
+size_t outBytesLeft = src.length() * 2 + 1;
+
+char * inBuf = new char[inBytesLeft];
+char * outBuf = new char[outBytesLeft];
+
+strncpy(inBuf, src.c_str(), src.length());
+
+inBuf[src.length()] = 0;
+
+#if defined(FREE_BSD) || defined(FREE_BSD5)
+const char * srcPos = inBuf;
+#else
+char * srcPos = inBuf;
+#endif
+char * dstPos = outBuf;
+
+iconv_t handle = iconv_open(to.c_str(),
+                            from.c_str());
+
+if (handle == iconv_t(-1))
+    {
+    if (errno == EINVAL)
+        {
+        printfd(__FILE__, "IconvString(): iconv from %s to %s failed\n", from.c_str(), to.c_str());
+        delete[] outBuf;
+        delete[] inBuf;
+        return src;
+        }
+    else
+        printfd(__FILE__, "IconvString(): iconv_open error\n");
+
+    delete[] outBuf;
+    delete[] inBuf;
+    return src;
+    }
+
+size_t res = iconv(handle,
+                   &srcPos, &inBytesLeft,
+                   &dstPos, &outBytesLeft);
+
+if (res == size_t(-1))
+    {
+    printfd(__FILE__, "IconvString(): '%s'\n", strerror(errno));
+
+    iconv_close(handle);
+    delete[] outBuf;
+    delete[] inBuf;
+    return src;
+    }
+
+dstPos = 0;
+
+std::string dst(outBuf);
+
+iconv_close(handle);
+
+delete[] outBuf;
+delete[] inBuf;
+
+return dst;
+}
diff --git a/projects/stargazer/plugins/configuration/rpcconfig/utils.h b/projects/stargazer/plugins/configuration/rpcconfig/utils.h
new file mode 100644 (file)
index 0000000..d273e3d
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <string>
+
+std::string IconvString(const std::string & src,
+                        const std::string & from = "UTF-8",
+                        const std::string & to = "KOI8-R");
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/sgconfig/Makefile b/projects/stargazer/plugins/configuration/sgconfig/Makefile
new file mode 100644 (file)
index 0000000..8f065d1
--- /dev/null
@@ -0,0 +1,22 @@
+###############################################################################
+# $Id: Makefile,v 1.11 2010/03/04 10:47:45 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_conf_sg.so
+
+SRCS = ./stgconfig.cpp \
+       ./rsconf.cpp \
+       ./configproto.cpp \
+       ./parser.cpp \
+       ./parser_tariff.cpp \
+       ./parser_admin.cpp
+
+LIBS += -lexpat \
+       $(LIB_THREAD)
+
+STGLIBS = -lstg_common -lstg_logger -lstg_crypto
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp b/projects/stargazer/plugins/configuration/sgconfig/configproto.cpp
new file mode 100644 (file)
index 0000000..38b423f
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.22 $
+ $Date: 2010/10/04 20:24:14 $
+ $Author: faust $
+ */
+
+
+#include <unistd.h>
+
+#include "configproto.h"
+
+//-----------------------------------------------------------------------------
+void ParseXMLStart(void *data, const char *el, const char **attr)
+{
+CONFIGPROTO * cp = static_cast<CONFIGPROTO *>(data);
+
+if (cp->currParser)
+    {
+    cp->currParser->SetAnswerList(&cp->answerList);
+    cp->currParser->SetCurrAdmin(cp->currAdmin);
+    cp->currParser->ParseStart(data, el, attr);
+    }
+else
+    {
+    for (unsigned int i = 0; i < cp->dataParser.size(); i++)
+        {
+        cp->dataParser[i]->SetAnswerList(&cp->answerList);
+        //cp->currAdmin->SetAdminIP(cp->GetAdminIP());
+        cp->dataParser[i]->SetCurrAdmin(cp->currAdmin);
+        cp->dataParser[i]->Reset();
+        if (cp->dataParser[i]->ParseStart(data, el, attr) == 0)
+            {
+            cp->currParser = cp->dataParser[i];
+            break;
+            }
+        else
+            {
+            cp->dataParser[i]->Reset();
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void ParseXMLEnd(void *data, const char *el)
+{
+CONFIGPROTO * cp = static_cast<CONFIGPROTO *>(data);
+if (cp->currParser)
+    {
+    if (cp->currParser->ParseEnd(data, el) == 0)
+        {
+        cp->currParser = NULL;
+        }
+    }
+else
+    {
+    for (unsigned int i = 0; i < cp->dataParser.size(); i++)
+        {
+        if (cp->dataParser[i]->ParseEnd(data, el) == 0)
+            {
+            break;
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+CONFIGPROTO::CONFIGPROTO()
+    : adminIP(0),
+      port(0),
+      nonstop(1),
+      state(0),
+      currAdmin(),
+      WriteServLog(GetStgLogger()),
+      outerSocket(0),
+      listenSocket(0),
+      admins(NULL),
+      //users(NULL),
+      //tariffs(NULL),
+      //store(NULL),
+      //settings(NULL),
+      currParser(NULL)
+{
+dataParser.push_back(&parserGetServInfo);
+
+dataParser.push_back(&parserGetUsers);
+dataParser.push_back(&parserGetUser);
+dataParser.push_back(&parserChgUser);
+dataParser.push_back(&parserAddUser);
+dataParser.push_back(&parserDelUser);
+dataParser.push_back(&parserCheckUser);
+dataParser.push_back(&parserSendMessage);
+
+dataParser.push_back(&parserGetTariffs);
+dataParser.push_back(&parserAddTariff);
+dataParser.push_back(&parserDelTariff);
+dataParser.push_back(&parserChgTariff);
+
+dataParser.push_back(&parserGetAdmins);
+dataParser.push_back(&parserChgAdmin);
+dataParser.push_back(&parserDelAdmin);
+dataParser.push_back(&parserAddAdmin);
+
+xmlParser = XML_ParserCreate(NULL);
+
+if (!xmlParser)
+    {
+    WriteServLog("Couldn't allocate memory for parser.");
+    exit(1);
+    }
+
+//XML_SetElementHandler(parser, ParseXMLStart, ParseXMLEnd);
+}
+//-----------------------------------------------------------------------------
+CONFIGPROTO::~CONFIGPROTO()
+{
+XML_ParserFree(xmlParser);
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::ParseCommand()
+{
+list<string>::iterator n;
+int done = 0;
+char str[9];
+int len;
+
+if (requestList.empty())
+    return 0;
+
+n = requestList.begin();
+
+strncpy(str, (*n).c_str(), 8);
+str[8] = 0;
+
+XML_ParserReset(xmlParser, NULL);
+XML_SetElementHandler(xmlParser, ParseXMLStart, ParseXMLEnd);
+XML_SetUserData(xmlParser, this);
+
+while(nonstop)
+    {
+    strncpy(str, (*n).c_str(), 8);
+    str[8] = 0;
+    len = strlen(str);
+
+    n++;
+    if (n == requestList.end())
+        done = 1;
+    n--;
+
+    if (XML_Parse(xmlParser, (*n).c_str(), len, done) == XML_STATUS_ERROR)
+        {
+        WriteServLog("Invalid configuration request");
+        printfd(__FILE__, "Parse error at line %d:\n%s\n",
+           XML_GetCurrentLineNumber(xmlParser),
+           XML_ErrorString(XML_GetErrorCode(xmlParser)));
+        if (currParser)
+            {
+            printfd(__FILE__, "Parser reset\n");
+            currParser->Reset();
+            currParser = NULL;
+            }
+
+        return -1;
+        }
+
+    if (done)
+        return 0;
+
+    n++;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetPort(uint16_t p)
+{
+port = p;
+}
+//-----------------------------------------------------------------------------
+/*void CONFIGPROTO::SetHostAllow(HOSTALLOW *)
+{
+//hostAllow = ha;
+}*/
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetAdmins(ADMINS * a)
+{
+admins = a;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetAdmins(a);
+    }
+
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetUsers(USERS * u)
+{
+//users = u;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetUsers(u);
+    }
+
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetTariffs(TARIFFS * t)
+{
+//tariffs = t;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetTariffs(t);
+    }
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetStore(BASE_STORE * s)
+{
+//store = s;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetStore(s);
+    }
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetStgSettings(const SETTINGS * s)
+{
+//settings = s;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetStgSettings(s);
+    }
+}
+//-----------------------------------------------------------------------------
+/*void CONFIGPROTO::Start()
+{
+finished = false;
+threadExited = false;
+status = starting;
+
+xmlParser = XML_ParserCreate(NULL);
+
+if (!xmlParser)
+    {
+    WriteServLog("Couldn't allocate memory for parser.");
+    }
+
+pthread_create(&thrReciveSendConf, NULL, ReciveSendConf, this);
+status = started;
+}*/
+//-----------------------------------------------------------------------------
+/*int CONFIGPROTO::Stop()
+{
+nonstop = true;
+close(outerSocket);
+return 0;
+}*/
+//-----------------------------------------------------------------------------
+/*void CONFIGPROTO::Restart()
+{
+//Stop();
+//Start();
+}*/
+//-----------------------------------------------------------------------------
+/*CONF_STATUS CONFIGPROTO::Status()
+{
+//return status;
+}
+//-----------------------------------------------------------------------------
+*/
+const string & CONFIGPROTO::GetStrError()
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+uint32_t CONFIGPROTO::GetAdminIP()
+{
+return adminIP;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/configuration/sgconfig/configproto.h b/projects/stargazer/plugins/configuration/sgconfig/configproto.h
new file mode 100644 (file)
index 0000000..2936986
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.14 $
+ $Date: 2010/10/04 20:24:14 $
+ $Author: faust $
+ */
+
+
+#ifndef CONFIGPROTO_H
+#define CONFIGPROTO_H
+
+#include <expat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string>
+
+#include "parser.h"
+#include "../../../users.h"
+#include "../../../admins.h"
+#include "../../../tariffs.h"
+#include "stg_logger.h"
+
+using namespace std;
+
+#define  STG_HEADER     "SG04"
+#define  OK_HEADER      "OKHD"
+#define  ERR_HEADER     "ERHD"
+#define  OK_LOGIN       "OKLG"
+#define  ERR_LOGIN      "ERLG"
+#define  OK_LOGINS      "OKLS"
+#define  ERR_LOGINS     "ERLS"
+
+//-----------------------------------------------------------------------------
+class CONFIGPROTO
+{
+public:
+    CONFIGPROTO();
+    ~CONFIGPROTO();
+
+    void            SetPort(uint16_t port);
+    //void            SetHostAllow(HOSTALLOW * ha);
+    void            SetAdmins(ADMINS * a);
+    void            SetUsers(USERS * u);
+    void            SetTariffs(TARIFFS * t);
+    void            SetStore(BASE_STORE * s);
+    void            SetStgSettings(const SETTINGS * s);
+    const string &  GetAdminLogin();
+    uint32_t        GetAdminIP();
+    int             Prepare();
+    int             Stop();
+    const string &  GetStrError();
+    static void *   Run(void * a);
+
+private:
+    int             RecvHdr(int sock);
+    int             RecvLogin(int sock);
+    int             SendLoginAnswer(int sock, int err);
+    int             SendHdrAnswer(int sock, int err);
+    int             RecvLoginS(int sock);
+    int             SendLoginSAnswer(int sock, int err);
+    int             RecvData(int sock);
+    int             SendDataAnswer(int sock);
+    void            SendError(const char * text);
+    void            WriteLogAccessFailed(uint32_t ip);
+
+    int             ParseCommand();
+
+    list<string>    answerList;
+    list<string>    requestList;
+    uint32_t        adminIP;
+    string          adminLogin;
+    uint16_t        port;
+    pthread_t       thrReciveSendConf;
+    bool            nonstop;
+    int             state;
+    //HOSTALLOW *     hostAllow;
+    ADMIN           currAdmin;
+    STG_LOGGER &    WriteServLog;
+
+    int                 outerSocket;
+    int                 listenSocket;
+    struct sockaddr_in  outerAddr;
+    socklen_t           outerAddrLen;
+
+    PARSER_GET_SERVER_INFO      parserGetServInfo;
+
+    PARSER_GET_USERS            parserGetUsers;
+    PARSER_GET_USER             parserGetUser;
+    PARSER_CHG_USER             parserChgUser;
+    PARSER_ADD_USER             parserAddUser;
+    PARSER_DEL_USER             parserDelUser;
+    PARSER_CHECK_USER           parserCheckUser;
+    PARSER_SEND_MESSAGE         parserSendMessage;
+
+    PARSER_GET_ADMINS           parserGetAdmins;
+    PARSER_ADD_ADMIN            parserAddAdmin;
+    PARSER_DEL_ADMIN            parserDelAdmin;
+    PARSER_CHG_ADMIN            parserChgAdmin;
+
+    PARSER_GET_TARIFFS          parserGetTariffs;
+    PARSER_ADD_TARIFF           parserAddTariff;
+    PARSER_DEL_TARIFF           parserDelTariff;
+    PARSER_CHG_TARIFF           parserChgTariff;
+
+    ADMINS *                    admins;
+    //USERS *                     users;
+    //TARIFFS *                   tariffs;
+    //BASE_STORE *                store;
+    //const SETTINGS *            settings;
+
+    BASE_PARSER *               currParser;
+    vector<BASE_PARSER*>        dataParser;
+
+    XML_Parser                  xmlParser;
+
+    string                      errorStr;
+
+    friend void ParseXMLStart(void *data, const char *el, const char **attr);
+    friend void ParseXMLEnd(void *data, const char *el);
+};
+//-----------------------------------------------------------------------------
+#endif //CONFIGPROTO_H
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/net_configurator.cpp b/projects/stargazer/plugins/configuration/sgconfig/net_configurator.cpp
new file mode 100644 (file)
index 0000000..6b8bc84
--- /dev/null
@@ -0,0 +1,133 @@
+#include <unistd.h>
+#include "net_configurator.h"
+#include "../../internal_configurator.h"
+
+//-----------------------------------------------------------------------------
+const string & NET_CONFIGURATOR_SETTINGS::GetStrError()
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR_SETTINGS::ReadSettings(const CONFIGFILE &cf)
+{
+if (cf.ReadUShortInt("AdminPort", &port, 5555) != 0)
+    {
+    strError = "Cannot read parameter AdminPort.";
+    return -1;
+    }
+if (port < 1 || port > 65535)
+    {
+    strError = "Incorrect value AdminPort.";
+    return -1;
+    }
+
+string strOrder;
+cf.ReadString("AdminOrder", &strOrder, "allow,deny");
+if (hostAllow.ParseOrder(strOrder.c_str()) < 0)
+    {
+    strError = string("Error in parameter AdminOrder. ") + hostAllow.GetStrError();
+    return -1;
+    }
+
+string strAllow;
+cf.ReadString("AdminAllowFrom", &strAllow, "all");
+if (hostAllow.ParseHosts(strAllow.c_str(), hostsAllow) != 0)
+    {
+    strError = string("Error in parameter AdminAllowFrom. ") + hostAllow.GetStrError();
+    return -1;
+    }
+
+string strDeny;
+cf.ReadString("AdminDenyFrom", &strDeny, "");
+if (hostAllow.ParseHosts(strDeny.c_str(), hostsDeny) != 0)
+    {
+    strError = string("Error in parameter AdminDenyFrom. ") + hostAllow.GetStrError();
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t NET_CONFIGURATOR_SETTINGS::GetPort()
+{
+return port;
+}
+//-----------------------------------------------------------------------------
+HOSTALLOW * NET_CONFIGURATOR_SETTINGS::GetHostAllow()
+{
+return &hostAllow;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+NET_CONFIGURATOR::NET_CONFIGURATOR()
+{
+hostAllow = settings.GetHostAllow();
+}
+//-----------------------------------------------------------------------------
+NET_CONFIGURATOR::~NET_CONFIGURATOR()
+{
+
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::SetStgConfigurator(BASE_INT_CONFIGURATOR * bsc)
+{
+stgConfigurator = bsc;
+cp.SetStgConfigurator(stgConfigurator);
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR::UserGetAll(string * login, 
+                       USER_CONF_RES * conf,
+                       USER_STAT_RES * stat,
+                       time_t lastUpdate)
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR::TatiffGetAll(TARIFF_CONF * conf)
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR::AdminGetAll(ADMIN_CONF  * conf)
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & NET_CONFIGURATOR::GetStrError()
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::Start()
+{
+cp.SetPort(settings.GetPort());
+cp.SetHostAllow(settings.GetHostAllow());
+cp.Start();
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::Stop()
+{
+cp.Stop();
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::Restart()
+{
+cp.Restart();
+}
+//-----------------------------------------------------------------------------
+CONF_STATUS NET_CONFIGURATOR::Status()
+{
+return cp.Status();
+}
+//-----------------------------------------------------------------------------
+BASE_SETTINGS * NET_CONFIGURATOR::GetConfiguratorSettings()
+{
+return &settings;
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::SetAdmins(const ADMINS * a)
+{
+cp.SetAdmins(a);
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/net_configurator.h b/projects/stargazer/plugins/configuration/sgconfig/net_configurator.h
new file mode 100644 (file)
index 0000000..ec1348f
--- /dev/null
@@ -0,0 +1,65 @@
+ /*
+ $Revision: 1.2 $
+ $Date: 2005/10/30 21:34:28 $
+ */
+
+#ifndef NET_CONFIGURATOR_H
+#define NET_CONFIGURATOR_H
+
+#include <time.h>
+#include <string>
+
+#include "../../base_ext_configurator.h"
+#include "../../base_int_configurator.h"
+#include "../../base_settings.h"
+#include "hostallow.h"
+#include "conffiles.h"
+#include "configproto.h"
+
+using namespace std;
+//-----------------------------------------------------------------------------
+class NET_CONFIGURATOR_SETTINGS: public BASE_SETTINGS
+{
+public:
+    virtual ~NET_CONFIGURATOR_SETTINGS(){};
+virtual const string & GetStrError();
+    virtual int ReadSettings(const CONFIGFILE & cf);
+    uint16_t    GetPort();
+    HOSTALLOW * GetHostAllow();
+
+private:
+    string strError;
+    uint16_t port;
+    HOSTALLOW hostAllow;
+};
+//-----------------------------------------------------------------------------
+class NET_CONFIGURATOR: public BASE_EXT_CONFIGURATOR
+{
+public:
+    NET_CONFIGURATOR();
+    virtual ~NET_CONFIGURATOR();
+    virtual void SetStgConfigurator(BASE_INT_CONFIGURATOR *);
+    virtual int UserGetAll(string * login, 
+                           USER_CONF_RES * conf,
+                           USER_STAT_RES * stat,
+                           time_t lastUpdate);
+    virtual int TatiffGetAll(TARIFF_CONF * conf);
+    virtual int AdminGetAll(ADMIN_CONF  * conf);
+    virtual const string & GetStrError();
+    virtual void Start();
+    virtual void Stop();
+    virtual void Restart();
+    virtual CONF_STATUS Status();
+    virtual BASE_SETTINGS * GetConfiguratorSettings();
+    virtual void SetAdmins(const ADMINS * a);
+
+private:
+    HOSTALLOW * hostAllow;
+    BASE_INT_CONFIGURATOR * stgConfigurator;
+    NET_CONFIGURATOR_SETTINGS settings;
+    string strError;
+    CONFIGPROTO cp;
+};
+//-----------------------------------------------------------------------------
+#endif //NET_CONFIGURATOR_H
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser.cpp
new file mode 100644 (file)
index 0000000..b62b292
--- /dev/null
@@ -0,0 +1,1466 @@
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sstream>
+
+#include "parser.h"
+#include "version.h"
+
+#define  UNAME_LEN      (256)
+//-----------------------------------------------------------------------------
+//  GET SERVER INFO
+//-----------------------------------------------------------------------------
+int PARSER_GET_SERVER_INFO::ParseStart(void *, const char *el, const char **)
+{
+answerList->erase(answerList->begin(), answerList->end());
+if (strcasecmp(el, "GetServerInfo") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_SERVER_INFO::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetServerInfo") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::CreateAnswer()
+{
+char s[UNAME_LEN + 128];
+char un[UNAME_LEN];
+struct utsname utsn;
+
+int tariff_type;
+
+tariff_type = 2;
+
+uname(&utsn);
+un[0] = 0;
+
+strcat(un, utsn.sysname);
+strcat(un, " ");
+strcat(un, utsn.release);
+strcat(un, " ");
+strcat(un, utsn.machine);
+strcat(un, " ");
+strcat(un, utsn.nodename);
+
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+answerList->push_back("<ServerInfo>");
+
+sprintf(s, "<version value=\"%s\"/>", SERVER_VERSION);
+answerList->push_back(s);
+
+sprintf(s, "<tariff_num value=\"%d\"/>", tariffs->GetTariffsNum());
+answerList->push_back(s);
+
+sprintf(s, "<tariff value=\"%d\"/>", 2);
+answerList->push_back(s);
+
+sprintf(s, "<users_num value=\"%d\"/>", users->GetUserNum());
+answerList->push_back(s);
+
+sprintf(s, "<uname value=\"%s\"/>", un);
+answerList->push_back(s);
+
+sprintf(s, "<dir_num value=\"%d\"/>", DIR_NUM);
+answerList->push_back(s);
+
+sprintf(s, "<day_fee value=\"%d\"/>", settings->GetDayFee());
+answerList->push_back(s);
+
+for (int i = 0; i< DIR_NUM; i++)
+    {
+    string dn2e;
+    Encode12str(dn2e, settings->GetDirName(i));
+    sprintf(s, "<dir_name_%d value=\"%s\"/>", i, dn2e.c_str());
+    answerList->push_back(s);
+    }
+
+answerList->push_back("</ServerInfo>");
+}
+//-----------------------------------------------------------------------------
+//  GET USER
+//-----------------------------------------------------------------------------
+PARSER_GET_USER::PARSER_GET_USER()
+{
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USER::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "GetUser") == 0)
+    {
+    if (attr[0] && attr[1])
+        login = attr[1];
+    else
+        {
+        //login.clear();
+        login.erase(login.begin(), login.end());
+        return -1;
+        }
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USER::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetUser") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::CreateAnswer()
+{
+string s;
+string enc;
+
+user_iter u;
+
+answerList->erase(answerList->begin(), answerList->end());
+
+if (users->FindByName(login, &u))
+    {
+    s = "<user result=\"error\"/>";
+    answerList->push_back(s);
+    return;
+    }
+
+s = "<user result=\"ok\">";
+answerList->push_back(s);
+
+s = "<login value=\"" + u->GetLogin() + "\"/>";
+answerList->push_back(s);
+
+if (currAdmin.GetPriv()->userConf || currAdmin.GetPriv()->userPasswd)
+    s = "<password value=\"" + u->property.password.Get() + "\" />";
+else
+    s = "<password value=\"++++++\"/>";
+answerList->push_back(s);
+
+strprintf(&s, "<cash value=\"%f\" />", u->property.cash.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<freemb value=\"%f\" />", u->property.freeMb.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<credit value=\"%f\" />", u->property.credit.Get());
+answerList->push_back(s);
+
+if (u->property.nextTariff.Get() != "")
+    {
+    strprintf(&s, "<tariff value=\"%s/%s\" />",
+              u->property.tariffName.Get().c_str(),
+              u->property.nextTariff.Get().c_str());
+    }
+else
+    {
+    strprintf(&s, "<tariff value=\"%s\" />",
+              u->property.tariffName.Get().c_str());
+    }
+
+answerList->push_back(s);
+
+Encode12str(enc, u->property.note);
+s = "<note value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.phone);
+s = "<phone value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.address);
+s = "<address value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.email);
+s = "<email value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+
+vector<USER_PROPERTY_LOGGED<string> *> userdata;
+userdata.push_back(u->property.userdata0.GetPointer());
+userdata.push_back(u->property.userdata1.GetPointer());
+userdata.push_back(u->property.userdata2.GetPointer());
+userdata.push_back(u->property.userdata3.GetPointer());
+userdata.push_back(u->property.userdata4.GetPointer());
+userdata.push_back(u->property.userdata5.GetPointer());
+userdata.push_back(u->property.userdata6.GetPointer());
+userdata.push_back(u->property.userdata7.GetPointer());
+userdata.push_back(u->property.userdata8.GetPointer());
+userdata.push_back(u->property.userdata9.GetPointer());
+
+string tmpI;
+for (unsigned i = 0; i < userdata.size(); i++)
+    {
+    Encode12str(enc, userdata[i]->Get());
+    s = "<UserData" + x2str(i, tmpI) + " value=\"" + enc + "\" />";
+    answerList->push_back(s);
+    }
+
+Encode12str(enc, u->property.realName);
+s = "<name value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.group);
+s = "<GROUP value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+strprintf(&s, "<status value=\"%d\" />", u->GetConnected());
+answerList->push_back(s);
+
+strprintf(&s, "<aonline value=\"%d\" />", u->property.alwaysOnline.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<currip value=\"%s\" />", inet_ntostring(u->GetCurrIP()).c_str());
+answerList->push_back(s);
+
+strprintf(&s, "<PingTime value=\"%lu\" />", u->GetPingTime());
+answerList->push_back(s);
+
+stringstream sstr;
+sstr << u->property.ips.Get();
+strprintf(&s, "<ip value=\"%s\" />", sstr.str().c_str());
+answerList->push_back(s);
+
+char * ss;
+ss = new char[DIR_NUM*25*4 + 50];
+char st[50];
+sprintf(ss, "<traff");
+DIR_TRAFF upload;
+DIR_TRAFF download;
+download = u->property.down.Get();
+upload = u->property.up.Get();
+
+for (int j = 0; j < DIR_NUM; j++)
+    {
+    string s;
+    x2str(upload[j], s);
+    sprintf(st, " MU%d=\"%s\"", j, s.c_str());
+    strcat(ss, st);
+
+    x2str(download[j], s);
+    sprintf(st, " MD%d=\"%s\"", j, s.c_str());
+    strcat(ss, st);
+
+    sprintf(st, " SU%d=\"0\"", j);
+    strcat(ss, st);
+
+    sprintf(st, " SD%d=\"0\"", j);
+    strcat(ss, st);
+    }
+strcat(ss, " />");
+answerList->push_back(ss);
+delete[] ss;
+
+strprintf(&s, "<down value=\"%d\" />", u->property.disabled.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<DisableDetailStat value=\"%d\" />", u->property.disabledDetailStat.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<passive value=\"%d\" />", u->property.passive.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<LastCash value=\"%f\" />", u->property.lastCashAdd.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<LastTimeCash value=\"%ld\" />", u->property.lastCashAddTime.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<LastActivityTime value=\"%ld\" />", u->property.lastActivityTime.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<CreditExpire value=\"%ld\" />", u->property.creditExpire.Get());
+answerList->push_back(s);
+
+strprintf(&s, "</user>");
+answerList->push_back(s);
+}
+//-----------------------------------------------------------------------------
+//  GET USERS
+//-----------------------------------------------------------------------------
+PARSER_GET_USERS::PARSER_GET_USERS()
+{
+lastUserUpdateTime = 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USERS::ParseStart(void *, const char *el, const char ** attr)
+{
+/*if (attr && *attr && *(attr+1))
+    {
+    printfd(__FILE__, "attr=%s %s\n", *attr, *(attr+1));
+    }
+else
+    {
+    printfd(__FILE__, "attr = NULL\n");
+    }*/
+
+lastUpdateFound = false;
+if (strcasecmp(el, "GetUsers") == 0)
+    {
+    while (attr && *attr && *(attr+1))
+        {
+        if (strcasecmp(*attr, "LastUpdate") == 0)
+            {
+            if (str2x(*(attr+1), lastUserUpdateTime) == 0)
+                {
+                //printfd(__FILE__, "lastUserUpdateTime=%d\n", lastUserUpdateTime);
+                lastUpdateFound = true;
+                }
+            else
+                {
+                //printfd(__FILE__, "NO lastUserUpdateTime\n");
+                }
+            }
+        ++attr;
+        }
+
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USERS::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetUsers") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::CreateAnswer()
+{
+answerList->erase(answerList->begin(), answerList->end());
+
+string s;
+string userStart;
+string traffStart;
+string traffMiddle;
+string traffFinish;
+string middle;
+string userFinish;
+
+
+string enc;
+
+user_iter u;
+
+int h = users->OpenSearch();
+if (!h)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    users->CloseSearch(h);
+    return;
+    }
+string updateTime;
+x2str(time(NULL), updateTime);
+
+if (lastUpdateFound)
+    answerList->push_back("<Users LastUpdate=\"" + updateTime + "\">");
+else
+    answerList->push_back("<Users>");
+
+while (1)
+    {
+    if (users->SearchNext(h, &u))
+        {
+        break;
+        }
+    userStart = "<user login=\"" + u->GetLogin() + "\">";
+    middle = "";
+
+    if (u->property.password.ModificationTime() > lastUserUpdateTime)
+        {
+        if (currAdmin.GetPriv()->userConf || currAdmin.GetPriv()->userPasswd)
+            s = "<password value=\"" + u->property.password.Get() + "\" />";
+        else
+            s = "<password value=\"++++++\"/>";
+        middle += s;
+        }
+
+
+    if (u->property.cash.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<cash value=\"%f\" />", u->property.cash.Get());
+        middle += s;
+        //printfd(__FILE__, "cash value=\"%f\"\n", u->property.cash.Get());
+        }
+
+
+    if (u->property.freeMb.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<freemb value=\"%f\" />", u->property.freeMb.Get());
+        middle += s;
+        }
+
+    if (u->property.credit.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<credit value=\"%f\" />", u->property.credit.Get());
+        middle += s;
+        }
+
+    if (u->property.nextTariff.Get() != "")
+        {
+        if (u->property.tariffName.ModificationTime() > lastUserUpdateTime
+            || u->property.nextTariff.ModificationTime() > lastUserUpdateTime)
+            {
+            strprintf(&s, "<tariff value=\"%s/%s\" />",
+                      u->property.tariffName.Get().c_str(),
+                      u->property.nextTariff.Get().c_str());
+            middle += s;
+            }
+        }
+    else
+        {
+        if (u->property.tariffName.ModificationTime() > lastUserUpdateTime)
+            {
+            strprintf(&s, "<tariff value=\"%s\" />",
+                      u->property.tariffName.Get().c_str());
+            middle += s;
+            }
+        }
+
+    if (u->property.note.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.note);
+        strprintf(&s, "<note value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.phone.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.phone);
+        strprintf(&s, "<phone value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.address.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.address);
+        strprintf(&s, "<address value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.email.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.email);
+        strprintf(&s, "<email value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    vector<USER_PROPERTY_LOGGED<string> *> userdata;
+    userdata.push_back(u->property.userdata0.GetPointer());
+    userdata.push_back(u->property.userdata1.GetPointer());
+    userdata.push_back(u->property.userdata2.GetPointer());
+    userdata.push_back(u->property.userdata3.GetPointer());
+    userdata.push_back(u->property.userdata4.GetPointer());
+    userdata.push_back(u->property.userdata5.GetPointer());
+    userdata.push_back(u->property.userdata6.GetPointer());
+    userdata.push_back(u->property.userdata7.GetPointer());
+    userdata.push_back(u->property.userdata8.GetPointer());
+    userdata.push_back(u->property.userdata9.GetPointer());
+
+    string tmpI;
+    for (unsigned i = 0; i < userdata.size(); i++)
+        {
+        if (userdata[i]->ModificationTime() > lastUserUpdateTime)
+            {
+            Encode12str(enc, userdata[i]->Get());
+            s = "<UserData" + x2str(i, tmpI) + " value=\"" + enc + "\" />";
+            middle += s;
+            }
+        }
+
+    if (u->property.realName.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.realName);
+        strprintf(&s, "<name value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.group.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.group);
+        strprintf(&s, "<GROUP value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.alwaysOnline.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<aonline value=\"%d\" />", u->property.alwaysOnline.Get());
+        middle += s;
+        }
+
+    if (u->GetCurrIPModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<currip value=\"%s\" />", inet_ntostring(u->GetCurrIP()).c_str());
+        middle += s;
+        }
+
+
+    if (u->GetConnectedModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<status value=\"%d\" />", u->GetConnected());
+        middle += s;
+        }
+
+    if (u->GetPingTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<PingTime value=\"%lu\" />", u->GetPingTime());
+        middle += s;
+        }
+
+    if (u->property.ips.ModificationTime() > lastUserUpdateTime)
+        {
+        stringstream sstr;
+        sstr << u->property.ips.Get();
+        strprintf(&s, "<ip value=\"%s\" />", sstr.str().c_str());
+        middle += s;
+        }
+
+    char st[50];
+    traffStart = "<traff";
+    DIR_TRAFF upload;
+    DIR_TRAFF download;
+    download = u->property.down.Get();
+    upload = u->property.up.Get();
+    traffMiddle = "";
+
+    if (u->property.up.ModificationTime() > lastUserUpdateTime)
+        {
+        for (int j = 0; j < DIR_NUM; j++)
+            {
+            string s;
+            x2str(upload[j], s);
+            sprintf(st, " MU%d=\"%s\" ", j, s.c_str());
+            traffMiddle += st;
+            }
+        }
+
+    if (u->property.down.ModificationTime() > lastUserUpdateTime)
+        {
+        for (int j = 0; j < DIR_NUM; j++)
+            {
+            x2str(download[j], s);
+            sprintf(st, " MD%d=\"%s\" ", j, s.c_str());
+            traffMiddle += st;
+            }
+        }
+
+    traffFinish = " />";
+    if (traffMiddle.length() > 0)
+        {
+        middle += traffStart;
+        middle += traffMiddle;
+        middle += traffFinish;
+        }
+
+    if (u->property.disabled.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<down value=\"%d\" />", u->property.disabled.Get());
+        middle += s;
+        }
+
+    if (u->property.disabledDetailStat.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<DisableDetailStat value=\"%d\" />", u->property.disabledDetailStat.Get());
+        middle += s;
+        }
+
+    //printfd(__FILE__, ">>>>> %s\n", s.c_str());
+
+    if (u->property.passive.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<passive value=\"%d\" />", u->property.passive.Get());
+        middle += s;
+        }
+
+    if (u->property.lastCashAdd.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<LastCash value=\"%f\" />", u->property.lastCashAdd.Get());
+        middle += s;
+        }
+
+    if (u->property.lastCashAddTime.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<LastTimeCash value=\"%ld\" />", u->property.lastCashAddTime.Get());
+        middle += s;
+        }
+
+
+    if (u->property.lastActivityTime.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<LastActivityTime value=\"%ld\" />", u->property.lastActivityTime.Get());
+        middle += s;
+        }
+
+    if (u->property.creditExpire.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<CreditExpire value=\"%ld\" />", u->property.creditExpire.Get());
+        middle += s;
+        }
+
+
+    userFinish = "</user>";
+
+    if (middle.length() > 0)
+        {
+        /*printfd(__FILE__, "login: %s\n", u->GetLogin().c_str());
+        printfd(__FILE__, "middle: %s\n", middle.c_str());*/
+
+        answerList->push_back(userStart);
+        answerList->push_back(middle);
+        answerList->push_back(userFinish);
+        }
+    }
+
+users->CloseSearch(h);
+
+//answerList->push_back("</Users>");
+
+answerList->push_back("</Users>");
+}
+//-----------------------------------------------------------------------------
+//  ADD USER
+//-----------------------------------------------------------------------------
+PARSER_ADD_USER::PARSER_ADD_USER()
+{
+depth = 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_USER::ParseStart(void *, const char *el, const char **attr)
+{
+depth++;
+
+if (depth == 1)
+    {
+    if (strcasecmp(el, "AddUser") == 0)
+        {
+        return 0;
+        }
+    }
+else
+    {
+    if (strcasecmp(el, "login") == 0)
+        {
+        login = attr[1];
+        return 0;
+        }
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_USER::ParseEnd(void *, const char *el)
+{
+if (depth == 1)
+    {
+    if (strcasecmp(el, "AddUser") == 0)
+        {
+        CreateAnswer();
+        depth--;
+        return 0;
+        }
+    }
+
+depth--;
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_USER::Reset()
+{
+BASE_PARSER::Reset();
+depth = 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_USER::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (CheckUserData() == 0)
+    {
+    answerList->push_back("<AddUser result=\"ok\"/>");
+    }
+else
+    {
+    answerList->push_back("<AddUser result=\"error\" reason=\"Access denied\"/>");
+    }
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_USER::CheckUserData()
+{
+user_iter u;
+if (users->FindByName(login, &u))
+    {
+    return users->Add(login, currAdmin);
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+//  PARSER CHG USER
+//-----------------------------------------------------------------------------
+PARSER_CHG_USER::PARSER_CHG_USER()
+{
+usr = NULL;
+ucr = NULL;
+upr = NULL;
+downr = NULL;
+
+Reset();
+}
+//-----------------------------------------------------------------------------
+PARSER_CHG_USER::~PARSER_CHG_USER()
+{
+delete usr;
+delete ucr;
+delete[] upr;
+delete[] downr;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::Reset()
+{
+depth = 0;
+delete usr;
+
+delete ucr;
+
+delete[] upr;
+
+delete[] downr;
+
+usr = new USER_STAT_RES;
+ucr = new USER_CONF_RES;
+
+upr = new RESETABLE<uint64_t>[DIR_NUM];
+downr = new RESETABLE<uint64_t>[DIR_NUM];
+};
+//-----------------------------------------------------------------------------
+string PARSER_CHG_USER::EncChar2String(const char * strEnc)
+{
+string str;
+Decode21str(str, strEnc);
+return str;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::ParseStart(void *, const char *el, const char **attr)
+{
+depth++;
+
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetUser") == 0)
+        {
+        return 0;
+        }
+    }
+else
+    {
+    //printfd(__FILE__, "el=%s\n", el);
+    if (strcasecmp(el, "login") == 0)
+        {
+        login = attr[1];
+        return 0;
+        }
+
+    if (strcasecmp(el, "ip") == 0)
+        {
+        try
+            {
+            ucr->ips = StrToIPS(attr[1]);
+            }
+        catch (...)
+            {
+            printfd(__FILE__, "StrToIPS Error!\n");
+            }
+        }
+
+    if (strcasecmp(el, "password") == 0)
+        {
+        ucr->password = attr[1];
+        return 0;
+        }
+
+    if (strcasecmp(el, "address") == 0)
+        {
+        ucr->address = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "aonline") == 0)
+        {
+        ucr->alwaysOnline = (*(attr[1]) != '0');
+        return 0;
+        }
+
+    if (strcasecmp(el, "cash") == 0)
+        {
+        if (attr[2] && (strcasecmp(attr[2], "msg") == 0))
+            {
+            cashMsg = EncChar2String(attr[3]);
+            }
+
+        double cash;
+        if (strtodouble2(attr[1], cash) == 0)
+            usr->cash = cash;
+
+        if (strcasecmp(attr[0], "set") == 0)
+            cashMustBeAdded = false;
+
+        if (strcasecmp(attr[0], "add") == 0)
+            cashMustBeAdded = true;
+
+        return 0;
+        }
+
+    if (strcasecmp(el, "CreditExpire") == 0)
+        {
+        long int creditExpire = 0;
+        if (str2x(attr[1], creditExpire) == 0)
+            ucr->creditExpire = (time_t)creditExpire;
+
+        return 0;
+        }
+
+    if (strcasecmp(el, "credit") == 0)
+        {
+        double credit;
+        if (strtodouble2(attr[1], credit) == 0)
+            ucr->credit = credit;
+        return 0;
+        }
+
+    if (strcasecmp(el, "freemb") == 0)
+        {
+        double freeMb;
+        if (strtodouble2(attr[1], freeMb) == 0)
+            usr->freeMb = freeMb;
+        return 0;
+        }
+
+    if (strcasecmp(el, "down") == 0)
+        {
+        int down = 0;
+        if (str2x(attr[1], down) == 0)
+            ucr->disabled = down;
+        return 0;
+        }
+
+    if (strcasecmp(el, "DisableDetailStat") == 0)
+        {
+        int disabledDetailStat = 0;
+        if (str2x(attr[1], disabledDetailStat) == 0)
+            ucr->disabledDetailStat = disabledDetailStat;
+        return 0;
+        }
+
+    if (strcasecmp(el, "email") == 0)
+        {
+        ucr->email = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    for (int i = 0; i < USERDATA_NUM; i++)
+        {
+        char name[15];
+        sprintf(name, "userdata%d", i);
+        if (strcasecmp(el, name) == 0)
+            {
+            ucr->userdata[i] = EncChar2String(attr[1]);
+            return 0;
+            }
+        }
+
+    if (strcasecmp(el, "group") == 0)
+        {
+        ucr->group = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "note") == 0)
+        {
+        ucr->note = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "passive") == 0)
+        {
+        int passive = 0;
+        if (str2x(attr[1], passive) == 0)
+            ucr->passive = passive;
+        return 0;
+        }
+
+    if (strcasecmp(el, "phone") == 0)
+        {
+        ucr->phone = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "Name") == 0)
+        {
+        ucr->realName = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "traff") == 0)
+        {
+        int j = 0;
+        int dir;
+        DIR_TRAFF dtu;
+        DIR_TRAFF dtd;
+        unsigned long long t = 0;
+        while (attr[j])
+            {
+            dir = attr[j][2] - '0';
+
+            if (strncasecmp(attr[j], "md", 2) == 0)
+                {
+                str2x(attr[j+1], t);
+                dtd[dir] = t;
+                downr[dir] = t;
+                }
+            if (strncasecmp(attr[j], "mu", 2) == 0)
+                {
+                str2x(attr[j+1], t);
+                dtu[dir] = t;
+                upr[dir] = t;
+                }
+            j+=2;
+            }
+        usr->down = dtd;
+        usr->up = dtu;
+        return 0;
+        }
+
+    if (strcasecmp(el, "tariff") == 0)
+        {
+        if (strcasecmp(attr[0], "now") == 0)
+            ucr->tariffName = attr[1];
+
+        if (strcasecmp(attr[0], "delayed") == 0)
+            ucr->nextTariff = attr[1];
+
+        return 0;
+        }
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::ParseEnd(void *, const char *el)
+{
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetUser") == 0)
+        {
+        AplayChanges();
+        CreateAnswer();
+        depth--;
+        return 0;
+        }
+    }
+
+depth--;
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+switch (res)
+    {
+    case 0:
+        answerList->push_back("<SetUser result=\"ok\"/>");
+        break;
+    case -1:
+        answerList->push_back("<SetUser result=\"error\"/>");
+        break;
+    case -2:
+        answerList->push_back("<SetUser result=\"error\"/>");
+        break;
+    default:
+        answerList->push_back("<SetUser result=\"error\"/>");
+        break;
+    }
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::CheckUserData()
+{
+return true;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::AplayChanges()
+{
+user_iter u;
+
+res = 0;
+if (users->FindByName(login, &u))
+    {
+    res = -1;
+    return -1;
+    }
+
+if (!ucr->ips.res_empty())
+    if (!u->property.ips.Set(ucr->ips.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->address.res_empty())
+    if (!u->property.address.Set(ucr->address.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->alwaysOnline.res_empty())
+    if (!u->property.alwaysOnline.Set(ucr->alwaysOnline.const_data(),
+                                      currAdmin, login, store))
+        res = -1;
+
+if (!ucr->creditExpire.res_empty())
+    if (!u->property.creditExpire.Set(ucr->creditExpire.const_data(),
+                                      currAdmin, login, store))
+        res = -1;
+
+if (!ucr->credit.res_empty())
+    if (!u->property.credit.Set(ucr->credit.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!usr->freeMb.res_empty())
+    if (!u->property.freeMb.Set(usr->freeMb.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->disabled.res_empty())
+    if (!u->property.disabled.Set(ucr->disabled.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->disabledDetailStat.res_empty())
+    if (!u->property.disabledDetailStat.Set(ucr->disabledDetailStat.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->email.res_empty())
+    if (!u->property.email.Set(ucr->email.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->group.res_empty())
+    if (!u->property.group.Set(ucr->group.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->note.res_empty())
+    if (!u->property.note.Set(ucr->note.const_data(), currAdmin, login, store))
+        res = -1;
+
+vector<USER_PROPERTY_LOGGED<string> *> userdata;
+userdata.push_back(u->property.userdata0.GetPointer());
+userdata.push_back(u->property.userdata1.GetPointer());
+userdata.push_back(u->property.userdata2.GetPointer());
+userdata.push_back(u->property.userdata3.GetPointer());
+userdata.push_back(u->property.userdata4.GetPointer());
+userdata.push_back(u->property.userdata5.GetPointer());
+userdata.push_back(u->property.userdata6.GetPointer());
+userdata.push_back(u->property.userdata7.GetPointer());
+userdata.push_back(u->property.userdata8.GetPointer());
+userdata.push_back(u->property.userdata9.GetPointer());
+
+for (int i = 0; i < (int)userdata.size(); i++)
+    {
+    if (!ucr->userdata[i].res_empty())
+        {
+        if(!userdata[i]->Set(ucr->userdata[i].const_data(), currAdmin, login, store))
+            res = -1;
+        }
+    }
+
+if (!ucr->passive.res_empty())
+    if (!u->property.passive.Set(ucr->passive.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->password.res_empty())
+    if (!u->property.password.Set(ucr->password.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->phone.res_empty())
+    if (!u->property.phone.Set(ucr->phone.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->realName.res_empty())
+    if (!u->property.realName.Set(ucr->realName.const_data(), currAdmin, login, store))
+        res = -1;
+
+
+if (!usr->cash.res_empty())
+    {
+    //if (currAdmin->GetPriv()->userCash)
+        {
+        if (cashMustBeAdded)
+            {
+            if (!u->property.cash.Set(usr->cash.const_data() + u->property.cash,
+                                      currAdmin,
+                                      login,
+                                      store,
+                                      cashMsg))
+                res = -1;
+            }
+        else
+            {
+            if (!u->property.cash.Set(usr->cash.const_data(), currAdmin, login, store, cashMsg))
+                res = -1;
+            }
+        }
+    }
+
+
+if (!ucr->tariffName.res_empty())
+    {
+    if (tariffs->FindByName(ucr->tariffName.const_data()))
+        {
+        if (!u->property.tariffName.Set(ucr->tariffName.const_data(), currAdmin, login, store))
+            res = -1;
+        u->ResetNextTariff();
+        }
+    else
+        {
+        //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
+        res = -1;
+        }
+    }
+
+if (!ucr->nextTariff.res_empty())
+    {
+    if (tariffs->FindByName(ucr->nextTariff.const_data()))
+        {
+        if (!u->property.nextTariff.Set(ucr->nextTariff.const_data(), currAdmin, login, store))
+            res = -1;
+        }
+    else
+        {
+        //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
+        res = -1;
+        }
+    }
+
+DIR_TRAFF up = u->property.up;
+DIR_TRAFF down = u->property.down;
+int upCount = 0;
+int downCount = 0;
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    if (!upr[i].res_empty())
+        {
+        up[i] = upr[i];
+        upCount++;
+        }
+    if (!downr[i].res_empty())
+        {
+        down[i] = downr[i];
+        downCount++;
+        }
+    }
+
+if (upCount)
+    if (!u->property.up.Set(up, currAdmin, login, store))
+        res = -1;
+
+if (downCount)
+    if (!u->property.down.Set(down, currAdmin, login, store))
+        res = -1;
+
+/*if (!usr->down.res_empty())
+    {
+    u->property.down.Set(usr->down.const_data(), currAdmin, login, store);
+    }
+if (!usr->up.res_empty())
+    {
+    u->property.up.Set(usr->up.const_data(), currAdmin, login, store);
+    }*/
+
+u->WriteConf();
+u->WriteStat();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//      SEND MESSAGE
+//-----------------------------------------------------------------------------
+int PARSER_SEND_MESSAGE::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "Message") == 0)
+    {
+    for (int i = 0; i < 14; i++)
+        {
+        if (attr[i] == NULL)
+            {
+            result = res_params_error;
+            CreateAnswer();
+            printfd(__FILE__, "To few parameters\n");
+            return 0;
+            }
+        }
+
+    for (int i = 0; i < 14; i+=2)
+        {
+        if (strcasecmp(attr[i], "login") == 0)
+            {
+            ParseLogins(attr[i+1]);
+            /*if (users->FindByName(login, &u))
+                {
+                result = res_unknown;
+                break;
+                }*/
+            }
+
+        if (strcasecmp(attr[i], "MsgVer") == 0)
+            {
+            str2x(attr[i+1], msg.header.ver);
+            if (msg.header.ver != 1)
+                result = res_params_error;
+            }
+
+        if (strcasecmp(attr[i], "MsgType") == 0)
+            {
+            str2x(attr[i+1], msg.header.type);
+            if (msg.header.type != 1)
+                result = res_params_error;
+            }
+
+        if (strcasecmp(attr[i], "Repeat") == 0)
+            {
+            str2x(attr[i+1], msg.header.repeat);
+            if (msg.header.repeat < 0)
+                result = res_params_error;
+            }
+
+        if (strcasecmp(attr[i], "RepeatPeriod") == 0)
+            {
+            str2x(attr[i+1], msg.header.repeatPeriod);
+            }
+
+        if (strcasecmp(attr[i], "ShowTime") == 0)
+            {
+            str2x(attr[i+1], msg.header.showTime);
+            }
+
+        if (strcasecmp(attr[i], "Text") == 0)
+            {
+            Decode21str(msg.text, attr[i+1]);
+            result = res_ok;
+            }
+        }
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_SEND_MESSAGE::ParseEnd(void *, const char *el)
+{
+//MSG msg;
+if (strcasecmp(el, "Message") == 0)
+    {
+    result = res_unknown;
+    for (unsigned i = 0; i < logins.size(); i++)
+        {
+        if (users->FindByName(logins[i], &u))
+            {
+            printfd(__FILE__, "User not found. %s\n", logins[i].c_str());
+            continue;
+            }
+        msg.header.creationTime = stgTime;
+        u->AddMessage(&msg);
+        result = res_ok;
+        }
+    /*if (result == res_ok)
+        {
+        if (strcmp(login, "*") == 0)
+            {
+            msg.text = text;
+            msg.prio = pri;
+            printfd(__FILE__, "SendMsg text: %s\n", text);
+            users->GetAllUsers(SendMessageAllUsers, &msg);
+            }
+        else
+            {
+            u->AddMessage(pri, text);
+            }
+        }*/
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_SEND_MESSAGE::ParseLogins(const char * login)
+{
+char * p;
+char * l = new char[strlen(login) + 1];
+strcpy(l, login);
+p = strtok(l, ":");
+logins.clear();
+while(p)
+    {
+    logins.push_back(p);
+    p = strtok(NULL, ":");
+    }
+
+delete[] l;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_SEND_MESSAGE::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+//answerList->push_back("<SendMessageResult value=\"ok\"/>");
+//
+switch (result)
+    {
+    case res_ok:
+        answerList->push_back("<SendMessageResult value=\"ok\"/>");
+        break;
+    case res_params_error:
+        printfd(__FILE__, "res_params_error\n");
+        answerList->push_back("<SendMessageResult value=\"Parameters error\"/>");
+        break;
+    case res_unknown:
+        printfd(__FILE__, "res_unknown\n");
+        answerList->push_back("<SendMessageResult value=\"Unknown user\"/>");
+        break;
+    default:
+        printfd(__FILE__, "res_default\n");
+    }
+
+}
+//-----------------------------------------------------------------------------
+//      DEL USER
+//-----------------------------------------------------------------------------
+int PARSER_DEL_USER::ParseStart(void *, const char *el, const char **attr)
+{
+res = 0;
+if (strcasecmp(el, "DelUser") == 0)
+    {
+    if (attr[0] == NULL || attr[1] == NULL)
+        {
+        //CreateAnswer("Parameters error!");
+        CreateAnswer();
+        return 0;
+        }
+
+    if (users->FindByName(attr[1], &u))
+        {
+        res = 1;
+        CreateAnswer();
+        return 0;
+        }
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_USER::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "DelUser") == 0)
+    {
+    if (!res)
+        users->Del(u->GetLogin(), currAdmin);
+
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_DEL_USER::CreateAnswer()
+{
+if (res)
+    answerList->push_back("<DelUser value=\"error\" reason=\"User not found\"/>");
+else
+    answerList->push_back("<DelUser value=\"ok\"/>");
+}
+//-----------------------------------------------------------------------------
+/*void PARSERDELUSER::CreateAnswer(char * mes)
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+char str[255];
+sprintf(str, "<DelUser value=\"%s\"/>", mes);
+answerList->push_back(str);
+}*/
+//-----------------------------------------------------------------------------
+//  CHECK USER
+// <checkuser login="vasya" password=\"123456\"/>
+//-----------------------------------------------------------------------------
+int PARSER_CHECK_USER::ParseStart(void *, const char *el, const char **attr)
+{
+result = false;
+
+if (strcasecmp(el, "CheckUser") == 0)
+    {
+    if (attr[0] == NULL || attr[1] == NULL
+     || attr[2] == NULL || attr[3] == NULL)
+        {
+        result = false;
+        CreateAnswer();
+        printfd(__FILE__, "PARSER_CHECK_USER - attr err\n");
+        return 0;
+        }
+
+    user_iter user;
+    if (users->FindByName(attr[1], &user))
+        {
+        result = false;
+        CreateAnswer();
+        printfd(__FILE__, "PARSER_CHECK_USER - login err\n");
+        return 0;
+        }
+
+    if (strcmp(user->property.password.Get().c_str(), attr[3]))
+        {
+        result = false;
+        CreateAnswer();
+        printfd(__FILE__, "PARSER_CHECK_USER - passwd err\n");
+        return 0;
+        }
+
+    result = true;
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHECK_USER::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "CheckUser") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHECK_USER::CreateAnswer()
+{
+if (result)
+    answerList->push_back("<CheckUser value=\"Ok\"/>");
+else
+    answerList->push_back("<CheckUser value=\"Err\"/>");
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser.h b/projects/stargazer/plugins/configuration/sgconfig/parser.h
new file mode 100644 (file)
index 0000000..4930db0
--- /dev/null
@@ -0,0 +1,257 @@
+ /*
+ $Revision: 1.20 $
+ $Date: 2010/10/04 20:26:10 $
+ $Author: faust $
+ */
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <list>
+#include <string>
+
+#include "resetable.h"
+#include "stg_const.h"
+#include "base_store.h"
+#include "../../../admins.h"
+#include "../../../users.h"
+#include "stg_message.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+class BASE_PARSER
+{
+public:
+    BASE_PARSER()
+        : admins(NULL),
+          users(NULL),
+          tariffs(NULL),
+          store(NULL),
+          settings(NULL),
+          currAdmin(),
+          depth(0)
+    { };
+    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 CreateAnswer() = 0;
+    virtual void SetAnswerList(list<string> * ansList) { answerList = ansList; };
+
+    virtual void SetUsers(USERS * u) { users = u; };
+    virtual void SetAdmins(ADMINS * a) { admins = a; };
+    virtual void SetTariffs(TARIFFS * t) { tariffs = t; };
+    virtual void SetStore(BASE_STORE * s) { store = s; };
+    virtual void SetStgSettings(const SETTINGS * s) { settings = s; };
+
+    virtual void SetCurrAdmin(const ADMIN & cua) { currAdmin = cua; };
+    virtual string & GetStrError(){return strError;};
+    virtual void Reset(){ answerList->clear(); depth = 0; };
+protected:
+    string           strError;
+    ADMINS *         admins;
+    USERS *          users;
+    TARIFFS *        tariffs;
+    BASE_STORE *     store;
+    const SETTINGS * settings;
+    ADMIN            currAdmin;
+    int              depth;
+    list<string> *   answerList;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_ADMINS: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+};
+//-----------------------------------------------------------------------------
+class PARSER_ADD_ADMIN: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+private:
+    string adminToAdd;
+};
+//-----------------------------------------------------------------------------
+class PARSER_DEL_ADMIN: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+private:
+    int CheckAttr(const char **attr);
+    string adminToDel;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_ADMIN: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+private:
+    RESETABLE<string>   login;
+    RESETABLE<string>   password;
+    RESETABLE<string>   privAsString;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_SERVER_INFO: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+};
+
+//-----------------------------------------------------------------------------
+class PARSER_GET_USER: public BASE_PARSER
+{
+public:
+            PARSER_GET_USER();
+            ~PARSER_GET_USER(){};
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    string  login;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_USERS: public BASE_PARSER
+{
+public:
+            PARSER_GET_USERS();
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    time_t  lastUserUpdateTime;
+    bool    lastUpdateFound;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_TARIFFS: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+};
+//-----------------------------------------------------------------------------
+class PARSER_ADD_TARIFF: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    string  tariffToAdd;
+};
+//-----------------------------------------------------------------------------
+class PARSER_DEL_TARIFF: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    string  tariffToDel;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_TARIFF: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    int     ParseSlashedIntParams(int paramsNum, const string & s, int * params);
+    int     ParseSlashedDoubleParams(int paramsNum, const string & s, double * params);
+    int     CheckTariffData();
+    int     AplayChanges();
+
+    TARIFF_DATA_RES td;
+};
+//-----------------------------------------------------------------------------/
+class PARSER_ADD_USER: public BASE_PARSER
+{
+public:
+            PARSER_ADD_USER();
+    virtual ~PARSER_ADD_USER(){};
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+    void    Reset();
+private:
+    int     CheckUserData();
+    string  login;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_USER: public BASE_PARSER
+{
+public:
+                    PARSER_CHG_USER();
+                    ~PARSER_CHG_USER();
+    int             ParseStart(void *data, const char *el, const char **attr);
+    int             ParseEnd(void *data, const char *el);
+    void            CreateAnswer();
+    void            Reset();
+private:
+    string          EncChar2String(const char *);
+
+    USER_STAT_RES * usr;
+    USER_CONF_RES * ucr;
+    RESETABLE<uint64_t> * upr;
+    RESETABLE<uint64_t> * downr;
+    string          cashMsg;
+    string          login;
+
+    int             CheckUserData();
+    int             AplayChanges();
+    bool            cashMustBeAdded;
+    int             res;
+};
+//-----------------------------------------------------------------------------
+class PARSER_DEL_USER: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+
+private:
+    int         res;
+    user_iter   u;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHECK_USER: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    bool    result;
+};
+//-----------------------------------------------------------------------------
+class PARSER_SEND_MESSAGE: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    enum {res_ok, res_params_error, res_unknown};
+    vector<string> logins;
+    int     ParseLogins(const char * logins);
+    int     result;
+    STG_MSG msg;
+    user_iter u;
+};
+//-----------------------------------------------------------------------------
+#endif //PARSER_H
+
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_admin.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser_admin.cpp
new file mode 100644 (file)
index 0000000..160acc8
--- /dev/null
@@ -0,0 +1,265 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "parser.h"
+
+//-----------------------------------------------------------------------------
+//  GET ADMINS
+//-----------------------------------------------------------------------------
+int PARSER_GET_ADMINS::ParseStart(void *, const char *el, const char **)
+{
+if (strcasecmp(el, "GetAdmins") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_ADMINS::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetAdmins") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_ADMINS::CreateAnswer()
+{
+const PRIV * priv = currAdmin.GetPriv();
+if (!priv->adminChg)
+    {
+    //answerList->clear();
+    answerList->erase(answerList->begin(), answerList->end());
+
+    answerList->push_back("<Error Result=\"Error. Access denied.\"/>");
+    return;
+    }
+
+string s;
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+answerList->push_back("<Admins>");
+ADMIN_CONF ac;
+int h = admins->OpenSearch();
+
+unsigned int p;
+while (admins->SearchNext(h, &ac) == 0)
+    {
+    //memcpy(&p, &ac.priv, sizeof(unsigned int));
+    p = (ac.priv.userStat << 0) +
+        (ac.priv.userConf << 2) +
+        (ac.priv.userCash << 4) +
+        (ac.priv.userPasswd << 6) +
+        (ac.priv.userAddDel << 8) +
+        (ac.priv.adminChg << 10) +
+        (ac.priv.tariffChg << 12);
+    strprintf(&s, "<admin login=\"%s\" priv=\"%d\"/>", ac.login.c_str(), p);
+    answerList->push_back(s);
+    }
+admins->CloseSearch(h);
+answerList->push_back("</Admins>");
+}
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+//  DEL ADMIN
+//-----------------------------------------------------------------------------
+int PARSER_DEL_ADMIN::ParseStart(void *, const char *el, const char **attr)
+{
+strError = "";
+if (strcasecmp(el, "DelAdmin") == 0)
+    {
+    adminToDel = attr[1];
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_ADMIN::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "DelAdmin") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_DEL_ADMIN::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (admins->Del(adminToDel, currAdmin) == 0)
+    {
+    answerList->push_back("<DelAdmin Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<DelAdmin Result=\"Error. %s\"/>", admins->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_ADMIN::CheckAttr(const char **attr)
+{
+/*  <DelAdmin login=\"admin\">
+ *  attr[0] = "login" (word login)
+ *  attr[1] = login, value of login
+ *  attr[2] = NULL                  */
+
+if (strcasecmp(attr[0], "login") == 0 && attr[1] && !attr[2])
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+//  ADD ADMIN
+//-----------------------------------------------------------------------------
+int PARSER_ADD_ADMIN::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "AddAdmin") == 0)
+    {
+    adminToAdd = attr[1];
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_ADMIN::ParseEnd(void *, const char *el)
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (strcasecmp(el, "AddAdmin") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_ADMIN::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (admins->Add(adminToAdd, currAdmin) == 0)
+    {
+    answerList->push_back("<AddAdmin Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<AddAdmin Result=\"Error. %s\"/>", admins->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//  CHG ADMIN
+//-----------------------------------------------------------------------------
+int PARSER_CHG_ADMIN::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "ChgAdmin") == 0)
+    {
+    for (int i = 0; i < 6; i+=2)
+        {
+        printfd(__FILE__, "PARSER_CHG_ADMIN::attr[%d] = %s\n", i, attr[i]);
+        if (attr[i] == NULL)
+            break;
+
+        if (strcasecmp(attr[i], "Login") == 0)
+            {
+            login = attr[i + 1];
+            continue;
+            }
+
+        if (strcasecmp(attr[i], "Priv") == 0)
+            {
+            privAsString = attr[i + 1];
+            continue;
+            }
+
+        if (strcasecmp(attr[i], "Password") == 0)
+            {
+            password = attr[i + 1];
+            continue;
+            }
+        }
+
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_ADMIN::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "ChgAdmin") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_ADMIN::CreateAnswer()
+{
+answerList->erase(answerList->begin(), answerList->end());
+
+ADMIN_CONF conf;
+conf.login = login;
+if (!login.res_empty())
+    {
+    string s;
+    //if (admins->FindAdmin(login.data()) != NULL)
+    //    {
+        if (!password.res_empty())
+            conf.password = password.data();
+
+        if (!privAsString.res_empty())
+            {
+            int p = 0;
+            if (str2x(privAsString.data().c_str(), p) < 0)
+                {
+                strprintf(&s, "<ChgAdmin Result = \"Incorrect parameter Priv.\"/>" );
+                answerList->push_back(s);
+                return;
+                }
+            //memcpy(&conf.priv, &p, sizeof(conf.priv));
+            conf.priv.userStat      = (p & 0x0003) >> 0x00; // 1+2
+            conf.priv.userConf      = (p & 0x000C) >> 0x02; // 4+8
+            conf.priv.userCash      = (p & 0x0030) >> 0x04; // 10+20
+            conf.priv.userPasswd    = (p & 0x00C0) >> 0x06; // 40+80
+            conf.priv.userAddDel    = (p & 0x0300) >> 0x08; // 100+200
+            conf.priv.adminChg      = (p & 0x0C00) >> 0x0A; // 400+800
+            conf.priv.tariffChg     = (p & 0x3000) >> 0x0C; // 1000+2000
+            }
+
+        if (admins->Change(conf, currAdmin) != 0)
+            {
+            strprintf(&s, "<ChgAdmin Result = \"%s\"/>", admins->GetStrError().c_str());
+            answerList->push_back(s);
+            }
+        else
+            {
+            answerList->push_back("<ChgAdmin Result = \"Ok\"/>");
+            }
+        return;
+    //    }
+    //strprintf(&s, "<ChgAdmin Result = \"%s\"/>", admins->GetStrError().c_str());
+    //answerList->push_back(s);
+    //return;
+    }
+else
+    {
+    answerList->push_back("<ChgAdmin Result = \"Incorrect parameter login.\"/>");
+    }
+}
+//-----------------------------------------------------------------------------*/
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_tariff.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser_tariff.cpp
new file mode 100644 (file)
index 0000000..aeb1c78
--- /dev/null
@@ -0,0 +1,492 @@
+//#include <stdio.h>
+#include <cstring>
+
+#include "parser.h"
+
+const int pt_mega = 1024 * 1024;
+//-----------------------------------------------------------------------------
+//  GET TARIFFS
+//-----------------------------------------------------------------------------
+int PARSER_GET_TARIFFS::ParseStart(void *, const char * el, const char **)
+{
+if (strcasecmp(el, "GetTariffs") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_TARIFFS::ParseEnd(void *, const char * el)
+{
+if (strcasecmp(el, "GetTariffs") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_TARIFFS::CreateAnswer()
+{
+string s;
+char vs[100];
+int hd, hn, md, mn;
+
+answerList->erase(answerList->begin(), answerList->end());
+
+answerList->push_back("<Tariffs>");
+
+std::list<TARIFF_DATA> dataList;
+tariffs->GetTariffsData(&dataList);
+std::list<TARIFF_DATA>::const_iterator it = dataList.begin();
+for (; it != dataList.end(); ++it)
+    {
+    s = "<tariff name=\"" + it->tariffConf.name + "\">";
+    answerList->push_back(s);
+
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        hd = it->dirPrice[j].hDay;
+        md = it->dirPrice[j].mDay;
+
+        hn = it->dirPrice[j].hNight;
+        mn = it->dirPrice[j].mNight;
+
+        strprintf(&s, "<Time%d value=\"%d:%d-%d:%d\"/>", j, hd, md, hn, mn);
+        answerList->push_back(s);
+        }
+
+    strprintf(&s, "    <PriceDayA value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", it->dirPrice[i].priceDayA * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PriceDayB value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", it->dirPrice[i].priceDayB * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PriceNightA value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", it->dirPrice[i].priceNightA * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PriceNightB value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", it->dirPrice[i].priceNightB * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <Threshold value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%d%s", it->dirPrice[i].threshold, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <SinglePrice value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%d%s", it->dirPrice[i].singlePrice, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <NoDiscount value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%d%s", it->dirPrice[i].noDiscount, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <Fee value=\"%.5f\"/>", it->tariffConf.fee);
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PassiveCost value=\"%.5f\"/>", it->tariffConf.passiveCost);
+    answerList->push_back(s);
+
+    strprintf(&s, "    <Free value=\"%.5f\"/>", it->tariffConf.free);
+    answerList->push_back(s);
+
+    switch (it->tariffConf.traffType)
+        {
+        case TRAFF_UP:
+            answerList->push_back("<TraffType value=\"up\"/>");
+            break;
+        case TRAFF_DOWN:
+            answerList->push_back("<TraffType value=\"down\"/>");
+            break;
+        case TRAFF_UP_DOWN:
+            answerList->push_back("<TraffType value=\"up+down\"/>");
+            break;
+        case TRAFF_MAX:
+            answerList->push_back("<TraffType value=\"max\"/>");
+            break;
+        }
+
+    answerList->push_back("</tariff>");
+    }
+answerList->push_back("</Tariffs>");
+}
+//-----------------------------------------------------------------------------
+//  ADD TARIFF
+//-----------------------------------------------------------------------------
+int PARSER_ADD_TARIFF::ParseStart(void *, const char * el, const char ** attr)
+{
+if (strcasecmp(el, "AddTariff") == 0)
+    {
+    if (attr[1])
+        {
+        tariffToAdd = attr[1];
+        }
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_TARIFF::ParseEnd(void *, const char * el)
+{
+if (strcasecmp(el, "AddTariff") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_TARIFF::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (tariffs->Add(tariffToAdd, currAdmin) == 0)
+    {
+    answerList->push_back("<AddTariff Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<AddTariff Result=\"Error. %s\"/>", tariffs->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+//  DEL TARIFF
+//-----------------------------------------------------------------------------
+int PARSER_DEL_TARIFF::ParseStart(void *, const char * el, const char ** attr)
+{
+strError = "";
+if (strcasecmp(el, "DelTariff") == 0)
+    {
+    tariffToDel = attr[1];
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_TARIFF::ParseEnd(void *, const char * el)
+{
+if (strcasecmp(el, "DelTariff") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_DEL_TARIFF::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (users->TariffInUse(tariffToDel))
+    {
+    string s;
+    strprintf(&s, "<DelTariff Result=\"Error. Tariff \'%s\' cannot be deleted. Tariff in use.\"/>", tariffToDel.c_str());
+    answerList->push_back(s);
+    return;
+    }
+
+if (tariffs->Del(tariffToDel, currAdmin) == 0)
+    {
+    answerList->push_back("<DelTariff Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<DelTariff Result=\"Error. %s\"/>", tariffs->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//  CHG TARIFF
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseSlashedIntParams(int paramsNum, const string & s, int * params)
+{
+char * str = new char[s.size() + 1];
+char * p;
+strcpy(str, s.c_str());
+p = strtok(str, "/");
+
+for (int i = 0; i < paramsNum; i++)
+    {
+    if (p == NULL)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    if (str2x(p, params[i]) != 0)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    p = strtok(NULL, "/");
+    }
+
+delete[] str;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseSlashedDoubleParams(int paramsNum, const string & s, double * params)
+{
+char * str = new char[s.size() + 1];
+char * p;
+strcpy(str, s.c_str());
+p = strtok(str, "/");
+
+for (int i = 0; i < paramsNum; i++)
+    {
+    if (p == NULL)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    if (strtodouble2(p, params[i]) != 0)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    p = strtok(NULL, "/");
+    }
+
+delete[] str;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseStart(void *, const char * el, const char ** attr)
+{
+char st[50];
+double price[DIR_NUM];
+int t[DIR_NUM];
+depth++;
+
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetTariff") == 0)
+        {
+        td.tariffConf.name = attr[1];
+        return 0;
+        }
+    }
+else
+    {
+    string s;
+
+    if (strcasecmp(el, "PriceDayA") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceDayA = price[j] / pt_mega;
+        return 0;
+        }
+
+    if (strcasecmp(el, "PriceDayB") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceDayB = price[j] / pt_mega;
+        return 0;
+        }
+
+
+    if (strcasecmp(el, "PriceNightA") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceNightA = price[j] / pt_mega;
+        return 0;
+        }
+
+    if (strcasecmp(el, "PriceNightB") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceNightB = price[j] / pt_mega;
+        return 0;
+        }
+
+    if (strcasecmp(el, "Threshold") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedIntParams(DIR_NUM, s, t) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].threshold = t[j];
+        return 0;
+        }
+
+    if (strcasecmp(el, "SinglePrice") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedIntParams(DIR_NUM, s, t) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].singlePrice = t[j];
+        return 0;
+        }
+
+    if (strcasecmp(el, "NoDiscount") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedIntParams(DIR_NUM, s, t) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].noDiscount = t[j];
+        return 0;
+        }
+
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        snprintf(st, 50, "Time%d", j);
+        if (strcasecmp(el, st) == 0)
+            {
+            int h1, m1, h2, m2;
+            if (ParseTariffTimeStr(attr[1], h1, m1, h2, m2) == 0)
+                {
+                td.dirPrice[j].hDay = h1;
+                td.dirPrice[j].mDay = m1;
+                td.dirPrice[j].hNight = h2;
+                td.dirPrice[j].mNight = m2;
+                }
+            return 0;
+            }
+        }
+
+    if (strcasecmp(el, "Fee") == 0)
+        {
+        double fee;
+        if (strtodouble2(attr[1], fee) == 0)
+            td.tariffConf.fee = fee;
+        return 0;
+        }
+
+    if (strcasecmp(el, "PassiveCost") == 0)
+        {
+        double pc;
+        if (strtodouble2(attr[1], pc) == 0)
+            td.tariffConf.passiveCost = pc;
+        return 0;
+        }
+    if (strcasecmp(el, "Free") == 0)
+        {
+        double free;
+        if (strtodouble2(attr[1], free) == 0)
+            td.tariffConf.free = free;
+        return 0;
+        }
+
+    if (strcasecmp(el, "TraffType") == 0)
+        {
+        if (strcasecmp(attr[1], "up") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_UP;
+            return 0;
+            }
+
+        if (strcasecmp(attr[1], "down") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_DOWN;
+            return 0;
+            }
+        if (strcasecmp(attr[1], "up+down") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_UP_DOWN;
+            return 0;
+            }
+        if (strcasecmp(attr[1], "max") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_MAX;
+            return 0;
+            }
+        return 0;
+        }
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseEnd(void *, const char * el)
+{
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetTariff") == 0)
+        {
+        CreateAnswer();
+        depth--;
+        return 0;
+        }
+    }
+
+depth--;
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_TARIFF::CreateAnswer()
+{
+answerList->erase(answerList->begin(), answerList->end());
+
+if (!td.tariffConf.name.data().empty())
+    {
+    TARIFF_DATA tariffData = td.GetData();
+    if (tariffs->Chg(tariffData, currAdmin) == 0)
+        {
+        answerList->push_back("<SetTariff Result=\"ok\"/>");
+        return;
+        }
+    else
+        {
+        string s;
+        strprintf(&s, "<SetTariff Result=\"Change tariff error! %s\"/>", tariffs->GetStrError().c_str());
+        answerList->push_back(s);
+        return;
+        }
+    }
+answerList->push_back("<SetTariff Result=\"Change tariff error!\"/>");
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp b/projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp
new file mode 100644 (file)
index 0000000..8ceb7e7
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ *    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
+ */
+
+/*******************************************************************
+*
+*    DESCRIPTION: æÁÊÌ Ó ÏÓÎÏ×ÎÙÍÉ ÆÕÎËÃÉÑÍÉ ÄÌÑ ÓÅÔÅ×ÏÇÏ ÏÂÍÅÎÁ ÄÁÎÎÙÍÉ
+*    Ó ÍÅÎÅÄÖÅÒÏÍ ËÌÉÅÎÔÏ×. ðÒÉÅÍ, ÐÅÒÅÄÁÞÁ É ÛÉÆÒÏ×ÁÎÉÅ ÓÏÏÂÝÅÎÉÊ.
+*
+*    AUTHOR: Boris Mikhailenko <stg34@stargazer.dp.ua>
+*
+*    $Revision: 1.24 $
+*    $Date: 2010/10/04 20:24:54 $
+*
+*******************************************************************/
+
+/*#include <unistd.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>*/
+
+#include <cerrno>
+#include <csignal>
+
+#include "configproto.h"
+#include "blowfish.h"
+
+enum CONF_STATE
+    {
+    confHdr,
+    confLogin,
+    confLoginCipher,
+    confData
+    };
+
+enum
+    {
+    ans_ok = 0,
+    ans_err
+    };
+
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::Prepare()
+{
+list<string> ansList; //óÀÄÁ ÂÕÄÅÔ ÐÏÍÅÝÅΠÏÔ×ÅÔ ÄÌÑ ÍÅÎÅÄÖÅÒÁ ËÌÉÅÎÔÏ×
+int res;
+struct sockaddr_in listenAddr;
+
+sigset_t sigmask, oldmask;
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+sigaddset(&sigmask, SIGTERM);
+sigaddset(&sigmask, SIGUSR1);
+sigaddset(&sigmask, SIGHUP);
+pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
+
+listenSocket = socket(PF_INET, SOCK_STREAM, 0);
+
+if (listenSocket < 0)
+    {
+    errorStr = "Create NET_CONFIGURATOR socket failed.";
+    return -1;
+    }
+
+listenAddr.sin_family = PF_INET;
+listenAddr.sin_port = htons(port);
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+int lng = 1;
+
+if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
+    {
+    errorStr = "Setsockopt failed. " + string(strerror(errno));
+    return -1;
+    }
+
+res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
+
+if (res == -1)
+    {
+    errorStr = "Bind admin socket failed";
+    return -1;
+    }
+
+res = listen(listenSocket, 0);
+if (res == -1)
+    {
+    errorStr = "Listen admin socket failed";
+    return -1;
+    }
+outerAddrLen = sizeof(outerAddr);
+
+/*if (0 != fcntl(listenSocket, F_SETFL, O_NONBLOCK))
+    {
+    errorStr = "fcntl error!";
+    return -1;
+    }*/
+
+errorStr = "";
+nonstop = true;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::Stop()
+{
+nonstop = false;
+close(listenSocket);
+//TODO: Idiotism
+int                 sock;
+struct sockaddr_in  addr;
+socklen_t           addrLen;
+addr.sin_family = PF_INET;
+addr.sin_port = htons(port);
+addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+addrLen = sizeof(outerAddr);
+sock = socket(PF_INET, SOCK_STREAM, 0);
+connect(sock, (sockaddr*)&addr, addrLen);
+close(sock);
+//Idiotism end
+return 0;
+}
+//-----------------------------------------------------------------------------
+// æÕÎËÃÉÑ ÏÂÝÅÎÉÑ Ó ËÏÎÆÉÇÕÒÁÔÏÒÏÍ
+void * CONFIGPROTO::Run(void * a)
+{
+/*
+ * Function Name:ReciveSendConf
+ * Parameters: void * a ÕËÁÚÁÔÅÌØ ÎÁ ÜËÚÅÍÐÌÑÒ ËÌÁÓÓÁ CONFIGPROTO
+ * Description: üÔÁ ÆÕÎËÃÉÑ ÏÂÅÓÐÅÞÉ×ÁÅÔ ÓÅÔÅ×ÏÅ ×ÚÁÉÍÏÄÅÊÓÔ×ÉÅ
+ *  Ó íÅÎÅÄÖÅÒÏÍ ëÌÉÅÎÔÏ×. ÷ ÅÅ ÚÁÄÁÞÉ ×ÈÏÄÉÔ: ÐÒÉÅÍ ÚÁÐÒÏÓÏ× ÐÏ TCP/IP
+ *  ÉÈ ÒÁÓÛÉÆÒÏ×ËÁ, ÐÅÒÅÄÁÞÁ ÐÒÉÎÑÔÙÈ ÄÁÎÎÙÈ ÁÎÁÌÉÚÁÔÏÒÕ É ÏÔÐÒÁ×ËÁ ÏÔ×ÅÔÁ ÎÁÚÁÄ.
+ * Returns: ×ÏÚ×ÒÁÝÁÅÔ NULL
+ */
+
+CONFIGPROTO * cp = (CONFIGPROTO*)a;
+cp->state = confHdr;
+
+while (cp->nonstop)
+    {
+    cp->state = confHdr;
+    cp->outerSocket = accept(cp->listenSocket,
+                             (struct sockaddr*)(&cp->outerAddr),
+                             &cp->outerAddrLen);
+
+    if (!cp->nonstop)
+        {
+        continue;
+        }
+
+    if (cp->outerSocket == -1)
+        {
+        printfd(__FILE__, "accept failed\n");
+        usleep(100000);
+        continue;
+        }
+
+    cp->adminIP = *(unsigned int*)&(cp->outerAddr.sin_addr);
+
+    /* TODO
+    if (!cp->hostAllow->HostAllowed(cp->adminIP))
+        {
+        close(outerSocket);
+        continue;
+        }*/
+
+    printfd(__FILE__, "Connection accepted from %s\n", inet_ntostring(cp->outerAddr.sin_addr.s_addr).c_str());
+
+    if (cp->state == confHdr)
+        {
+        if (cp->RecvHdr(cp->outerSocket) < 0)
+            {
+            close(cp->outerSocket);
+            continue;
+            }
+        if (cp->state == confLogin)
+            {
+            if (cp->SendHdrAnswer(cp->outerSocket, ans_ok) < 0)
+                {
+                close(cp->outerSocket);
+                continue;
+                }
+
+            if (cp->RecvLogin(cp->outerSocket) < 0)
+                {
+                close(cp->outerSocket);
+                continue;
+                }
+
+            if (cp->state == confLoginCipher)
+                {
+                if (cp->SendLoginAnswer(cp->outerSocket, ans_ok) < 0)
+                    {
+                    close(cp->outerSocket);
+                    continue;
+                    }
+                if (cp->RecvLoginS(cp->outerSocket) < 0)
+                    {
+                    close(cp->outerSocket);
+                    continue;
+                    }
+
+                if (cp->state == confData)
+                    {
+                    if (cp->SendLoginSAnswer(cp->outerSocket, ans_ok) < 0)
+                        {
+                        close(cp->outerSocket);
+                        continue;
+                        }
+                    if (cp->RecvData(cp->outerSocket) < 0)
+                        {
+                        close(cp->outerSocket);
+                        continue;
+                        }
+                    cp->state = confHdr;
+                    }
+                else
+                    {
+                    if (cp->SendLoginSAnswer(cp->outerSocket, ans_err) < 0)
+                        {
+                        close(cp->outerSocket);
+                        continue;
+                        }
+                    cp->WriteLogAccessFailed(cp->adminIP);
+                    }
+                }
+            else
+                {
+                cp->WriteLogAccessFailed(cp->adminIP);
+                }
+            }
+        else
+            {
+            cp->WriteLogAccessFailed(cp->adminIP);
+            if (cp->SendHdrAnswer(cp->outerSocket, ans_err) < 0)
+                {
+                close(cp->outerSocket);
+                continue;
+                }
+            }
+        }
+    else
+        {
+        cp->WriteLogAccessFailed(cp->adminIP);
+        }
+    close(cp->outerSocket);
+    }
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvHdr(int sock)
+{
+char buf[sizeof(STG_HEADER)];
+memset(buf, 0, sizeof(STG_HEADER));
+int ret;
+int stgHdrLen = strlen(STG_HEADER);
+for (int i = 0; i < stgHdrLen; i++)
+    {
+    ret = recv(sock, &buf[i], 1, 0);
+    if (ret <= 0)
+        {
+        state = confHdr;
+        return -1;
+        }
+    }
+
+if (0 == strncmp(buf, STG_HEADER, strlen(STG_HEADER)))
+    {
+    state = confLogin;
+    return 0;
+    }
+else
+    {
+    SendError("Bad request");
+    }
+
+state = confHdr;
+return -1;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendHdrAnswer(int sock, int err)
+{
+int ret;
+
+if (err)
+    {
+    ret = send(sock, ERR_HEADER, sizeof(ERR_HEADER)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send ERR_HEADER error in SendHdrAnswer.");
+        return -1;
+        }
+    }
+else
+    {
+    ret = send(sock, OK_HEADER, sizeof(OK_HEADER)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send OK_HEADER error in SendHdrAnswer.");
+        return -1;
+        }
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvLogin(int sock)
+{
+char login[ADM_LOGIN_LEN+1];
+int ret;
+
+memset(login, 0, ADM_LOGIN_LEN + 1);
+
+//printfd(__FILE__, "RecvLogin\n");
+
+/*for (int i = 0; i < ADM_LOGIN_LEN; i++)
+    {
+    ret = recv(sock, &login[i], 1, 0);
+
+    if (ret <= 0)
+        {
+        close(sock);
+        state = confHdr;
+        return ENODATA;
+        }
+    }*/
+
+ret = recv(sock, login, ADM_LOGIN_LEN, 0);
+
+if (ret < 0)
+    {
+    // Error in network
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }
+
+if (ret < ADM_LOGIN_LEN)
+    {
+    // Error in protocol
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }
+
+if (admins->FindAdmin(login, &currAdmin))
+    {
+    // Admin not found
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }
+currAdmin.SetAdminIP(adminIP);
+adminLogin = login;
+state = confLoginCipher;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendLoginAnswer(int sock, int)
+{
+int ret;
+
+ret = send(sock, OK_LOGIN, sizeof(OK_LOGIN)-1, 0);
+if (ret < 0)
+    {
+    WriteServLog("Send OK_LOGIN error in SendLoginAnswer.");
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvLoginS(int sock)
+{
+char loginS[ADM_LOGIN_LEN + 1];
+char login[ADM_LOGIN_LEN + 1];
+int ret;
+BLOWFISH_CTX ctx;
+memset(loginS, 0, ADM_LOGIN_LEN + 1);
+
+//printfd(__FILE__, "RecvLoginS\n");
+
+/*for (int i = 0; i < ADM_LOGIN_LEN; i++)
+    {
+    ret = recv(sock, &loginS[i], 1, 0);
+
+    if (ret <= 0)
+        {
+        //printfd(__FILE__, "RecvLoginS close\n");
+        close(sock);
+        state = confHdr;
+        return ENODATA;
+        }
+    }*/
+
+int total = 0;
+
+while (total < ADM_LOGIN_LEN)
+    {
+    ret = recv(sock, &loginS[total], ADM_LOGIN_LEN - total, 0);
+
+    if (ret < 0)
+        {
+        // Network error
+        printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
+        close(sock);
+        state = confHdr;
+        return ENODATA;
+        }
+
+    total += ret;
+    }
+
+// TODO: implement select on socket
+/*if (total < ADM_LOGIN_LEN)
+    {
+    // Protocol error
+    printfd(__FILE__, "Protocol error. Need %d bytes of cryptologin. Got %d bytes.\n", ADM_LOGIN_LEN, ret);
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }*/
+
+if (currAdmin.GetLogin() == "")
+    {
+    state = confHdr;
+    return ENODATA;
+    }
+
+EnDecodeInit(currAdmin.GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
+
+for (int i = 0; i < ADM_LOGIN_LEN/8; i++)
+    {
+    DecodeString(login + i*8, loginS + i*8, &ctx);
+    }
+
+if (currAdmin == admins->GetNoAdmin())
+    {
+    // If there are no admins registered in the system - give access with any password
+    state = confData;
+    return 0;
+    }
+
+if (strncmp(currAdmin.GetLogin().c_str(), login, ADM_LOGIN_LEN) != 0)
+    {
+    state = confHdr;
+    return ENODATA;
+    }
+
+state = confData;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendLoginSAnswer(int sock, int err)
+{
+int ret;
+
+if (err)
+    {
+    ret = send(sock, ERR_LOGINS, sizeof(ERR_LOGINS)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send ERR_LOGIN error in SendLoginAnswer.");
+        return -1;
+        }
+    }
+else
+    {
+    ret = send(sock, OK_LOGINS, sizeof(OK_LOGINS)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send OK_LOGINS error in SendLoginSAnswer.");
+        return -1;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvData(int sock)
+{
+//printfd(__FILE__, "RecvData\n");
+//int n = 0;
+int ret;
+char bufferS[8];
+char buffer[9];
+
+buffer[8] = 0;
+
+requestList.clear();
+BLOWFISH_CTX ctx;
+
+EnDecodeInit(currAdmin.GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
+
+while (1)
+    {
+    /*ret = recv(sock, &bufferS[n++], 1, 0);
+    if (ret <= 0)
+        {
+        //printfd(__FILE__, "RecvData close\n");
+        close(sock);
+        return 0;
+        }*/
+    int total = 0;
+    bool done = false;
+    while (total < 8)
+        {
+        ret = recv(sock, &bufferS[total], 8 - total, 0);
+        if (ret < 0)
+            {
+            // Network error
+            close(sock);
+            return 0;
+            }
+
+        if (ret < 8)
+            {
+            if (memchr(buffer, 0, ret) != NULL)
+                {
+                done = true;
+                break;
+                }
+            }
+
+        total += ret;
+        }
+
+    DecodeString(buffer, bufferS, &ctx);
+    requestList.push_back(std::string(buffer, total));
+
+    if (done || memchr(buffer, 0, total) != NULL)
+        {
+        // ëÏÎÅàÐÏÓÙÌËÉ
+        if (ParseCommand())
+            {
+            SendError("Bad command");
+            }
+        return SendDataAnswer(sock);
+        }
+
+    /*if (n == 8)
+        {
+        n = 0;
+        DecodeString(buffer, bufferS, &ctx);
+        requestList.push_back(std::string(buffer, 8));
+        for (int j = 0; j < 8; j++)
+            {
+            if (buffer[j] == 0)
+                {
+                // ëÏÎÅàÐÏÓÙÌËÉ
+                if (ParseCommand())
+                    {
+                    SendError("Bad command");
+                    }
+                return SendDataAnswer(sock);
+                }
+            }
+        }*/
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendDataAnswer(int sock)
+{
+list<string>::iterator li;
+li = answerList.begin();
+
+BLOWFISH_CTX ctx;
+
+char buff[8];
+char buffS[8];
+int n = 0;
+int k = 0;
+int ret = 0;
+
+EnDecodeInit(currAdmin.GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
+
+while (li != answerList.end())
+    {
+    while ((*li).c_str()[k])
+        {
+        buff[n%8] = (*li).c_str()[k];
+        n++;
+        k++;
+
+        if (n%8 == 0)
+            {
+            EncodeString(buffS, buff, &ctx);
+            ret = send(sock, buffS, 8, 0);
+            if (ret < 0)
+                {
+                return -1;
+                }
+            }
+        }
+    k = 0;// new node
+    li++;
+    }
+
+if (answerList.empty()) {
+    return 0;
+}
+
+buff[n%8] = 0;
+EncodeString(buffS, buff, &ctx);
+
+answerList.clear();
+
+return send(sock, buffS, 8, 0);
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SendError(const char * text)
+{
+char s[255];
+answerList.clear();
+sprintf(s, "<Error value=\"%s\"/>", text);
+answerList.push_back(s);
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
+{
+WriteServLog("Admin's connect failed. IP %s", inet_ntostring(ip).c_str());
+}
+//-----------------------------------------------------------------------------
+
+
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/stgconfig.cpp b/projects/stargazer/plugins/configuration/sgconfig/stgconfig.cpp
new file mode 100644 (file)
index 0000000..8ba4b0f
--- /dev/null
@@ -0,0 +1,245 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "stgconfig.h"
+#include "../../../tariffs.h"
+#include "../../../admins.h"
+#include "../../../users.h"
+
+class STGCONFIG_CREATOR
+{
+private:
+    STG_CONFIG * stgconfig;
+
+public:
+    STGCONFIG_CREATOR()
+        : stgconfig(new STG_CONFIG())
+        {
+        };
+    ~STGCONFIG_CREATOR()
+        {
+        delete stgconfig;
+        };
+
+    STG_CONFIG * GetPlugin()
+        {
+        return stgconfig;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+STGCONFIG_CREATOR stgc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+STG_CONFIG_SETTINGS::STG_CONFIG_SETTINGS()
+    : port(0)
+{
+}
+//-----------------------------------------------------------------------------
+const string& STG_CONFIG_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    printfd(__FILE__, "Parameter 'Port' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+port = p;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t STG_CONFIG_SETTINGS::GetPort()
+{
+return port;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return stgc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string STG_CONFIG::GetVersion() const
+{
+return "Stg configurator v.0.08";
+}
+//-----------------------------------------------------------------------------
+STG_CONFIG::STG_CONFIG()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void STG_CONFIG::SetUsers(USERS * u)
+{
+users = u;
+}
+//-----------------------------------------------------------------------------
+void STG_CONFIG::SetTariffs(TARIFFS * t)
+{
+tariffs = t;
+}
+//-----------------------------------------------------------------------------
+void STG_CONFIG::SetAdmins(ADMINS * a)
+{
+admins = a;
+}
+//-----------------------------------------------------------------------------
+void STG_CONFIG::SetStore(BASE_STORE * s)
+{
+store = s;
+}
+//-----------------------------------------------------------------------------
+void STG_CONFIG::SetStgSettings(const SETTINGS * s)
+{
+stgSettings = s;
+}
+//-----------------------------------------------------------------------------
+void STG_CONFIG::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG::ParseSettings()
+{
+int ret = stgConfigSettings.ParseSettings(settings);
+if (ret)
+    errorStr = stgConfigSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+const string & STG_CONFIG::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG::Start()
+{
+if (isRunning)
+    return 0;
+
+nonstop = true;
+
+config.SetPort(stgConfigSettings.GetPort());
+config.SetAdmins(admins);
+config.SetUsers(users);
+config.SetTariffs(tariffs);
+config.SetStgSettings(stgSettings);
+config.SetStore(store);
+
+if (config.Prepare())
+    {
+    errorStr = config.GetStrError();
+    return -1;
+    }
+
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    errorStr = "Cannot create thread.";
+    printfd(__FILE__, "Cannot create thread\n");
+    return -1;
+    }
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_CONFIG::Stop()
+{
+if (!isRunning)
+    return 0;
+
+config.Stop();
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    //TODO pthread_cancel()
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        printfd(__FILE__, "Cannot kill thread\n");
+        return -1;
+        }
+    printfd(__FILE__, "STG_CONFIG killed\n");
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool STG_CONFIG::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * STG_CONFIG::Run(void * d)
+{
+STG_CONFIG * stgConf = (STG_CONFIG *)d;
+stgConf->isRunning = true;
+
+stgConf->config.Run(&stgConf->config);
+
+stgConf->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t STG_CONFIG::GetStartPosition() const
+{
+return 220;
+}
+//-----------------------------------------------------------------------------
+uint16_t STG_CONFIG::GetStopPosition() const
+{
+return 220;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig/stgconfig.h b/projects/stargazer/plugins/configuration/sgconfig/stgconfig.h
new file mode 100644 (file)
index 0000000..57241c6
--- /dev/null
@@ -0,0 +1,104 @@
+#include <string>
+#include <pthread.h>
+#include "base_plugin.h"
+#include "base_store.h"
+#include "configproto.h"
+//#include "user_ips.h"
+//#include "../../../users.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class STG_CONFIG;
+
+//-----------------------------------------------------------------------------
+/*template <typename varParamType>
+class CHG_BEFORE_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void Notify(const varParamType & oldValue, const varParamType & newValue)
+        {
+        auth->Unauthorize(user);
+        }
+    void SetUser(USER * u) { user = u; }
+    void SetAuthorizaror(const AUTH_AO * a) { auth = a; }
+
+private:
+    USER * user;
+    const AUTH_AO * auth;
+};
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class CHG_AFTER_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void Notify(const varParamType & oldValue, const varParamType & newValue)
+        {
+        auth->UpdateUserAuthorization(user);
+        }
+    void SetUser(USER * u) { user = u; }
+    void SetAuthorizaror(const AUTH_AO * a) { auth = a; }
+
+private:
+    USER * user;
+    const AUTH_AO * auth;
+};*/
+//-----------------------------------------------------------------------------
+class STG_CONFIG_SETTINGS
+{
+public:
+                    STG_CONFIG_SETTINGS();
+    virtual         ~STG_CONFIG_SETTINGS(){};
+    const string &  GetStrError() const;
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    uint16_t        GetPort();
+private:
+    int     ParseIntInRange(const string & str, int min, int max, int * val);
+    string  errorStr;
+    int     port;
+};
+//-----------------------------------------------------------------------------
+class STG_CONFIG :public BASE_PLUGIN
+{
+public:
+    STG_CONFIG();
+    virtual ~STG_CONFIG(){};
+
+    void                SetUsers(USERS * u);
+    void                SetTariffs(TARIFFS * t);
+    void                SetAdmins(ADMINS * a);
+    void                SetStore(BASE_STORE * s);
+    void                SetTraffcounter(TRAFFCOUNTER *){};
+    void                SetStgSettings(const SETTINGS * s);
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+private:
+    static void *       Run(void *);
+    mutable string      errorStr;
+    STG_CONFIG_SETTINGS stgConfigSettings;
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+    CONFIGPROTO         config;
+    USERS *             users;
+    ADMINS *            admins;
+    TARIFFS *           tariffs;
+    BASE_STORE *        store;
+    MODULE_SETTINGS     settings;
+    const SETTINGS *    stgSettings;
+};
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/Makefile b/projects/stargazer/plugins/configuration/sgconfig2/Makefile
new file mode 100644 (file)
index 0000000..ab02cdf
--- /dev/null
@@ -0,0 +1,22 @@
+###############################################################################
+# $Id: Makefile,v 1.9 2008/12/04 17:09:40 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_conf_sg2.so
+
+SRCS = ./stgconfig.cpp \
+       ./rsconf.cpp \
+       ./configproto.cpp \
+       ./parser.cpp \
+       ./parser_tariff.cpp \
+       ./parser_admin.cpp
+
+LIBS += -lexpat \
+       $(LIB_THREAD)
+
+STGLIBS = -lstg_common -lstg_logger
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/configproto.cpp b/projects/stargazer/plugins/configuration/sgconfig2/configproto.cpp
new file mode 100644 (file)
index 0000000..b0255e1
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.20 $
+ $Date: 2009/10/20 11:53:40 $
+ $Author: faust $
+ */
+
+
+//#include <string.h>
+//#include <stdio.h>
+#include <unistd.h>
+
+#include "configproto.h"
+
+//-----------------------------------------------------------------------------
+void ParseXMLStart(void *data, const char *el, const char **attr)
+{
+CONFIGPROTO * cp = (CONFIGPROTO*)(data);
+
+if (cp->currParser)
+    {
+    cp->currParser->SetAnswerList(&cp->answerList);
+    cp->currParser->SetCurrAdmin(cp->currAdmin);
+    cp->currParser->ParseStart(data, el, attr);
+    }
+else
+    {
+    for (unsigned int i = 0; i < cp->dataParser.size(); i++)
+        {
+        cp->dataParser[i]->SetAnswerList(&cp->answerList);
+        cp->currAdmin->SetAdminIP(cp->GetAdminIP());
+        cp->dataParser[i]->SetCurrAdmin(cp->currAdmin);
+        cp->dataParser[i]->Reset();
+        if (cp->dataParser[i]->ParseStart(data, el, attr) == 0)
+            {
+            cp->currParser = cp->dataParser[i];
+            break;
+            }
+        else
+            {
+            cp->dataParser[i]->Reset();
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void ParseXMLEnd(void *data, const char *el)
+{
+CONFIGPROTO * cp = (CONFIGPROTO*)(data);
+if (cp->currParser)
+    {
+    if (cp->currParser->ParseEnd(data, el) == 0)
+        {
+        cp->currParser = NULL;
+        }
+    }
+else
+    {
+    for (unsigned int i = 0; i < cp->dataParser.size(); i++)
+        {
+        if (cp->dataParser[i]->ParseEnd(data, el) == 0)
+            {
+            break;
+            }
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+CONFIGPROTO::CONFIGPROTO()
+    : adminIP(0),
+      port(0),
+      nonstop(1),
+      state(0),
+      currAdmin(NULL),
+      WriteServLog(GetStgLogger()),
+      outerSocket(0),
+      listenSocket(0),
+      admins(NULL),
+      users(NULL),
+      tariffs(NULL),
+      store(NULL),
+      settings(NULL),
+      currParser(NULL)
+{
+dataParser.push_back(&parserGetServInfo);
+
+dataParser.push_back(&parserGetUsers);
+dataParser.push_back(&parserGetUser);
+dataParser.push_back(&parserChgUser);
+dataParser.push_back(&parserAddUser);
+dataParser.push_back(&parserDelUser);
+dataParser.push_back(&parserCheckUser);
+dataParser.push_back(&parserSendMessage);
+
+dataParser.push_back(&parserGetTariffs);
+dataParser.push_back(&parserAddTariff);
+dataParser.push_back(&parserDelTariff);
+dataParser.push_back(&parserChgTariff);
+
+dataParser.push_back(&parserGetAdmins);
+dataParser.push_back(&parserChgAdmin);
+dataParser.push_back(&parserDelAdmin);
+dataParser.push_back(&parserAddAdmin);
+
+xmlParser = XML_ParserCreate(NULL);
+
+if (!xmlParser)
+    {
+    WriteServLog("Couldn't allocate memory for parser.");
+    exit(1);
+    }
+
+//XML_SetElementHandler(parser, ParseXMLStart, ParseXMLEnd);
+}
+//-----------------------------------------------------------------------------
+CONFIGPROTO::~CONFIGPROTO()
+{
+XML_ParserFree(xmlParser);
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::ParseCommand()
+{
+list<string>::iterator n;
+int done = 0;
+char str[9];
+int len;
+
+if (requestList.empty())
+    return 0;
+
+n = requestList.begin();
+
+strncpy(str, (*n).c_str(), 8);
+str[8] = 0;
+
+XML_ParserReset(xmlParser, NULL);
+XML_SetElementHandler(xmlParser, ParseXMLStart, ParseXMLEnd);
+XML_SetUserData(xmlParser, this);
+
+while(nonstop)
+    {
+    strncpy(str, (*n).c_str(), 8);
+    str[8] = 0;
+    len = strlen(str);
+
+    n++;
+    if (n == requestList.end())
+        done = 1;
+    n--;
+
+    if (XML_Parse(xmlParser, (*n).c_str(), len, done) == XML_STATUS_ERROR)
+        {
+        WriteServLog("Invalid configuration request");
+        printfd(__FILE__, "Parse error at line %d:\n%s\n",
+           XML_GetCurrentLineNumber(xmlParser),
+           XML_ErrorString(XML_GetErrorCode(xmlParser)));
+        if (currParser)
+            {
+            printfd(__FILE__, "Parser reset\n");
+            currParser->Reset();
+            currParser = NULL;
+            }
+
+        return -1;
+        }
+
+    if (done)
+        return 0;
+
+    n++;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetPort(uint16_t p)
+{
+port = p;
+}
+//-----------------------------------------------------------------------------
+/*void CONFIGPROTO::SetHostAllow(HOSTALLOW *)
+{
+//hostAllow = ha;
+}*/
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetAdmins(ADMINS * a)
+{
+admins = a;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetAdmins(admins);
+    }
+
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetUsers(USERS * u)
+{
+users = u;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetUsers(users);
+    }
+
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetTariffs(TARIFFS * t)
+{
+tariffs = t;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetTariffs(tariffs);
+    }
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetStore(BASE_STORE * s)
+{
+store = s;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetStore(s);
+    }
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SetStgSettings(const SETTINGS * s)
+{
+settings = s;
+for (unsigned int i = 0; i < dataParser.size(); i++)
+    {
+    dataParser[i]->SetStgSettings(settings);
+    }
+}
+//-----------------------------------------------------------------------------
+/*void CONFIGPROTO::Start()
+{
+finished = false;
+threadExited = false;
+status = starting;
+
+xmlParser = XML_ParserCreate(NULL);
+
+if (!xmlParser)
+    {
+    WriteServLog("Couldn't allocate memory for parser.");
+    }
+
+pthread_create(&thrReciveSendConf, NULL, ReciveSendConf, this);
+status = started;
+}*/
+//-----------------------------------------------------------------------------
+/*int CONFIGPROTO::Stop()
+{
+nonstop = true;
+close(outerSocket);
+return 0;
+}*/
+//-----------------------------------------------------------------------------
+/*void CONFIGPROTO::Restart()
+{
+//Stop();
+//Start();
+}*/
+//-----------------------------------------------------------------------------
+/*CONF_STATUS CONFIGPROTO::Status()
+{
+//return status;
+}
+//-----------------------------------------------------------------------------
+*/
+const string & CONFIGPROTO::GetStrError()
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+uint32_t CONFIGPROTO::GetAdminIP()
+{
+return adminIP;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/configproto.h b/projects/stargazer/plugins/configuration/sgconfig2/configproto.h
new file mode 100644 (file)
index 0000000..71e546b
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.12 $
+ $Date: 2009/10/15 14:46:17 $
+ $Author: faust $
+ */
+
+
+#ifndef CONFIGPROTO_H
+#define CONFIGPROTO_H
+
+#include <expat.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string>
+
+#include "parser.h"
+#include "../../../users.h"
+#include "../../../admins.h"
+#include "../../../tariffs.h"
+#include "stg_logger.h"
+
+using namespace std;
+
+#define  STG_HEADER     "SG04"
+#define  OK_HEADER      "OKHD"
+#define  ERR_HEADER     "ERHD"
+#define  OK_LOGIN       "OKLG"
+#define  ERR_LOGIN      "ERLG"
+#define  OK_LOGINS      "OKLS"
+#define  ERR_LOGINS     "ERLS"
+
+//-----------------------------------------------------------------------------
+class CONFIGPROTO
+{
+public:
+    CONFIGPROTO();
+    ~CONFIGPROTO();
+
+    void            SetPort(uint16_t port);
+    //void            SetHostAllow(HOSTALLOW * ha);
+    void            SetAdmins(ADMINS * a);
+    void            SetUsers(USERS * u);
+    void            SetTariffs(TARIFFS * t);
+    void            SetStore(BASE_STORE * s);
+    void            SetStgSettings(const SETTINGS * s);
+    const string &  GetAdminLogin();
+    uint32_t        GetAdminIP();
+    int             Prepare();
+    int             Stop();
+    const string &  GetStrError();
+    static void *   Run(void * a);
+
+private:
+    int             RecvHdr(int sock);
+    int             RecvLogin(int sock);
+    int             SendLoginAnswer(int sock, int err);
+    int             SendHdrAnswer(int sock, int err);
+    int             RecvLoginS(int sock);
+    int             SendLoginSAnswer(int sock, int err);
+    int             RecvData(int sock);
+    int             SendDataAnswer(int sock);
+    void            SendError(const char * text);
+    void            WriteLogAccessFailed(uint32_t ip);
+
+    int             ParseCommand();
+
+    list<string>    answerList;
+    list<string>    requestList;
+    uint32_t        adminIP;
+    string          adminLogin;
+    uint16_t        port;
+    pthread_t       thrReciveSendConf;
+    bool            nonstop;
+    int             state;
+    //HOSTALLOW *     hostAllow;
+    const ADMIN *   currAdmin;
+    STG_LOGGER &    WriteServLog;
+
+    int                 outerSocket;
+    int                 listenSocket;
+    struct sockaddr_in  outerAddr;
+    socklen_t           outerAddrLen;
+
+    PARSER_GET_SERVER_INFO      parserGetServInfo;
+
+    PARSER_GET_USERS            parserGetUsers;
+    PARSER_GET_USER             parserGetUser;
+    PARSER_CHG_USER             parserChgUser;
+    PARSER_ADD_USER             parserAddUser;
+    PARSER_DEL_USER             parserDelUser;
+    PARSER_CHECK_USER           parserCheckUser;
+    PARSER_SEND_MESSAGE         parserSendMessage;
+
+    PARSER_GET_ADMINS           parserGetAdmins;
+    PARSER_ADD_ADMIN            parserAddAdmin;
+    PARSER_DEL_ADMIN            parserDelAdmin;
+    PARSER_CHG_ADMIN            parserChgAdmin;
+
+    PARSER_GET_TARIFFS          parserGetTariffs;
+    PARSER_ADD_TARIFF           parserAddTariff;
+    PARSER_DEL_TARIFF           parserDelTariff;
+    PARSER_CHG_TARIFF           parserChgTariff;
+
+    ADMINS *                    admins;
+    USERS *                     users;
+    TARIFFS *                   tariffs;
+    BASE_STORE *                store;
+    const SETTINGS *            settings;
+
+    BASE_PARSER *               currParser;
+    vector<BASE_PARSER*>        dataParser;
+
+    XML_Parser                  xmlParser;
+
+    string                      errorStr;
+
+    friend void ParseXMLStart(void *data, const char *el, const char **attr);
+    friend void ParseXMLEnd(void *data, const char *el);
+};
+//-----------------------------------------------------------------------------
+#endif //CONFIGPROTO_H
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/net_configurator.cpp b/projects/stargazer/plugins/configuration/sgconfig2/net_configurator.cpp
new file mode 100644 (file)
index 0000000..6b8bc84
--- /dev/null
@@ -0,0 +1,133 @@
+#include <unistd.h>
+#include "net_configurator.h"
+#include "../../internal_configurator.h"
+
+//-----------------------------------------------------------------------------
+const string & NET_CONFIGURATOR_SETTINGS::GetStrError()
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR_SETTINGS::ReadSettings(const CONFIGFILE &cf)
+{
+if (cf.ReadUShortInt("AdminPort", &port, 5555) != 0)
+    {
+    strError = "Cannot read parameter AdminPort.";
+    return -1;
+    }
+if (port < 1 || port > 65535)
+    {
+    strError = "Incorrect value AdminPort.";
+    return -1;
+    }
+
+string strOrder;
+cf.ReadString("AdminOrder", &strOrder, "allow,deny");
+if (hostAllow.ParseOrder(strOrder.c_str()) < 0)
+    {
+    strError = string("Error in parameter AdminOrder. ") + hostAllow.GetStrError();
+    return -1;
+    }
+
+string strAllow;
+cf.ReadString("AdminAllowFrom", &strAllow, "all");
+if (hostAllow.ParseHosts(strAllow.c_str(), hostsAllow) != 0)
+    {
+    strError = string("Error in parameter AdminAllowFrom. ") + hostAllow.GetStrError();
+    return -1;
+    }
+
+string strDeny;
+cf.ReadString("AdminDenyFrom", &strDeny, "");
+if (hostAllow.ParseHosts(strDeny.c_str(), hostsDeny) != 0)
+    {
+    strError = string("Error in parameter AdminDenyFrom. ") + hostAllow.GetStrError();
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t NET_CONFIGURATOR_SETTINGS::GetPort()
+{
+return port;
+}
+//-----------------------------------------------------------------------------
+HOSTALLOW * NET_CONFIGURATOR_SETTINGS::GetHostAllow()
+{
+return &hostAllow;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+NET_CONFIGURATOR::NET_CONFIGURATOR()
+{
+hostAllow = settings.GetHostAllow();
+}
+//-----------------------------------------------------------------------------
+NET_CONFIGURATOR::~NET_CONFIGURATOR()
+{
+
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::SetStgConfigurator(BASE_INT_CONFIGURATOR * bsc)
+{
+stgConfigurator = bsc;
+cp.SetStgConfigurator(stgConfigurator);
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR::UserGetAll(string * login, 
+                       USER_CONF_RES * conf,
+                       USER_STAT_RES * stat,
+                       time_t lastUpdate)
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR::TatiffGetAll(TARIFF_CONF * conf)
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+int NET_CONFIGURATOR::AdminGetAll(ADMIN_CONF  * conf)
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & NET_CONFIGURATOR::GetStrError()
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::Start()
+{
+cp.SetPort(settings.GetPort());
+cp.SetHostAllow(settings.GetHostAllow());
+cp.Start();
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::Stop()
+{
+cp.Stop();
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::Restart()
+{
+cp.Restart();
+}
+//-----------------------------------------------------------------------------
+CONF_STATUS NET_CONFIGURATOR::Status()
+{
+return cp.Status();
+}
+//-----------------------------------------------------------------------------
+BASE_SETTINGS * NET_CONFIGURATOR::GetConfiguratorSettings()
+{
+return &settings;
+}
+//-----------------------------------------------------------------------------
+void NET_CONFIGURATOR::SetAdmins(const ADMINS * a)
+{
+cp.SetAdmins(a);
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/net_configurator.h b/projects/stargazer/plugins/configuration/sgconfig2/net_configurator.h
new file mode 100644 (file)
index 0000000..ec1348f
--- /dev/null
@@ -0,0 +1,65 @@
+ /*
+ $Revision: 1.2 $
+ $Date: 2005/10/30 21:34:28 $
+ */
+
+#ifndef NET_CONFIGURATOR_H
+#define NET_CONFIGURATOR_H
+
+#include <time.h>
+#include <string>
+
+#include "../../base_ext_configurator.h"
+#include "../../base_int_configurator.h"
+#include "../../base_settings.h"
+#include "hostallow.h"
+#include "conffiles.h"
+#include "configproto.h"
+
+using namespace std;
+//-----------------------------------------------------------------------------
+class NET_CONFIGURATOR_SETTINGS: public BASE_SETTINGS
+{
+public:
+    virtual ~NET_CONFIGURATOR_SETTINGS(){};
+virtual const string & GetStrError();
+    virtual int ReadSettings(const CONFIGFILE & cf);
+    uint16_t    GetPort();
+    HOSTALLOW * GetHostAllow();
+
+private:
+    string strError;
+    uint16_t port;
+    HOSTALLOW hostAllow;
+};
+//-----------------------------------------------------------------------------
+class NET_CONFIGURATOR: public BASE_EXT_CONFIGURATOR
+{
+public:
+    NET_CONFIGURATOR();
+    virtual ~NET_CONFIGURATOR();
+    virtual void SetStgConfigurator(BASE_INT_CONFIGURATOR *);
+    virtual int UserGetAll(string * login, 
+                           USER_CONF_RES * conf,
+                           USER_STAT_RES * stat,
+                           time_t lastUpdate);
+    virtual int TatiffGetAll(TARIFF_CONF * conf);
+    virtual int AdminGetAll(ADMIN_CONF  * conf);
+    virtual const string & GetStrError();
+    virtual void Start();
+    virtual void Stop();
+    virtual void Restart();
+    virtual CONF_STATUS Status();
+    virtual BASE_SETTINGS * GetConfiguratorSettings();
+    virtual void SetAdmins(const ADMINS * a);
+
+private:
+    HOSTALLOW * hostAllow;
+    BASE_INT_CONFIGURATOR * stgConfigurator;
+    NET_CONFIGURATOR_SETTINGS settings;
+    string strError;
+    CONFIGPROTO cp;
+};
+//-----------------------------------------------------------------------------
+#endif //NET_CONFIGURATOR_H
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/parser.cpp b/projects/stargazer/plugins/configuration/sgconfig2/parser.cpp
new file mode 100644 (file)
index 0000000..95c20c0
--- /dev/null
@@ -0,0 +1,1466 @@
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sstream>
+
+#include "parser.h"
+#include "version.h"
+
+#define  UNAME_LEN      (256)
+//-----------------------------------------------------------------------------
+//  GET SERVER INFO
+//-----------------------------------------------------------------------------
+int PARSER_GET_SERVER_INFO::ParseStart(void *, const char *el, const char **)
+{
+answerList->erase(answerList->begin(), answerList->end());
+if (strcasecmp(el, "GetServerInfo") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_SERVER_INFO::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetServerInfo") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::CreateAnswer()
+{
+char s[UNAME_LEN + 128];
+char un[UNAME_LEN];
+struct utsname utsn;
+
+int tariff_type;
+
+tariff_type = 2;
+
+uname(&utsn);
+un[0] = 0;
+
+strcat(un, utsn.sysname);
+strcat(un, " ");
+strcat(un, utsn.release);
+strcat(un, " ");
+strcat(un, utsn.machine);
+strcat(un, " ");
+strcat(un, utsn.nodename);
+
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+answerList->push_back("<ServerInfo>");
+
+sprintf(s, "<version value=\"%s\"/>", SERVER_VERSION);
+answerList->push_back(s);
+
+sprintf(s, "<tariff_num value=\"%d\"/>", tariffs->GetTariffsNum());
+answerList->push_back(s);
+
+sprintf(s, "<tariff value=\"%d\"/>", 2);
+answerList->push_back(s);
+
+sprintf(s, "<users_num value=\"%d\"/>", users->GetUserNum());
+answerList->push_back(s);
+
+sprintf(s, "<uname value=\"%s\"/>", un);
+answerList->push_back(s);
+
+sprintf(s, "<dir_num value=\"%d\"/>", DIR_NUM);
+answerList->push_back(s);
+
+sprintf(s, "<day_fee value=\"%d\"/>", settings->GetDayFee());
+answerList->push_back(s);
+
+for (int i = 0; i< DIR_NUM; i++)
+    {
+    string dn2e;
+    Encode12str(dn2e, settings->GetDirName(i));
+    sprintf(s, "<dir_name_%d value=\"%s\"/>", i, dn2e.c_str());
+    answerList->push_back(s);
+    }
+
+answerList->push_back("</ServerInfo>");
+}
+//-----------------------------------------------------------------------------
+//  GET USER
+//-----------------------------------------------------------------------------
+PARSER_GET_USER::PARSER_GET_USER()
+{
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USER::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "GetUser") == 0)
+    {
+    if (attr[0] && attr[1])
+        login = attr[1];
+    else
+        {
+        //login.clear();
+        login.erase(login.begin(), login.end());
+        return -1;
+        }
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USER::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetUser") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::CreateAnswer()
+{
+string s;
+string enc;
+
+user_iter u;
+
+answerList->erase(answerList->begin(), answerList->end());
+
+if (users->FindByName(login, &u))
+    {
+    s = "<user result=\"error\"/>";
+    answerList->push_back(s);
+    return;
+    }
+
+s = "<user result=\"ok\">";
+answerList->push_back(s);
+
+s = "<login value=\"" + u->GetLogin() + "\"/>";
+answerList->push_back(s);
+
+if (currAdmin->GetPriv()->userConf || currAdmin->GetPriv()->userPasswd)
+    s = "<password value=\"" + u->property.password.Get() + "\" />";
+else
+    s = "<password value=\"++++++\"/>";
+answerList->push_back(s);
+
+strprintf(&s, "<cash value=\"%f\" />", u->property.cash.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<freemb value=\"%f\" />", u->property.freeMb.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<credit value=\"%f\" />", u->property.credit.Get());
+answerList->push_back(s);
+
+if (u->property.nextTariff.Get() != "")
+    {
+    strprintf(&s, "<tariff value=\"%s/%s\" />",
+              u->property.tariffName.Get().c_str(),
+              u->property.nextTariff.Get().c_str());
+    }
+else
+    {
+    strprintf(&s, "<tariff value=\"%s\" />",
+              u->property.tariffName.Get().c_str());
+    }
+
+answerList->push_back(s);
+
+Encode12str(enc, u->property.note);
+s = "<note value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.phone);
+s = "<phone value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.address);
+s = "<address value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.email);
+s = "<email value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+
+vector<USER_PROPERTY_LOGGED<string> *> userdata;
+userdata.push_back(u->property.userdata0.GetPointer());
+userdata.push_back(u->property.userdata1.GetPointer());
+userdata.push_back(u->property.userdata2.GetPointer());
+userdata.push_back(u->property.userdata3.GetPointer());
+userdata.push_back(u->property.userdata4.GetPointer());
+userdata.push_back(u->property.userdata5.GetPointer());
+userdata.push_back(u->property.userdata6.GetPointer());
+userdata.push_back(u->property.userdata7.GetPointer());
+userdata.push_back(u->property.userdata8.GetPointer());
+userdata.push_back(u->property.userdata9.GetPointer());
+
+string tmpI;
+for (unsigned i = 0; i < userdata.size(); i++)
+    {
+    Encode12str(enc, userdata[i]->Get());
+    s = "<UserData" + x2str(i, tmpI) + " value=\"" + enc + "\" />";
+    answerList->push_back(s);
+    }
+
+Encode12str(enc, u->property.realName);
+s = "<name value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+Encode12str(enc, u->property.group);
+s = "<GROUP value=\"" + enc + "\" />";
+answerList->push_back(s);
+
+strprintf(&s, "<status value=\"%d\" />", u->GetConnected());
+answerList->push_back(s);
+
+strprintf(&s, "<aonline value=\"%d\" />", u->property.alwaysOnline.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<currip value=\"%s\" />", inet_ntostring(u->GetCurrIP()).c_str());
+answerList->push_back(s);
+
+strprintf(&s, "<PingTime value=\"%lu\" />", u->GetPingTime());
+answerList->push_back(s);
+
+stringstream sstr;
+sstr << u->property.ips.Get();
+strprintf(&s, "<ip value=\"%s\" />", sstr.str().c_str());
+answerList->push_back(s);
+
+char * ss;
+ss = new char[DIR_NUM*25*4 + 50];
+char st[50];
+sprintf(ss, "<traff");
+DIR_TRAFF upload;
+DIR_TRAFF download;
+download = u->property.down.Get();
+upload = u->property.up.Get();
+
+for (int j = 0; j < DIR_NUM; j++)
+    {
+    string s;
+    x2str(upload[j], s);
+    sprintf(st, " MU%d=\"%s\"", j, s.c_str());
+    strcat(ss, st);
+
+    x2str(download[j], s);
+    sprintf(st, " MD%d=\"%s\"", j, s.c_str());
+    strcat(ss, st);
+
+    sprintf(st, " SU%d=\"0\"", j);
+    strcat(ss, st);
+
+    sprintf(st, " SD%d=\"0\"", j);
+    strcat(ss, st);
+    }
+strcat(ss, " />");
+answerList->push_back(ss);
+delete[] ss;
+
+strprintf(&s, "<down value=\"%d\" />", u->property.disabled.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<DisableDetailStat value=\"%d\" />", u->property.disabledDetailStat.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<passive value=\"%d\" />", u->property.passive.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<LastCash value=\"%f\" />", u->property.lastCashAdd.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<LastTimeCash value=\"%ld\" />", u->property.lastCashAddTime.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<LastActivityTime value=\"%ld\" />", u->property.lastActivityTime.Get());
+answerList->push_back(s);
+
+strprintf(&s, "<CreditExpire value=\"%ld\" />", u->property.creditExpire.Get());
+answerList->push_back(s);
+
+strprintf(&s, "</user>");
+answerList->push_back(s);
+}
+//-----------------------------------------------------------------------------
+//  GET USERS
+//-----------------------------------------------------------------------------
+PARSER_GET_USERS::PARSER_GET_USERS()
+{
+lastUserUpdateTime = 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USERS::ParseStart(void *, const char *el, const char ** attr)
+{
+/*if (attr && *attr && *(attr+1))
+    {
+    printfd(__FILE__, "attr=%s %s\n", *attr, *(attr+1));
+    }
+else
+    {
+    printfd(__FILE__, "attr = NULL\n");
+    }*/
+
+lastUpdateFound = false;
+if (strcasecmp(el, "GetUsers") == 0)
+    {
+    while (attr && *attr && *(attr+1))
+        {
+        if (strcasecmp(*attr, "LastUpdate") == 0)
+            {
+            if (str2x(*(attr+1), lastUserUpdateTime) == 0)
+                {
+                //printfd(__FILE__, "lastUserUpdateTime=%d\n", lastUserUpdateTime);
+                lastUpdateFound = true;
+                }
+            else
+                {
+                //printfd(__FILE__, "NO lastUserUpdateTime\n");
+                }
+            }
+        ++attr;
+        }
+
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USERS::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetUsers") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::CreateAnswer()
+{
+answerList->erase(answerList->begin(), answerList->end());
+
+string s;
+string userStart;
+string traffStart;
+string traffMiddle;
+string traffFinish;
+string middle;
+string userFinish;
+
+
+string enc;
+
+user_iter u;
+
+int h = users->OpenSearch();
+if (!h)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    users->CloseSearch(h);
+    return;
+    }
+string updateTime;
+x2str(time(NULL), updateTime);
+
+if (lastUpdateFound)
+    answerList->push_back("<Users LastUpdate=\"" + updateTime + "\">");
+else
+    answerList->push_back("<Users>");
+
+while (1)
+    {
+    if (users->SearchNext(h, &u))
+        {
+        break;
+        }
+    userStart = "<user login=\"" + u->GetLogin() + "\">";
+    middle = "";
+
+    if (u->property.password.ModificationTime() > lastUserUpdateTime)
+        {
+        if (currAdmin->GetPriv()->userConf || currAdmin->GetPriv()->userPasswd)
+            s = "<password value=\"" + u->property.password.Get() + "\" />";
+        else
+            s = "<password value=\"++++++\"/>";
+        middle += s;
+        }
+
+
+    if (u->property.cash.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<cash value=\"%f\" />", u->property.cash.Get());
+        middle += s;
+        //printfd(__FILE__, "cash value=\"%f\"\n", u->property.cash.Get());
+        }
+
+
+    if (u->property.freeMb.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<freemb value=\"%f\" />", u->property.freeMb.Get());
+        middle += s;
+        }
+
+    if (u->property.credit.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<credit value=\"%f\" />", u->property.credit.Get());
+        middle += s;
+        }
+
+    if (u->property.nextTariff.Get() != "")
+        {
+        if (u->property.tariffName.ModificationTime() > lastUserUpdateTime
+            || u->property.nextTariff.ModificationTime() > lastUserUpdateTime)
+            {
+            strprintf(&s, "<tariff value=\"%s/%s\" />",
+                      u->property.tariffName.Get().c_str(),
+                      u->property.nextTariff.Get().c_str());
+            middle += s;
+            }
+        }
+    else
+        {
+        if (u->property.tariffName.ModificationTime() > lastUserUpdateTime)
+            {
+            strprintf(&s, "<tariff value=\"%s\" />",
+                      u->property.tariffName.Get().c_str());
+            middle += s;
+            }
+        }
+
+    if (u->property.note.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.note);
+        strprintf(&s, "<note value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.phone.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.phone);
+        strprintf(&s, "<phone value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.address.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.address);
+        strprintf(&s, "<address value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.email.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.email);
+        strprintf(&s, "<email value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    vector<USER_PROPERTY_LOGGED<string> *> userdata;
+    userdata.push_back(u->property.userdata0.GetPointer());
+    userdata.push_back(u->property.userdata1.GetPointer());
+    userdata.push_back(u->property.userdata2.GetPointer());
+    userdata.push_back(u->property.userdata3.GetPointer());
+    userdata.push_back(u->property.userdata4.GetPointer());
+    userdata.push_back(u->property.userdata5.GetPointer());
+    userdata.push_back(u->property.userdata6.GetPointer());
+    userdata.push_back(u->property.userdata7.GetPointer());
+    userdata.push_back(u->property.userdata8.GetPointer());
+    userdata.push_back(u->property.userdata9.GetPointer());
+
+    string tmpI;
+    for (unsigned i = 0; i < userdata.size(); i++)
+        {
+        if (userdata[i]->ModificationTime() > lastUserUpdateTime)
+            {
+            Encode12str(enc, userdata[i]->Get());
+            s = "<UserData" + x2str(i, tmpI) + " value=\"" + enc + "\" />";
+            middle += s;
+            }
+        }
+
+    if (u->property.realName.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.realName);
+        strprintf(&s, "<name value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.group.ModificationTime() > lastUserUpdateTime)
+        {
+        Encode12str(enc, u->property.group);
+        strprintf(&s, "<GROUP value=\"%s\" />", enc.c_str());
+        middle += s;
+        }
+
+    if (u->property.alwaysOnline.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<aonline value=\"%d\" />", u->property.alwaysOnline.Get());
+        middle += s;
+        }
+
+    if (u->GetCurrIPModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<currip value=\"%s\" />", inet_ntostring(u->GetCurrIP()).c_str());
+        middle += s;
+        }
+
+
+    if (u->GetConnectedModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<status value=\"%d\" />", u->GetConnected());
+        middle += s;
+        }
+
+    if (u->GetPingTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<PingTime value=\"%lu\" />", u->GetPingTime());
+        middle += s;
+        }
+
+    if (u->property.ips.ModificationTime() > lastUserUpdateTime)
+        {
+        stringstream sstr;
+        sstr << u->property.ips.Get();
+        strprintf(&s, "<ip value=\"%s\" />", sstr.str().c_str());
+        middle += s;
+        }
+
+    char st[50];
+    traffStart = "<traff";
+    DIR_TRAFF upload;
+    DIR_TRAFF download;
+    download = u->property.down.Get();
+    upload = u->property.up.Get();
+    traffMiddle = "";
+
+    if (u->property.up.ModificationTime() > lastUserUpdateTime)
+        {
+        for (int j = 0; j < DIR_NUM; j++)
+            {
+            string s;
+            x2str(upload[j], s);
+            sprintf(st, " MU%d=\"%s\" ", j, s.c_str());
+            traffMiddle += st;
+            }
+        }
+
+    if (u->property.down.ModificationTime() > lastUserUpdateTime)
+        {
+        for (int j = 0; j < DIR_NUM; j++)
+            {
+            x2str(download[j], s);
+            sprintf(st, " MD%d=\"%s\" ", j, s.c_str());
+            traffMiddle += st;
+            }
+        }
+
+    traffFinish = " />";
+    if (traffMiddle.length() > 0)
+        {
+        middle += traffStart;
+        middle += traffMiddle;
+        middle += traffFinish;
+        }
+
+    if (u->property.disabled.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<down value=\"%d\" />", u->property.disabled.Get());
+        middle += s;
+        }
+
+    if (u->property.disabledDetailStat.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<DisableDetailStat value=\"%d\" />", u->property.disabledDetailStat.Get());
+        middle += s;
+        }
+
+    //printfd(__FILE__, ">>>>> %s\n", s.c_str());
+
+    if (u->property.passive.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<passive value=\"%d\" />", u->property.passive.Get());
+        middle += s;
+        }
+
+    if (u->property.lastCashAdd.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<LastCash value=\"%f\" />", u->property.lastCashAdd.Get());
+        middle += s;
+        }
+
+    if (u->property.lastCashAddTime.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<LastTimeCash value=\"%ld\" />", u->property.lastCashAddTime.Get());
+        middle += s;
+        }
+
+
+    if (u->property.lastActivityTime.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<LastActivityTime value=\"%ld\" />", u->property.lastActivityTime.Get());
+        middle += s;
+        }
+
+    if (u->property.creditExpire.ModificationTime() > lastUserUpdateTime)
+        {
+        strprintf(&s, "<CreditExpire value=\"%ld\" />", u->property.creditExpire.Get());
+        middle += s;
+        }
+
+
+    userFinish = "</user>";
+
+    if (middle.length() > 0)
+        {
+        /*printfd(__FILE__, "login: %s\n", u->GetLogin().c_str());
+        printfd(__FILE__, "middle: %s\n", middle.c_str());*/
+
+        answerList->push_back(userStart);
+        answerList->push_back(middle);
+        answerList->push_back(userFinish);
+        }
+    }
+
+users->CloseSearch(h);
+
+//answerList->push_back("</Users>");
+
+answerList->push_back("</Users>");
+}
+//-----------------------------------------------------------------------------
+//  ADD USER
+//-----------------------------------------------------------------------------
+PARSER_ADD_USER::PARSER_ADD_USER()
+{
+depth = 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_USER::ParseStart(void *, const char *el, const char **attr)
+{
+depth++;
+
+if (depth == 1)
+    {
+    if (strcasecmp(el, "AddUser") == 0)
+        {
+        return 0;
+        }
+    }
+else
+    {
+    if (strcasecmp(el, "login") == 0)
+        {
+        login = attr[1];
+        return 0;
+        }
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_USER::ParseEnd(void *, const char *el)
+{
+if (depth == 1)
+    {
+    if (strcasecmp(el, "AddUser") == 0)
+        {
+        CreateAnswer();
+        depth--;
+        return 0;
+        }
+    }
+
+depth--;
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_USER::Reset()
+{
+BASE_PARSER::Reset();
+depth = 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_USER::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (CheckUserData() == 0)
+    {
+    answerList->push_back("<AddUser result=\"ok\"/>");
+    }
+else
+    {
+    answerList->push_back("<AddUser result=\"error\" reason=\"Access denied\"/>");
+    }
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_USER::CheckUserData()
+{
+user_iter u;
+if (users->FindByName(login, &u))
+    {
+    return users->Add(login, *currAdmin);
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+//  PARSER CHG USER
+//-----------------------------------------------------------------------------
+PARSER_CHG_USER::PARSER_CHG_USER()
+{
+usr = NULL;
+ucr = NULL;
+upr = NULL;
+downr = NULL;
+
+Reset();
+}
+//-----------------------------------------------------------------------------
+PARSER_CHG_USER::~PARSER_CHG_USER()
+{
+delete usr;
+delete ucr;
+delete[] upr;
+delete[] downr;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::Reset()
+{
+depth = 0;
+delete usr;
+
+delete ucr;
+
+delete[] upr;
+
+delete[] downr;
+
+usr = new USER_STAT_RES;
+ucr = new USER_CONF_RES;
+
+upr = new RESETABLE<uint64_t>[DIR_NUM];
+downr = new RESETABLE<uint64_t>[DIR_NUM];
+};
+//-----------------------------------------------------------------------------
+string PARSER_CHG_USER::EncChar2String(const char * strEnc)
+{
+string str;
+Decode21str(str, strEnc);
+return str;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::ParseStart(void *, const char *el, const char **attr)
+{
+depth++;
+
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetUser") == 0)
+        {
+        return 0;
+        }
+    }
+else
+    {
+    //printfd(__FILE__, "el=%s\n", el);
+    if (strcasecmp(el, "login") == 0)
+        {
+        login = attr[1];
+        return 0;
+        }
+
+    if (strcasecmp(el, "ip") == 0)
+        {
+        try
+            {
+            ucr->ips = StrToIPS(attr[1]);
+            }
+        catch (...)
+            {
+            printfd(__FILE__, "StrToIPS Error!\n");
+            }
+        }
+
+    if (strcasecmp(el, "password") == 0)
+        {
+        ucr->password = attr[1];
+        return 0;
+        }
+
+    if (strcasecmp(el, "address") == 0)
+        {
+        ucr->address = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "aonline") == 0)
+        {
+        ucr->alwaysOnline = (*(attr[1]) != '0');
+        return 0;
+        }
+
+    if (strcasecmp(el, "cash") == 0)
+        {
+        if (attr[2] && (strcasecmp(attr[2], "msg") == 0))
+            {
+            cashMsg = EncChar2String(attr[3]);
+            }
+
+        double cash;
+        if (strtodouble2(attr[1], cash) == 0)
+            usr->cash = cash;
+
+        if (strcasecmp(attr[0], "set") == 0)
+            cashMustBeAdded = false;
+
+        if (strcasecmp(attr[0], "add") == 0)
+            cashMustBeAdded = true;
+
+        return 0;
+        }
+
+    if (strcasecmp(el, "CreditExpire") == 0)
+        {
+        long int creditExpire = 0;
+        if (str2x(attr[1], creditExpire) == 0)
+            ucr->creditExpire = (time_t)creditExpire;
+
+        return 0;
+        }
+
+    if (strcasecmp(el, "credit") == 0)
+        {
+        double credit;
+        if (strtodouble2(attr[1], credit) == 0)
+            ucr->credit = credit;
+        return 0;
+        }
+
+    if (strcasecmp(el, "freemb") == 0)
+        {
+        double freeMb;
+        if (strtodouble2(attr[1], freeMb) == 0)
+            usr->freeMb = freeMb;
+        return 0;
+        }
+
+    if (strcasecmp(el, "down") == 0)
+        {
+        int down = 0;
+        if (str2x(attr[1], down) == 0)
+            ucr->disabled = down;
+        return 0;
+        }
+
+    if (strcasecmp(el, "DisableDetailStat") == 0)
+        {
+        int disabledDetailStat = 0;
+        if (str2x(attr[1], disabledDetailStat) == 0)
+            ucr->disabledDetailStat = disabledDetailStat;
+        return 0;
+        }
+
+    if (strcasecmp(el, "email") == 0)
+        {
+        ucr->email = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    for (int i = 0; i < USERDATA_NUM; i++)
+        {
+        char name[15];
+        sprintf(name, "userdata%d", i);
+        if (strcasecmp(el, name) == 0)
+            {
+            ucr->userdata[i] = EncChar2String(attr[1]);
+            return 0;
+            }
+        }
+
+    if (strcasecmp(el, "group") == 0)
+        {
+        ucr->group = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "note") == 0)
+        {
+        ucr->note = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "passive") == 0)
+        {
+        int passive = 0;
+        if (str2x(attr[1], passive) == 0)
+            ucr->passive = passive;
+        return 0;
+        }
+
+    if (strcasecmp(el, "phone") == 0)
+        {
+        ucr->phone = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "Name") == 0)
+        {
+        ucr->realName = EncChar2String(attr[1]);
+        return 0;
+        }
+
+    if (strcasecmp(el, "traff") == 0)
+        {
+        int j = 0;
+        int dir;
+        DIR_TRAFF dtu;
+        DIR_TRAFF dtd;
+        unsigned long long t = 0;
+        while (attr[j])
+            {
+            dir = attr[j][2] - '0';
+
+            if (strncasecmp(attr[j], "md", 2) == 0)
+                {
+                str2x(attr[j+1], t);
+                dtd[dir] = t;
+                downr[dir] = t;
+                }
+            if (strncasecmp(attr[j], "mu", 2) == 0)
+                {
+                str2x(attr[j+1], t);
+                dtu[dir] = t;
+                upr[dir] = t;
+                }
+            j+=2;
+            }
+        usr->down = dtd;
+        usr->up = dtu;
+        return 0;
+        }
+
+    if (strcasecmp(el, "tariff") == 0)
+        {
+        if (strcasecmp(attr[0], "now") == 0)
+            ucr->tariffName = attr[1];
+
+        if (strcasecmp(attr[0], "delayed") == 0)
+            ucr->nextTariff = attr[1];
+
+        return 0;
+        }
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::ParseEnd(void *, const char *el)
+{
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetUser") == 0)
+        {
+        AplayChanges();
+        CreateAnswer();
+        depth--;
+        return 0;
+        }
+    }
+
+depth--;
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+switch (res)
+    {
+    case 0:
+        answerList->push_back("<SetUser result=\"ok\"/>");
+        break;
+    case -1:
+        answerList->push_back("<SetUser result=\"error\"/>");
+        break;
+    case -2:
+        answerList->push_back("<SetUser result=\"error\"/>");
+        break;
+    default:
+        answerList->push_back("<SetUser result=\"error\"/>");
+        break;
+    }
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::CheckUserData()
+{
+return true;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::AplayChanges()
+{
+user_iter u;
+
+res = 0;
+if (users->FindByName(login, &u))
+    {
+    res = -1;
+    return -1;
+    }
+
+if (!ucr->ips.res_empty())
+    if (!u->property.ips.Set(ucr->ips.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->address.res_empty())
+    if (!u->property.address.Set(ucr->address.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->alwaysOnline.res_empty())
+    if (!u->property.alwaysOnline.Set(ucr->alwaysOnline.const_data(),
+                                      currAdmin, login, store))
+        res = -1;
+
+if (!ucr->creditExpire.res_empty())
+    if (!u->property.creditExpire.Set(ucr->creditExpire.const_data(),
+                                      currAdmin, login, store))
+        res = -1;
+
+if (!ucr->credit.res_empty())
+    if (!u->property.credit.Set(ucr->credit.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!usr->freeMb.res_empty())
+    if (!u->property.freeMb.Set(usr->freeMb.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->disabled.res_empty())
+    if (!u->property.disabled.Set(ucr->disabled.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->disabledDetailStat.res_empty())
+    if (!u->property.disabledDetailStat.Set(ucr->disabledDetailStat.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->email.res_empty())
+    if (!u->property.email.Set(ucr->email.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->group.res_empty())
+    if (!u->property.group.Set(ucr->group.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->note.res_empty())
+    if (!u->property.note.Set(ucr->note.const_data(), currAdmin, login, store))
+        res = -1;
+
+vector<USER_PROPERTY_LOGGED<string> *> userdata;
+userdata.push_back(u->property.userdata0.GetPointer());
+userdata.push_back(u->property.userdata1.GetPointer());
+userdata.push_back(u->property.userdata2.GetPointer());
+userdata.push_back(u->property.userdata3.GetPointer());
+userdata.push_back(u->property.userdata4.GetPointer());
+userdata.push_back(u->property.userdata5.GetPointer());
+userdata.push_back(u->property.userdata6.GetPointer());
+userdata.push_back(u->property.userdata7.GetPointer());
+userdata.push_back(u->property.userdata8.GetPointer());
+userdata.push_back(u->property.userdata9.GetPointer());
+
+for (int i = 0; i < (int)userdata.size(); i++)
+    {
+    if (!ucr->userdata[i].res_empty())
+        {
+        if(!userdata[i]->Set(ucr->userdata[i].const_data(), currAdmin, login, store))
+            res = -1;
+        }
+    }
+
+if (!ucr->passive.res_empty())
+    if (!u->property.passive.Set(ucr->passive.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->password.res_empty())
+    if (!u->property.password.Set(ucr->password.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->phone.res_empty())
+    if (!u->property.phone.Set(ucr->phone.const_data(), currAdmin, login, store))
+        res = -1;
+
+if (!ucr->realName.res_empty())
+    if (!u->property.realName.Set(ucr->realName.const_data(), currAdmin, login, store))
+        res = -1;
+
+
+if (!usr->cash.res_empty())
+    {
+    //if (currAdmin->GetPriv()->userCash)
+        {
+        if (cashMustBeAdded)
+            {
+            if (!u->property.cash.Set(usr->cash.const_data() + u->property.cash,
+                                      currAdmin,
+                                      login,
+                                      store,
+                                      cashMsg))
+                res = -1;
+            }
+        else
+            {
+            if (!u->property.cash.Set(usr->cash.const_data(), currAdmin, login, store, cashMsg))
+                res = -1;
+            }
+        }
+    }
+
+
+if (!ucr->tariffName.res_empty())
+    {
+    if (tariffs->FindByName(ucr->tariffName.const_data()))
+        {
+        if (!u->property.tariffName.Set(ucr->tariffName.const_data(), currAdmin, login, store))
+            res = -1;
+        u->ResetNextTariff();
+        }
+    else
+        {
+        //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
+        res = -1;
+        }
+    }
+
+if (!ucr->nextTariff.res_empty())
+    {
+    if (tariffs->FindByName(ucr->nextTariff.const_data()))
+        {
+        if (!u->property.nextTariff.Set(ucr->nextTariff.const_data(), currAdmin, login, store))
+            res = -1;
+        }
+    else
+        {
+        //WriteServLog("SetUser: Tariff %s not found", ud.conf.tariffName.c_str());
+        res = -1;
+        }
+    }
+
+DIR_TRAFF up = u->property.up;
+DIR_TRAFF down = u->property.down;
+int upCount = 0;
+int downCount = 0;
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    if (!upr[i].res_empty())
+        {
+        up[i] = upr[i];
+        upCount++;
+        }
+    if (!downr[i].res_empty())
+        {
+        down[i] = downr[i];
+        downCount++;
+        }
+    }
+
+if (upCount)
+    if (!u->property.up.Set(up, currAdmin, login, store))
+        res = -1;
+
+if (downCount)
+    if (!u->property.down.Set(down, currAdmin, login, store))
+        res = -1;
+
+/*if (!usr->down.res_empty())
+    {
+    u->property.down.Set(usr->down.const_data(), currAdmin, login, store);
+    }
+if (!usr->up.res_empty())
+    {
+    u->property.up.Set(usr->up.const_data(), currAdmin, login, store);
+    }*/
+
+u->WriteConf();
+u->WriteStat();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//      SEND MESSAGE
+//-----------------------------------------------------------------------------
+int PARSER_SEND_MESSAGE::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "Message") == 0)
+    {
+    for (int i = 0; i < 14; i++)
+        {
+        if (attr[i] == NULL)
+            {
+            result = res_params_error;
+            CreateAnswer();
+            printfd(__FILE__, "To few parameters\n");
+            return 0;
+            }
+        }
+
+    for (int i = 0; i < 14; i+=2)
+        {
+        if (strcasecmp(attr[i], "login") == 0)
+            {
+            ParseLogins(attr[i+1]);
+            /*if (users->FindByName(login, &u))
+                {
+                result = res_unknown;
+                break;
+                }*/
+            }
+
+        if (strcasecmp(attr[i], "MsgVer") == 0)
+            {
+            str2x(attr[i+1], msg.header.ver);
+            if (msg.header.ver != 1)
+                result = res_params_error;
+            }
+
+        if (strcasecmp(attr[i], "MsgType") == 0)
+            {
+            str2x(attr[i+1], msg.header.type);
+            if (msg.header.type != 1)
+                result = res_params_error;
+            }
+
+        if (strcasecmp(attr[i], "Repeat") == 0)
+            {
+            str2x(attr[i+1], msg.header.repeat);
+            if (msg.header.repeat < 0)
+                result = res_params_error;
+            }
+
+        if (strcasecmp(attr[i], "RepeatPeriod") == 0)
+            {
+            str2x(attr[i+1], msg.header.repeatPeriod);
+            }
+
+        if (strcasecmp(attr[i], "ShowTime") == 0)
+            {
+            str2x(attr[i+1], msg.header.showTime);
+            }
+
+        if (strcasecmp(attr[i], "Text") == 0)
+            {
+            Decode21str(msg.text, attr[i+1]);
+            result = res_ok;
+            }
+        }
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_SEND_MESSAGE::ParseEnd(void *, const char *el)
+{
+//MSG msg;
+if (strcasecmp(el, "Message") == 0)
+    {
+    result = res_unknown;
+    for (unsigned i = 0; i < logins.size(); i++)
+        {
+        if (users->FindByName(logins[i], &u))
+            {
+            printfd(__FILE__, "User not found. %s\n", logins[i].c_str());
+            continue;
+            }
+        msg.header.creationTime = stgTime;
+        u->AddMessage(&msg);
+        result = res_ok;
+        }
+    /*if (result == res_ok)
+        {
+        if (strcmp(login, "*") == 0)
+            {
+            msg.text = text;
+            msg.prio = pri;
+            printfd(__FILE__, "SendMsg text: %s\n", text);
+            users->GetAllUsers(SendMessageAllUsers, &msg);
+            }
+        else
+            {
+            u->AddMessage(pri, text);
+            }
+        }*/
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_SEND_MESSAGE::ParseLogins(const char * login)
+{
+char * p;
+char * l = new char[strlen(login) + 1];
+strcpy(l, login);
+p = strtok(l, ":");
+logins.clear();
+while(p)
+    {
+    logins.push_back(p);
+    p = strtok(NULL, ":");
+    }
+
+delete[] l;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_SEND_MESSAGE::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+//answerList->push_back("<SendMessageResult value=\"ok\"/>");
+//
+switch (result)
+    {
+    case res_ok:
+        answerList->push_back("<SendMessageResult value=\"ok\"/>");
+        break;
+    case res_params_error:
+        printfd(__FILE__, "res_params_error\n");
+        answerList->push_back("<SendMessageResult value=\"Parameters error\"/>");
+        break;
+    case res_unknown:
+        printfd(__FILE__, "res_unknown\n");
+        answerList->push_back("<SendMessageResult value=\"Unknown user\"/>");
+        break;
+    default:
+        printfd(__FILE__, "res_default\n");
+    }
+
+}
+//-----------------------------------------------------------------------------
+//      DEL USER
+//-----------------------------------------------------------------------------
+int PARSER_DEL_USER::ParseStart(void *, const char *el, const char **attr)
+{
+res = 0;
+if (strcasecmp(el, "DelUser") == 0)
+    {
+    if (attr[0] == NULL || attr[1] == NULL)
+        {
+        //CreateAnswer("Parameters error!");
+        CreateAnswer();
+        return 0;
+        }
+
+    if (users->FindByName(attr[1], &u))
+        {
+        res = 1;
+        CreateAnswer();
+        return 0;
+        }
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_USER::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "DelUser") == 0)
+    {
+    if (!res)
+        users->Del(u->GetLogin(), *currAdmin);
+
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_DEL_USER::CreateAnswer()
+{
+if (res)
+    answerList->push_back("<DelUser value=\"error\" reason=\"User not found\"/>");
+else
+    answerList->push_back("<DelUser value=\"ok\"/>");
+}
+//-----------------------------------------------------------------------------
+/*void PARSERDELUSER::CreateAnswer(char * mes)
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+char str[255];
+sprintf(str, "<DelUser value=\"%s\"/>", mes);
+answerList->push_back(str);
+}*/
+//-----------------------------------------------------------------------------
+//  CHECK USER
+// <checkuser login="vasya" password=\"123456\"/>
+//-----------------------------------------------------------------------------
+int PARSER_CHECK_USER::ParseStart(void *, const char *el, const char **attr)
+{
+result = false;
+
+if (strcasecmp(el, "CheckUser") == 0)
+    {
+    if (attr[0] == NULL || attr[1] == NULL
+     || attr[2] == NULL || attr[3] == NULL)
+        {
+        result = false;
+        CreateAnswer();
+        printfd(__FILE__, "PARSER_CHECK_USER - attr err\n");
+        return 0;
+        }
+
+    user_iter user;
+    if (users->FindByName(attr[1], &user))
+        {
+        result = false;
+        CreateAnswer();
+        printfd(__FILE__, "PARSER_CHECK_USER - login err\n");
+        return 0;
+        }
+
+    if (strcmp(user->property.password.Get().c_str(), attr[3]))
+        {
+        result = false;
+        CreateAnswer();
+        printfd(__FILE__, "PARSER_CHECK_USER - passwd err\n");
+        return 0;
+        }
+
+    result = true;
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHECK_USER::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "CheckUser") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHECK_USER::CreateAnswer()
+{
+if (result)
+    answerList->push_back("<CheckUser value=\"Ok\"/>");
+else
+    answerList->push_back("<CheckUser value=\"Err\"/>");
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/parser.h b/projects/stargazer/plugins/configuration/sgconfig2/parser.h
new file mode 100644 (file)
index 0000000..a7b87db
--- /dev/null
@@ -0,0 +1,257 @@
+ /*
+ $Revision: 1.18 $
+ $Date: 2009/07/30 18:57:37 $
+ $Author: nobunaga $
+ */
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+#include "resetable.h"
+#include "stg_const.h"
+#include "base_store.h"
+#include "../../../admins.h"
+#include "../../../users.h"
+#include "stg_message.h"
+
+//-----------------------------------------------------------------------------
+class BASE_PARSER
+{
+public:
+    BASE_PARSER()
+        : admins(NULL),
+          users(NULL),
+          tariffs(NULL),
+          store(NULL),
+          settings(NULL),
+          currAdmin(NULL),
+          depth(0)
+    { };
+    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 CreateAnswer() = 0;
+    virtual void SetAnswerList(list<string> * ansList){answerList = ansList;};
+
+    virtual void SetUsers(USERS * u){users = u;};
+    virtual void SetAdmins(ADMINS * a){admins = a;};
+    virtual void SetTariffs(TARIFFS * t){tariffs = t;};
+    virtual void SetStore(BASE_STORE * s){store = s;};
+    virtual void SetStgSettings(const SETTINGS * s){settings = s;};
+
+    virtual void SetCurrAdmin(const ADMIN * cua){currAdmin = cua;};
+    virtual string & GetStrError(){return strError;};
+    virtual void Reset(){ answerList->clear(); depth = 0; };
+protected:
+    string              strError;
+    ADMINS *            admins;
+    USERS *             users;
+    TARIFFS *           tariffs;
+    BASE_STORE *        store;
+    const SETTINGS *    settings;
+    const ADMIN *       currAdmin;
+    int                 depth;
+    list<string> *      answerList;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_ADMINS: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+};
+//-----------------------------------------------------------------------------
+class PARSER_ADD_ADMIN: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+private:
+    string adminToAdd;
+};
+//-----------------------------------------------------------------------------
+class PARSER_DEL_ADMIN: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+private:
+    int CheckAttr(const char **attr);
+    string adminToDel;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_ADMIN: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+private:
+    RESETABLE<string>   login;
+    RESETABLE<string>   password;
+    RESETABLE<string>   privAsString;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_SERVER_INFO: public BASE_PARSER
+{
+public:
+    int ParseStart(void *data, const char *el, const char **attr);
+    int ParseEnd(void *data, const char *el);
+    void CreateAnswer();
+};
+
+//-----------------------------------------------------------------------------
+class PARSER_GET_USER: public BASE_PARSER
+{
+public:
+            PARSER_GET_USER();
+            ~PARSER_GET_USER(){};
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    string  login;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_USERS: public BASE_PARSER
+{
+public:
+            PARSER_GET_USERS();
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    time_t  lastUserUpdateTime;
+    bool    lastUpdateFound;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_TARIFFS: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+};
+//-----------------------------------------------------------------------------
+class PARSER_ADD_TARIFF: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    string  tariffToAdd;
+};
+//-----------------------------------------------------------------------------
+class PARSER_DEL_TARIFF: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    string  tariffToDel;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_TARIFF: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    int     ParseSlashedIntParams(int paramsNum, const string & s, int * params);
+    int     ParseSlashedDoubleParams(int paramsNum, const string & s, double * params);
+    int     CheckTariffData();
+    int     AplayChanges();
+
+    TARIFF_DATA_RES td;
+};
+//-----------------------------------------------------------------------------/
+class PARSER_ADD_USER: public BASE_PARSER
+{
+public:
+            PARSER_ADD_USER();
+    virtual ~PARSER_ADD_USER(){};
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+    void    Reset();
+private:
+    int     CheckUserData();
+    string  login;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_USER: public BASE_PARSER
+{
+public:
+                    PARSER_CHG_USER();
+                    ~PARSER_CHG_USER();
+    int             ParseStart(void *data, const char *el, const char **attr);
+    int             ParseEnd(void *data, const char *el);
+    void            CreateAnswer();
+    void            Reset();
+private:
+    string          EncChar2String(const char *);
+
+    USER_STAT_RES * usr;
+    USER_CONF_RES * ucr;
+    RESETABLE<uint64_t> * upr;
+    RESETABLE<uint64_t> * downr;
+    string          cashMsg;
+    string          login;
+
+    int             CheckUserData();
+    int             AplayChanges();
+    bool            cashMustBeAdded;
+    int             res;
+};
+//-----------------------------------------------------------------------------
+class PARSER_DEL_USER: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+
+private:
+    int         res;
+    user_iter   u;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHECK_USER: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    bool    result;
+};
+//-----------------------------------------------------------------------------
+class PARSER_SEND_MESSAGE: public BASE_PARSER
+{
+public:
+    int     ParseStart(void *data, const char *el, const char **attr);
+    int     ParseEnd(void *data, const char *el);
+    void    CreateAnswer();
+private:
+    enum {res_ok, res_params_error, res_unknown};
+    vector<string> logins;
+    int     ParseLogins(const char * logins);
+    int     result;
+    STG_MSG msg;
+    user_iter u;
+};
+//-----------------------------------------------------------------------------
+#endif //PARSER_H
+
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/parser_admin.cpp b/projects/stargazer/plugins/configuration/sgconfig2/parser_admin.cpp
new file mode 100644 (file)
index 0000000..f232fb2
--- /dev/null
@@ -0,0 +1,265 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "parser.h"
+
+//-----------------------------------------------------------------------------
+//  GET ADMINS
+//-----------------------------------------------------------------------------
+int PARSER_GET_ADMINS::ParseStart(void *, const char *el, const char **)
+{
+if (strcasecmp(el, "GetAdmins") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_ADMINS::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetAdmins") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_ADMINS::CreateAnswer()
+{
+const PRIV * priv = currAdmin->GetPriv();
+if (!priv->adminChg)
+    {
+    //answerList->clear();
+    answerList->erase(answerList->begin(), answerList->end());
+
+    answerList->push_back("<Error Result=\"Error. Access denied.\"/>");
+    return;
+    }
+
+string s;
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+answerList->push_back("<Admins>");
+ADMIN_CONF ac;
+int h = admins->OpenSearch();
+
+unsigned int p;
+while (admins->SearchNext(h, &ac) == 0)
+    {
+    //memcpy(&p, &ac.priv, sizeof(unsigned int));
+    p = (ac.priv.userStat << 0) +
+        (ac.priv.userConf << 2) +
+        (ac.priv.userCash << 4) +
+        (ac.priv.userPasswd << 6) +
+        (ac.priv.userAddDel << 8) +
+        (ac.priv.adminChg << 10) +
+        (ac.priv.tariffChg << 12);
+    strprintf(&s, "<admin login=\"%s\" priv=\"%d\"/>", ac.login.c_str(), p);
+    answerList->push_back(s);
+    }
+admins->CloseSearch(h);
+answerList->push_back("</Admins>");
+}
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+//  DEL ADMIN
+//-----------------------------------------------------------------------------
+int PARSER_DEL_ADMIN::ParseStart(void *, const char *el, const char **attr)
+{
+strError = "";
+if (strcasecmp(el, "DelAdmin") == 0)
+    {
+    adminToDel = attr[1];
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_ADMIN::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "DelAdmin") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_DEL_ADMIN::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (admins->Del(adminToDel, *currAdmin) == 0)
+    {
+    answerList->push_back("<DelAdmin Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<DelAdmin Result=\"Error. %s\"/>", admins->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_ADMIN::CheckAttr(const char **attr)
+{
+/*  <DelAdmin login=\"admin\">
+ *  attr[0] = "login" (word login)
+ *  attr[1] = login, value of login
+ *  attr[2] = NULL                  */
+
+if (strcasecmp(attr[0], "login") == 0 && attr[1] && !attr[2])
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+//  ADD ADMIN
+//-----------------------------------------------------------------------------
+int PARSER_ADD_ADMIN::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "AddAdmin") == 0)
+    {
+    adminToAdd = attr[1];
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_ADMIN::ParseEnd(void *, const char *el)
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (strcasecmp(el, "AddAdmin") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_ADMIN::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (admins->Add(adminToAdd, *currAdmin) == 0)
+    {
+    answerList->push_back("<AddAdmin Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<AddAdmin Result=\"Error. %s\"/>", admins->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//  CHG ADMIN
+//-----------------------------------------------------------------------------
+int PARSER_CHG_ADMIN::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "ChgAdmin") == 0)
+    {
+    for (int i = 0; i < 6; i+=2)
+        {
+        printfd(__FILE__, "PARSER_CHG_ADMIN::attr[%d] = %s\n", i, attr[i]);
+        if (attr[i] == NULL)
+            break;
+
+        if (strcasecmp(attr[i], "Login") == 0)
+            {
+            login = attr[i + 1];
+            continue;
+            }
+
+        if (strcasecmp(attr[i], "Priv") == 0)
+            {
+            privAsString = attr[i + 1];
+            continue;
+            }
+
+        if (strcasecmp(attr[i], "Password") == 0)
+            {
+            password = attr[i + 1];
+            continue;
+            }
+        }
+
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_ADMIN::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "ChgAdmin") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_ADMIN::CreateAnswer()
+{
+answerList->erase(answerList->begin(), answerList->end());
+
+ADMIN_CONF conf;
+conf.login = login;
+if (!login.res_empty())
+    {
+    string s;
+    //if (admins->FindAdmin(login.data()) != NULL)
+    //    {
+        if (!password.res_empty())
+            conf.password = password.data();
+
+        if (!privAsString.res_empty())
+            {
+            int p = 0;
+            if (str2x(privAsString.data().c_str(), p) < 0)
+                {
+                strprintf(&s, "<ChgAdmin Result = \"Incorrect parameter Priv.\"/>" );
+                answerList->push_back(s);
+                return;
+                }
+            //memcpy(&conf.priv, &p, sizeof(conf.priv));
+            conf.priv.userStat      = (p & 0x0003) >> 0x00; // 1+2
+            conf.priv.userConf      = (p & 0x000C) >> 0x02; // 4+8
+            conf.priv.userCash      = (p & 0x0030) >> 0x04; // 10+20
+            conf.priv.userPasswd    = (p & 0x00C0) >> 0x06; // 40+80
+            conf.priv.userAddDel    = (p & 0x0300) >> 0x08; // 100+200
+            conf.priv.adminChg      = (p & 0x0C00) >> 0x0A; // 400+800
+            conf.priv.tariffChg     = (p & 0x3000) >> 0x0C; // 1000+2000
+            }
+
+        if (admins->Change(conf, *currAdmin) != 0)
+            {
+            strprintf(&s, "<ChgAdmin Result = \"%s\"/>", admins->GetStrError().c_str());
+            answerList->push_back(s);
+            }
+        else
+            {
+            answerList->push_back("<ChgAdmin Result = \"Ok\"/>");
+            }
+        return;
+    //    }
+    //strprintf(&s, "<ChgAdmin Result = \"%s\"/>", admins->GetStrError().c_str());
+    //answerList->push_back(s);
+    //return;
+    }
+else
+    {
+    answerList->push_back("<ChgAdmin Result = \"Incorrect parameter login.\"/>");
+    }
+}
+//-----------------------------------------------------------------------------*/
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/parser_tariff.cpp b/projects/stargazer/plugins/configuration/sgconfig2/parser_tariff.cpp
new file mode 100644 (file)
index 0000000..29b4453
--- /dev/null
@@ -0,0 +1,489 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "parser.h"
+//#include "admins.h"
+//#include "tariff2.h"
+const int pt_mega = 1024 * 1024;
+//-----------------------------------------------------------------------------
+//  GET TARIFFS
+//-----------------------------------------------------------------------------
+int PARSER_GET_TARIFFS::ParseStart(void *, const char *el, const char **)
+{
+if (strcasecmp(el, "GetTariffs") == 0)
+    {
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_TARIFFS::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "GetTariffs") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_TARIFFS::CreateAnswer()
+{
+string s;
+char vs[100];
+int hd, hn, md, mn;
+
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+answerList->push_back("<Tariffs>");
+int h = tariffs->OpenSearch();
+
+TARIFF_DATA td;
+while (tariffs->SearchNext(h, &td) == 0)
+    {
+    s = "<tariff name=\"" + td.tariffConf.name + "\">";
+    //printfd(__FILE__, "%s\n", s.c_str());
+    answerList->push_back(s);
+
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        hd = td.dirPrice[j].hDay;
+        md = td.dirPrice[j].mDay;
+
+        hn = td.dirPrice[j].hNight;
+        mn = td.dirPrice[j].mNight;
+
+        strprintf(&s, "<Time%d value=\"%d:%d-%d:%d\"/>", j, hd, md, hn, mn);
+        answerList->push_back(s);
+        }
+
+    strprintf(&s, "    <PriceDayA value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", td.dirPrice[i].priceDayA * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PriceDayB value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", td.dirPrice[i].priceDayB * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PriceNightA value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", td.dirPrice[i].priceNightA * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <PriceNightB value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%.5f%s", td.dirPrice[i].priceNightB * pt_mega, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <Threshold value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%d%s", td.dirPrice[i].threshold, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <SinglePrice value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%d%s", td.dirPrice[i].singlePrice, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <NoDiscount value=\"");
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        snprintf(vs, 100, "%d%s", td.dirPrice[i].noDiscount, i+1 == DIR_NUM?"":"/");
+        s += vs;
+        }
+    s += "\"/>";
+    answerList->push_back(s);
+
+    strprintf(&s, "    <Fee value=\"%.5f\"/>", td.tariffConf.fee);
+    answerList->push_back(s);
+    //printfd(__FILE__, "%s\n", s.c_str());
+
+    strprintf(&s, "    <PassiveCost value=\"%.5f\"/>", td.tariffConf.passiveCost);
+    answerList->push_back(s);
+
+    strprintf(&s, "    <Free value=\"%.5f\"/>", td.tariffConf.free);
+    answerList->push_back(s);
+
+    switch (td.tariffConf.traffType)
+        {
+        case TRAFF_UP:
+            answerList->push_back("<TraffType value=\"up\"/>");
+            break;
+        case TRAFF_DOWN:
+            answerList->push_back("<TraffType value=\"down\"/>");
+            break;
+        case TRAFF_UP_DOWN:
+            answerList->push_back("<TraffType value=\"up+down\"/>");
+            break;
+        case TRAFF_MAX:
+            answerList->push_back("<TraffType value=\"max\"/>");
+            break;
+        }
+
+    answerList->push_back("</tariff>");
+    }
+tariffs->CloseSearch(h);
+answerList->push_back("</Tariffs>");
+}
+//-----------------------------------------------------------------------------
+//  ADD TARIFF
+//-----------------------------------------------------------------------------
+int PARSER_ADD_TARIFF::ParseStart(void *, const char *el, const char **attr)
+{
+if (strcasecmp(el, "AddTariff") == 0)
+    {
+    if (attr[1])
+        {
+        tariffToAdd = attr[1];
+        }
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_ADD_TARIFF::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "AddTariff") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_ADD_TARIFF::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (tariffs->Add(tariffToAdd, *currAdmin) == 0)
+    {
+    answerList->push_back("<AddTariff Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<AddTariff Result=\"Error. %s\"/>", tariffs->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+//  DEL TARIFF
+//-----------------------------------------------------------------------------
+int PARSER_DEL_TARIFF::ParseStart(void *, const char *el, const char **attr)
+{
+strError = "";
+if (strcasecmp(el, "DelTariff") == 0)
+    {
+    tariffToDel = attr[1];
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_DEL_TARIFF::ParseEnd(void *, const char *el)
+{
+if (strcasecmp(el, "DelTariff") == 0)
+    {
+    CreateAnswer();
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_DEL_TARIFF::CreateAnswer()
+{
+//answerList->clear();
+answerList->erase(answerList->begin(), answerList->end());
+
+if (tariffs->Del(tariffToDel, *currAdmin) == 0)
+    {
+    answerList->push_back("<DelTariff Result=\"Ok\"/>");
+    }
+else
+    {
+    string s;
+    strprintf(&s, "<DelTariff Result=\"Error. %s\"/>", tariffs->GetStrError().c_str());
+    answerList->push_back(s);
+    }
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//  CHG TARIFF
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseSlashedIntParams(int paramsNum, const string & s, int * params)
+{
+char * str = new char[s.size() + 1];
+char * p;
+strcpy(str, s.c_str());
+p = strtok(str, "/");
+
+for (int i = 0; i < paramsNum; i++)
+    {
+    if (p == NULL)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    if (str2x(p, params[i]) != 0)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    p = strtok(NULL, "/");
+    }
+
+delete[] str;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseSlashedDoubleParams(int paramsNum, const string & s, double * params)
+{
+char * str = new char[s.size() + 1];
+char * p;
+strcpy(str, s.c_str());
+p = strtok(str, "/");
+
+for (int i = 0; i < paramsNum; i++)
+    {
+    if (p == NULL)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    if (strtodouble2(p, params[i]) != 0)
+        {
+        delete[] str;
+        return -1;
+        }
+
+    p = strtok(NULL, "/");
+    }
+
+delete[] str;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseStart(void *, const char *el, const char **attr)
+{
+char st[50];
+double price[DIR_NUM];
+int t[DIR_NUM];
+depth++;
+
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetTariff") == 0)
+        {
+        td.tariffConf.name = attr[1];
+        return 0;
+        }
+    }
+else
+    {
+    string s;
+
+    if (strcasecmp(el, "PriceDayA") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceDayA = price[j] / pt_mega;
+        return 0;
+        }
+
+    if (strcasecmp(el, "PriceDayB") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceDayB = price[j] / pt_mega;
+        return 0;
+        }
+
+
+    if (strcasecmp(el, "PriceNightA") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceNightA = price[j] / pt_mega;
+        return 0;
+        }
+
+    if (strcasecmp(el, "PriceNightB") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedDoubleParams(DIR_NUM, s, price) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].priceNightB = price[j] / pt_mega;
+        return 0;
+        }
+
+    if (strcasecmp(el, "Threshold") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedIntParams(DIR_NUM, s, t) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].threshold = t[j];
+        return 0;
+        }
+
+    if (strcasecmp(el, "SinglePrice") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedIntParams(DIR_NUM, s, t) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].singlePrice = t[j];
+        return 0;
+        }
+
+    if (strcasecmp(el, "NoDiscount") == 0)
+        {
+        s = attr[1];
+        if (ParseSlashedIntParams(DIR_NUM, s, t) == 0)
+            for (int j = 0; j < DIR_NUM; j++)
+                td.dirPrice[j].noDiscount = t[j];
+        return 0;
+        }
+
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        snprintf(st, 50, "Time%d", j);
+        if (strcasecmp(el, st) == 0)
+            {
+            int h1, m1, h2, m2;
+            if (ParseTariffTimeStr(attr[1], h1, m1, h2, m2) == 0)
+                {
+                td.dirPrice[j].hDay = h1;
+                td.dirPrice[j].mDay = m1;
+                td.dirPrice[j].hNight = h2;
+                td.dirPrice[j].mNight = m2;
+                }
+            return 0;
+            }
+        }
+
+    if (strcasecmp(el, "Fee") == 0)
+        {
+        double fee;
+        if (strtodouble2(attr[1], fee) == 0)
+            td.tariffConf.fee = fee;
+        return 0;
+        }
+
+    if (strcasecmp(el, "PassiveCost") == 0)
+        {
+        double pc;
+        if (strtodouble2(attr[1], pc) == 0)
+            td.tariffConf.passiveCost = pc;
+        return 0;
+        }
+    if (strcasecmp(el, "Free") == 0)
+        {
+        double free;
+        if (strtodouble2(attr[1], free) == 0)
+            td.tariffConf.free = free;
+        return 0;
+        }
+
+    if (strcasecmp(el, "TraffType") == 0)
+        {
+        if (strcasecmp(attr[1], "up") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_UP;
+            return 0;
+            }
+
+        if (strcasecmp(attr[1], "down") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_DOWN;
+            return 0;
+            }
+        if (strcasecmp(attr[1], "up+down") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_UP_DOWN;
+            return 0;
+            }
+        if (strcasecmp(attr[1], "max") == 0)
+            {
+            td.tariffConf.traffType = TRAFF_MAX;
+            return 0;
+            }
+        return 0;
+        }
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_TARIFF::ParseEnd(void *, const char *el)
+{
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetTariff") == 0)
+        {
+        CreateAnswer();
+        depth--;
+        return 0;
+        }
+    }
+
+depth--;
+return -1;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_TARIFF::CreateAnswer()
+{
+answerList->erase(answerList->begin(), answerList->end());
+
+if (!td.tariffConf.name.data().empty())
+    {
+    TARIFF_DATA tariffData = td.GetData();
+    if (tariffs->Chg(tariffData, *currAdmin) == 0)
+        {
+        answerList->push_back("<SetTariff Result=\"ok\"/>");
+        return;
+        }
+    else
+        {
+        string s;
+        strprintf(&s, "<SetTariff Result=\"Change tariff error! %s\"/>", tariffs->GetStrError().c_str());
+        answerList->push_back(s);
+        return;
+        }
+    }
+answerList->push_back("<SetTariff Result=\"Change tariff error!\"/>");
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/proto.h b/projects/stargazer/plugins/configuration/sgconfig2/proto.h
new file mode 100644 (file)
index 0000000..7dc4b50
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef __PROTO_H__
+#define __PROTO_H__
+
+namespace SGCONF2 {
+
+/*
+ * --- Protocol structure (binary part) ---
+ *
+ *  Request:
+ *  |---------------|
+ *  |PROTOHEADER    |
+ *  |REQUESTHEADER  |
+ *  |---------------|
+ *  |   cryptodata  |
+ *  ~~~~~~~~~~~~~~~~~
+ *  |---------------|
+ *
+ *  Response:
+ *  |---------------|
+ *  |PROTOHEADER    |
+ *  |RESPONSEHEADER |
+ *  | error message |
+ *  |   cryptodata  |
+ *  ~~~~~~~~~~~~~~~~~
+ *  |---------------|
+ *
+ */
+
+    static char magic[8] = "STGCONF2";
+
+    enum RESPONSECODES {
+       E_OK = 0,       // No error
+       E_NET_ERROR,    // Network error (i.e. - timeout)
+       E_PROTO_ERROR,  // Protocol error (invalid magic, unsupported version, etc.)
+       E_INVALID_LOGIN,// Invalid login
+       E_PERMISSIONS   // Operation not permitted
+    };
+
+    struct PROTOHEADER {
+       char     magic[8];
+       uint32_t version;
+    };
+
+    struct REQUESTHEADER {
+       char     login[32];
+    };
+
+    struct CRYPTOHEADER {
+       char     login[32];
+       uint32_t dataSize; // Can't be 0
+    };
+
+    struct RESPONSEHEADER {
+       uint32_t code;
+       uint32_t errorMessageSize; // May be 0
+       uint32_t dataSize; // May be 0
+    };
+
+}
+
+#endif
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/rsconf.cpp b/projects/stargazer/plugins/configuration/sgconfig2/rsconf.cpp
new file mode 100644 (file)
index 0000000..48af0e7
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ *    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
+ */
+
+/*******************************************************************
+*
+*    DESCRIPTION: æÁÊÌ Ó ÏÓÎÏ×ÎÙÍÉ ÆÕÎËÃÉÑÍÉ ÄÌÑ ÓÅÔÅ×ÏÇÏ ÏÂÍÅÎÁ ÄÁÎÎÙÍÉ
+*    Ó ÍÅÎÅÄÖÅÒÏÍ ËÌÉÅÎÔÏ×. ðÒÉÅÍ, ÐÅÒÅÄÁÞÁ É ÛÉÆÒÏ×ÁÎÉÅ ÓÏÏÂÝÅÎÉÊ.
+*
+*    AUTHOR: Boris Mikhailenko <stg34@stargazer.dp.ua>
+*
+*    $Revision: 1.20 $
+*    $Date: 2009/10/31 15:44:02 $
+*
+*******************************************************************/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <pthread.h>
+
+#ifdef LINUX
+#include <error.h>
+#endif
+
+#ifdef FREE_BSD
+#include <sys/errno.h>
+#endif
+
+#ifdef FREE_BSD5
+#include <sys/errno.h>
+#endif
+
+extern int errno;
+
+#include "configproto.h"
+
+enum CONF_STATE
+    {
+    confHdr,
+    confLogin,
+    confLoginCipher,
+    confData
+    };
+
+enum
+    {
+    ans_ok = 0,
+    ans_err
+    };
+
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::Prepare()
+{
+list<string> ansList; //óÀÄÁ ÂÕÄÅÔ ÐÏÍÅÝÅΠÏÔ×ÅÔ ÄÌÑ ÍÅÎÅÄÖÅÒÁ ËÌÉÅÎÔÏ×
+int res;
+struct sockaddr_in listenAddr;
+
+sigset_t sigmask, oldmask;
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+sigaddset(&sigmask, SIGTERM);
+sigaddset(&sigmask, SIGUSR1);
+sigaddset(&sigmask, SIGHUP);
+pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
+
+listenSocket = socket(PF_INET, SOCK_STREAM, 0);
+
+if (listenSocket < 0)
+    {
+    errorStr = "Create NET_CONFIGURATOR socket failed.";
+    return -1;
+    }
+
+listenAddr.sin_family = PF_INET;
+listenAddr.sin_port = htons(port);
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+int lng = 1;
+
+if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
+    {
+    errorStr = "Setsockopt failed. " + string(strerror(errno));
+    return -1;
+    }
+
+res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
+
+if (res == -1)
+    {
+    errorStr = "Bind admin socket failed";
+    return -1;
+    }
+
+res = listen(listenSocket, 0);
+if (res == -1)
+    {
+    errorStr = "Listen admin socket failed";
+    return -1;
+    }
+outerAddrLen = sizeof(outerAddr);
+
+/*if (0 != fcntl(listenSocket, F_SETFL, O_NONBLOCK))
+    {
+    errorStr = "fcntl error!";
+    return -1;
+    }*/
+
+errorStr = "";
+nonstop = true;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::Stop()
+{
+nonstop = false;
+close(listenSocket);
+//TODO: Idiotism
+int                 sock;
+struct sockaddr_in  addr;
+socklen_t           addrLen;
+addr.sin_family = PF_INET;
+addr.sin_port = htons(port);
+addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+addrLen = sizeof(outerAddr);
+sock = socket(PF_INET, SOCK_STREAM, 0);
+connect(sock, (sockaddr*)&addr, addrLen);
+close(sock);
+//Idiotism end
+return 0;
+}
+//-----------------------------------------------------------------------------
+// æÕÎËÃÉÑ ÏÂÝÅÎÉÑ Ó ËÏÎÆÉÇÕÒÁÔÏÒÏÍ
+void * CONFIGPROTO::Run(void * a)
+{
+/*
+ * Function Name:ReciveSendConf
+ * Parameters: void * a ÕËÁÚÁÔÅÌØ ÎÁ ÜËÚÅÍÐÌÑÒ ËÌÁÓÓÁ CONFIGPROTO
+ * Description: üÔÁ ÆÕÎËÃÉÑ ÏÂÅÓÐÅÞÉ×ÁÅÔ ÓÅÔÅ×ÏÅ ×ÚÁÉÍÏÄÅÊÓÔ×ÉÅ
+ *  Ó íÅÎÅÄÖÅÒÏÍ ëÌÉÅÎÔÏ×. ÷ ÅÅ ÚÁÄÁÞÉ ×ÈÏÄÉÔ: ÐÒÉÅÍ ÚÁÐÒÏÓÏ× ÐÏ TCP/IP
+ *  ÉÈ ÒÁÓÛÉÆÒÏ×ËÁ, ÐÅÒÅÄÁÞÁ ÐÒÉÎÑÔÙÈ ÄÁÎÎÙÈ ÁÎÁÌÉÚÁÔÏÒÕ É ÏÔÐÒÁ×ËÁ ÏÔ×ÅÔÁ ÎÁÚÁÄ.
+ * Returns: ×ÏÚ×ÒÁÝÁÅÔ NULL
+ */
+
+CONFIGPROTO * cp = (CONFIGPROTO*)a;
+cp->state = confHdr;
+
+while (cp->nonstop)
+    {
+    cp->state = confHdr;
+    cp->outerSocket = accept(cp->listenSocket,
+                             (struct sockaddr*)(&cp->outerAddr),
+                             &cp->outerAddrLen);
+
+    if (!cp->nonstop)
+        {
+        continue;
+        }
+
+    if (cp->outerSocket == -1)
+        {
+        printfd(__FILE__, "accept failed\n");
+        usleep(100000);
+        continue;
+        }
+
+    cp->adminIP = *(unsigned int*)&(cp->outerAddr.sin_addr);
+
+    /* TODO
+    if (!cp->hostAllow->HostAllowed(cp->adminIP))
+        {
+        close(outerSocket);
+        continue;
+        }*/
+
+    printfd(__FILE__, "Connection accepted from %s\n", inet_ntostring(cp->outerAddr.sin_addr.s_addr).c_str());
+
+    if (cp->state == confHdr)
+        {
+        if (cp->RecvHdr(cp->outerSocket) < 0)
+            {
+            close(cp->outerSocket);
+            continue;
+            }
+        if (cp->state == confLogin)
+            {
+            if (cp->SendHdrAnswer(cp->outerSocket, ans_ok) < 0)
+                {
+                close(cp->outerSocket);
+                continue;
+                }
+
+            if (cp->RecvLogin(cp->outerSocket) < 0)
+                {
+                close(cp->outerSocket);
+                continue;
+                }
+
+            if (cp->state == confLoginCipher)
+                {
+                if (cp->SendLoginAnswer(cp->outerSocket, ans_ok) < 0)
+                    {
+                    close(cp->outerSocket);
+                    continue;
+                    }
+                if (cp->RecvLoginS(cp->outerSocket) < 0)
+                    {
+                    close(cp->outerSocket);
+                    continue;
+                    }
+
+                if (cp->state == confData)
+                    {
+                    if (cp->SendLoginSAnswer(cp->outerSocket, ans_ok) < 0)
+                        {
+                        close(cp->outerSocket);
+                        continue;
+                        }
+                    if (cp->RecvData(cp->outerSocket) < 0)
+                        {
+                        close(cp->outerSocket);
+                        continue;
+                        }
+                    cp->state = confHdr;
+                    }
+                else
+                    {
+                    if (cp->SendLoginSAnswer(cp->outerSocket, ans_err) < 0)
+                        {
+                        close(cp->outerSocket);
+                        continue;
+                        }
+                    cp->WriteLogAccessFailed(cp->adminIP);
+                    }
+                }
+            else
+                {
+                cp->WriteLogAccessFailed(cp->adminIP);
+                }
+            }
+        else
+            {
+            cp->WriteLogAccessFailed(cp->adminIP);
+            if (cp->SendHdrAnswer(cp->outerSocket, ans_err) < 0)
+                {
+                close(cp->outerSocket);
+                continue;
+                }
+            }
+        }
+    else
+        {
+        cp->WriteLogAccessFailed(cp->adminIP);
+        }
+    close(cp->outerSocket);
+    }
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvHdr(int sock)
+{
+char buf[sizeof(STG_HEADER)];
+memset(buf, 0, sizeof(STG_HEADER));
+int ret;
+int stgHdrLen = strlen(STG_HEADER);
+for (int i = 0; i < stgHdrLen; i++)
+    {
+    ret = recv(sock, &buf[i], 1, 0);
+    if (ret <= 0)
+        {
+        state = confHdr;
+        return -1;
+        }
+    }
+
+if (0 == strncmp(buf, STG_HEADER, strlen(STG_HEADER)))
+    {
+    state = confLogin;
+    return 0;
+    }
+else
+    {
+    SendError("Bad request");
+    }
+
+state = confHdr;
+return -1;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendHdrAnswer(int sock, int err)
+{
+int ret;
+
+if (err)
+    {
+    ret = send(sock, ERR_HEADER, sizeof(ERR_HEADER)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send ERR_HEADER error in SendHdrAnswer.");
+        return -1;
+        }
+    }
+else
+    {
+    ret = send(sock, OK_HEADER, sizeof(OK_HEADER)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send OK_HEADER error in SendHdrAnswer.");
+        return -1;
+        }
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvLogin(int sock)
+{
+char login[ADM_LOGIN_LEN+1];
+int ret;
+
+memset(login, 0, ADM_LOGIN_LEN + 1);
+
+//printfd(__FILE__, "RecvLogin\n");
+
+/*for (int i = 0; i < ADM_LOGIN_LEN; i++)
+    {
+    ret = recv(sock, &login[i], 1, 0);
+
+    if (ret <= 0)
+        {
+        close(sock);
+        state = confHdr;
+        return ENODATA;
+        }
+    }*/
+
+ret = recv(sock, login, ADM_LOGIN_LEN, 0);
+
+if (ret < 0)
+    {
+    // Error in network
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }
+
+if (ret < ADM_LOGIN_LEN)
+    {
+    // Error in protocol
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }
+
+currAdmin = admins->FindAdmin(login);
+adminLogin = login;
+state = confLoginCipher;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendLoginAnswer(int sock, int)
+{
+int ret;
+
+ret = send(sock, OK_LOGIN, sizeof(OK_LOGIN)-1, 0);
+if (ret < 0)
+    {
+    WriteServLog("Send OK_LOGIN error in SendLoginAnswer.");
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvLoginS(int sock)
+{
+char loginS[ADM_LOGIN_LEN + 1];
+char login[ADM_LOGIN_LEN + 1];
+int ret;
+BLOWFISH_CTX ctx;
+memset(loginS, 0, ADM_LOGIN_LEN + 1);
+
+//printfd(__FILE__, "RecvLoginS\n");
+
+/*for (int i = 0; i < ADM_LOGIN_LEN; i++)
+    {
+    ret = recv(sock, &loginS[i], 1, 0);
+
+    if (ret <= 0)
+        {
+        //printfd(__FILE__, "RecvLoginS close\n");
+        close(sock);
+        state = confHdr;
+        return ENODATA;
+        }
+    }*/
+
+int total = 0;
+
+while (total < ADM_LOGIN_LEN)
+    {
+    ret = recv(sock, &loginS[total], ADM_LOGIN_LEN - total, 0);
+
+    if (ret < 0)
+        {
+        // Network error
+        printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
+        close(sock);
+        state = confHdr;
+        return ENODATA;
+        }
+
+    total += ret;
+    }
+
+// TODO: implement select on socket
+/*if (total < ADM_LOGIN_LEN)
+    {
+    // Protocol error
+    printfd(__FILE__, "Protocol error. Need %d bytes of cryptologin. Got %d bytes.\n", ADM_LOGIN_LEN, ret);
+    close(sock);
+    state = confHdr;
+    return ENODATA;
+    }*/
+
+if (currAdmin == NULL)
+    {
+    state = confHdr;
+    return ENODATA;
+    }
+
+EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
+
+for (int i = 0; i < ADM_LOGIN_LEN/8; i++)
+    {
+    DecodeString(login + i*8, loginS + i*8, &ctx);
+    }
+
+if (currAdmin == admins->GetNoAdmin())
+    {
+    // If there are no admins registered in the system - give access with any password
+    state = confData;
+    return 0;
+    }
+
+if (strncmp(currAdmin->GetLogin().c_str(), login, ADM_LOGIN_LEN) != 0)
+    {
+    state = confHdr;
+    return ENODATA;
+    }
+
+state = confData;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendLoginSAnswer(int sock, int err)
+{
+int ret;
+
+if (err)
+    {
+    ret = send(sock, ERR_LOGINS, sizeof(ERR_LOGINS)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send ERR_LOGIN error in SendLoginAnswer.");
+        return -1;
+        }
+    }
+else
+    {
+    ret = send(sock, OK_LOGINS, sizeof(OK_LOGINS)-1, 0);
+    if (ret < 0)
+        {
+        WriteServLog("send OK_LOGINS error in SendLoginSAnswer.");
+        return -1;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::RecvData(int sock)
+{
+//printfd(__FILE__, "RecvData\n");
+int n = 0;
+int ret;
+char bufferS[8];
+char buffer[9];
+
+buffer[8] = 0;
+
+requestList.clear();
+BLOWFISH_CTX ctx;
+
+EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
+
+while (1)
+    {
+    /*ret = recv(sock, &bufferS[n++], 1, 0);
+    if (ret <= 0)
+        {
+        //printfd(__FILE__, "RecvData close\n");
+        close(sock);
+        return 0;
+        }*/
+    int total = 0;
+    bool done = false;
+    while (total < 8)
+        {
+        ret = recv(sock, &bufferS[total], 8 - total, 0);
+        if (ret < 0)
+            {
+            // Network error
+            close(sock);
+            return 0;
+            }
+
+        if (ret < 8)
+            {
+            if (memchr(buffer, 0, ret) != NULL)
+                {
+                done = true;
+                break;
+                }
+            }
+
+        total += ret;
+        }
+
+    DecodeString(buffer, bufferS, &ctx);
+    requestList.push_back(std::string(buffer, total));
+
+    if (done || memchr(buffer, 0, total) != NULL)
+        {
+        // ëÏÎÅàÐÏÓÙÌËÉ
+        if (ParseCommand())
+            {
+            SendError("Bad command");
+            }
+        return SendDataAnswer(sock);
+        }
+
+    /*if (n == 8)
+        {
+        n = 0;
+        DecodeString(buffer, bufferS, &ctx);
+        requestList.push_back(std::string(buffer, 8));
+        for (int j = 0; j < 8; j++)
+            {
+            if (buffer[j] == 0)
+                {
+                // ëÏÎÅàÐÏÓÙÌËÉ
+                if (ParseCommand())
+                    {
+                    SendError("Bad command");
+                    }
+                return SendDataAnswer(sock);
+                }
+            }
+        }*/
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int CONFIGPROTO::SendDataAnswer(int sock)
+{
+list<string>::iterator li;
+li = answerList.begin();
+
+BLOWFISH_CTX ctx;
+
+char buff[8];
+char buffS[8];
+int n = 0;
+int k = 0;
+int ret = 0;
+
+EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
+
+while (li != answerList.end())
+    {
+    while ((*li).c_str()[k])
+        {
+        buff[n%8] = (*li).c_str()[k];
+        n++;
+        k++;
+
+        if (n%8 == 0)
+            {
+            EncodeString(buffS, buff, &ctx);
+            ret = send(sock, buffS, 8, 0);
+            if (ret < 0)
+                {
+                return -1;
+                }
+            }
+        }
+    k = 0;// new node
+    li++;
+    }
+
+if (answerList.empty()) {
+    return 0;
+}
+
+buff[n%8] = 0;
+EncodeString(buffS, buff, &ctx);
+
+answerList.clear();
+
+return send(sock, buffS, 8, 0);
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::SendError(const char * text)
+{
+char s[255];
+answerList.clear();
+sprintf(s, "<Error value=\"%s\"/>", text);
+answerList.push_back(s);
+}
+//-----------------------------------------------------------------------------
+void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
+{
+WriteServLog("Admin's connect failed. IP %s", inet_ntostring(ip).c_str());
+}
+//-----------------------------------------------------------------------------
+
+
+
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/stgconfig.cpp b/projects/stargazer/plugins/configuration/sgconfig2/stgconfig.cpp
new file mode 100644 (file)
index 0000000..cec02d4
--- /dev/null
@@ -0,0 +1,313 @@
+#include <cstdio>
+#include <cunistd>
+#include <csignal>
+#include <functional>
+#include <algorithm>
+
+#include "stgconfig.h"
+#include "../../../tariffs.h"
+#include "../../../admins.h"
+#include "../../../users.h"
+
+class STGCONFIG_CREATOR
+{
+private:
+    STG_CONFIG * stgconfig;
+
+public:
+    STGCONFIG_CREATOR()
+        : stgconfig(new STG_CONFIG())
+        {
+        };
+    ~STGCONFIG_CREATOR()
+        {
+        delete stgconfig;
+        };
+
+    STG_CONFIG * GetPlugin()
+        {
+        return stgconfig;
+        };
+};
+
+STGCONFIG_CREATOR stgc;
+
+BASE_PLUGIN * GetPlugin()
+{
+return stgc.GetPlugin();
+}
+
+STG_CONFIG_SETTINGS::STG_CONFIG_SETTINGS()
+    : port(0)
+{
+}
+
+const string& STG_CONFIG_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+
+int STG_CONFIG_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+
+int STG_CONFIG_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    printfd(__FILE__, "Parameter 'Port' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+port = p;
+
+return 0;
+}
+
+uint16_t STG_CONFIG_SETTINGS::GetPort()
+{
+return port;
+}
+
+STG_CONFIG::STG_CONFIG()
+    : running(false),
+      stopped(true)
+{
+}
+
+string STG_CONFIG::GetVersion() const
+{
+return "Stg configurator v.2.00";
+}
+
+int STG_CONFIG::ParseSettings()
+{
+int ret = stgConfigSettings.ParseSettings(settings);
+if (ret)
+    errorStr = stgConfigSettings.GetStrError();
+return ret;
+}
+
+int STG_CONFIG::Start()
+{
+if (running)
+    return false;
+
+if (PrepareNetwork())
+    return true;
+
+stopped = false;
+
+config.SetPort(stgConfigSettings.GetPort());
+config.SetAdmins(admins);
+config.SetUsers(users);
+config.SetTariffs(tariffs);
+config.SetStgSettings(stgSettings);
+config.SetStore(store);
+
+if (config.Prepare())
+    {
+    errorStr = config.GetStrError();
+    return true;
+    }
+
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    errorStr = "Cannot create thread.";
+    printfd(__FILE__, "Cannot create thread\n");
+    return true;
+    }
+
+errorStr = "";
+return false;
+}
+
+int STG_CONFIG::Stop()
+{
+if (!running)
+    return false;
+
+running = false;
+
+config.Stop();
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25 && !stopped; i++)
+    {
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now killing it
+if (!stopped)
+    {
+    //TODO pthread_cancel()
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        printfd(__FILE__, "Cannot kill thread\n");
+        return FinalizeNetwork();
+        }
+    printfd(__FILE__, "STG_CONFIG killed\n");
+    }
+
+return FinalizeNetwork();
+}
+
+void * STG_CONFIG::Run(void * d)
+{
+STG_CONFIG * stgConf = static_cast<STG_CONFIG *>(d);
+stgConf->running = true;
+
+stgConf->RealRun();
+
+stgConf->stopped = true;
+return NULL;
+}
+
+uint16_t STG_CONFIG::GetStartPosition() const
+{
+return 220;
+}
+
+uint16_t STG_CONFIG::GetStopPosition() const
+{
+return 220;
+}
+
+bool PrepareNetwork()
+{
+struct sockaddr_in local;
+
+local.sin_family = AF_INET;
+local.sin_port = htons(port);
+local.sin_addr.s_addr = INADDR_ANY;
+
+sd = socket(AF_INET, SOCK_STREAM, 0);
+if (sd < 0)
+    {
+    errorStr = "Error creating socket: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    return true;
+    }
+
+if (bind(sd, static_cast<struct sockaddr *>(&local), sizeof(local)) < 0)
+    {
+    errorStr = "Error binding socket: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    return true;
+    }
+
+return false;
+}
+
+bool FinalizeNetwork()
+{
+if (close(sd) < 0)
+    {
+    errorStr = "Error closing socket: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    return true;
+    }
+return false;
+}
+
+void STG_CONFIG::RealRun()
+{
+if (listen(sd, 64) < 0)
+    {
+    errorStr = "Error listening socket: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    return;
+    }
+
+fd_set rfds;
+
+FD_ZERO(&rfds);
+FD_SET(sd, &rfds);
+
+running = true;
+while (running)
+    {
+    struct timeval tv;
+    tv.tv_sec = 0;
+    tv.tv_usec = 500000;
+
+    int res = select(sd + 1, &rfds, NULL, NULL, &tv);
+
+    if (res < 0)
+        {
+        // Error logging
+        }
+    else if (res == 0)
+        {
+        // Timeout
+        }
+    else
+        {
+        if (FD_ISSET(sd, &rfds))
+            {
+            AcceptConnection();
+            }
+        }
+
+    // Reorder: right part is done
+    std::list<ConnectionThread *>::iterator done(
+            std::remove_if(
+                connections.begin(),
+                connections.end(),
+                std::not1(std::mem_fun(&ConnectionThread::isDone))
+            )
+    );
+    // Destruct done
+    std::for_each(
+            done,
+            connections.end(),
+            DeleteConnection());
+    // Erase done
+    std::erase(done, connections.end());
+
+    }
+stopped = true;
+}
+
+void STG_CONFIG::AcceptConnection()
+{
+struct sockaddr_in remoteAddr;
+socklen_t len = sizeof(struct sockaddr_in);
+int rsd = accept(sd, &remoteAddr, &len);
+
+if (rsd < 0)
+    {
+    // Error logging
+    }
+
+connections.push_back(new ConnectionThread(this, rsd, remoteAddr, users, admins, tariffs, store, stgSettings));
+}
diff --git a/projects/stargazer/plugins/configuration/sgconfig2/stgconfig.h b/projects/stargazer/plugins/configuration/sgconfig2/stgconfig.h
new file mode 100644 (file)
index 0000000..a444953
--- /dev/null
@@ -0,0 +1,80 @@
+#include <pthread.h>
+
+#include <string>
+#include <list>
+
+#include "base_plugin.h"
+#include "base_store.h"
+#include "configproto.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class STG_CONFIG;
+
+//-----------------------------------------------------------------------------
+class STG_CONFIG_SETTINGS
+{
+public:
+                    STG_CONFIG_SETTINGS();
+    virtual         ~STG_CONFIG_SETTINGS(){};
+    const string &  GetStrError() const;
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    uint16_t        GetPort();
+private:
+    int     ParseIntInRange(const string & str, int min, int max, int * val);
+    string  errorStr;
+    int     port;
+};
+//-----------------------------------------------------------------------------
+class STG_CONFIG: public BASE_PLUGIN
+{
+public:
+    STG_CONFIG();
+    virtual ~STG_CONFIG(){};
+
+    void                SetUsers(USERS * u) { users = u; };
+    void                SetTariffs(TARIFFS * t) { tariffs = t; };
+    void                SetAdmins(ADMINS * a) { admins = a; };
+    void                SetStore(BASE_STORE * s) { store = s; };
+    void                SetTraffcounter(TRAFFCOUNTER *) {};
+    void                SetStgSettings(const SETTINGS * s) { stgConfigSettings = s; };
+    void                SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning() { return running; };
+
+    const string      & GetStrError() const { return errorStr; };
+    string              GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+private:
+    static void *       Run(void *);
+    void                RealRun();
+    bool                PrepareNetwork();
+    bool                FinalizeNetwork();
+    void                AcceptConnection();
+
+    mutable string      errorStr;
+    STG_CONFIG_SETTINGS stgConfigSettings;
+    pthread_t           thread;
+    bool                running;
+    bool                stopped;
+    CONFIGPROTO         config;
+    USERS *             users;
+    ADMINS *            admins;
+    TARIFFS *           tariffs;
+    BASE_STORE *        store;
+    MODULE_SETTINGS     settings;
+    const SETTINGS *    stgSettings;
+
+    std::list<ConnectionThread *> connections;
+
+    int                 sd;
+};
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/configuration/xrconfig/Makefile b/projects/stargazer/plugins/configuration/xrconfig/Makefile
new file mode 100644 (file)
index 0000000..db6b65b
--- /dev/null
@@ -0,0 +1,64 @@
+###############################################################################
+# $Id: Makefile,v 1.3 2009/03/03 15:49:35 faust Exp $
+###############################################################################
+DEFS = -DLINUX
+
+ifeq ($(OS),bsd)
+DEFS = -DFREE_BSD
+endif
+
+ifeq ($(OS),bsd5)
+DEFS = -DFREE_BSD5
+endif
+
+
+DIR_INCLUDE = ../../../../../include
+DIR_LIB = ../../../../../lib
+
+PROG = mod_conf_xr.so
+
+SRCS = ./xrconfig.cpp
+
+
+LIBS = $(LIB_THREAD)
+
+SEARCH_DIRS = -I $(DIR_INCLUDE)
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+CXXFLAGS = -g3 -Wall -fPIC
+LDFLAGS = -g3 -shared
+
+
+vpath %.a $(DIR_LIB)
+
+
+all: $(PROG)
+
+$(PROG): $(OBJS) $(LIBS)
+       $(CC) $^ $(LDFLAGS) -o $(PROG)
+
+clean:
+       rm -f deps $(PROG) *.o tags *.*~
+
+
+install:
+       echo TODO
+
+uninstall:
+       echo TODO
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+include deps
+endif
+endif
+
+deps:  $(SRCS)
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(DEFS) $(SEARCH_DIRS) -MM $$file` Makefile" >> deps ;\
+         echo -e '\t$$(CC) -c $$< $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS)' >> deps ;\
+       done
+
+
diff --git a/projects/stargazer/plugins/configuration/xrconfig/xrconfig.cpp b/projects/stargazer/plugins/configuration/xrconfig/xrconfig.cpp
new file mode 100644 (file)
index 0000000..cb156ee
--- /dev/null
@@ -0,0 +1,248 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "xrconfig.h"
+#include "../../../tariff2.h"
+#include "../../../admins.h"
+#include "../../../users.h"
+
+class XR_CONFIG_CREATOR
+{
+private:
+    XR_CONFIG * xrconfig;
+
+public:
+    XR_CONFIG_CREATOR()
+        : xrconfig(new XR_CONFIG())
+        {
+        };
+    ~XR_CONFIG_CREATOR()
+        {
+        delete xrconfig;
+        };
+
+    XR_CONFIG * GetPlugin()
+        {
+        return xrconfig;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+XRCONFIG_CREATOR xrc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+XR_CONFIG_SETTINGS::XR_CONFIG_SETTINGS()
+    : port(0)
+{
+}
+//-----------------------------------------------------------------------------
+const string & XR_CONFIG_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int XR_CONFIG_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (strtoi2(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int XR_CONFIG_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+/*int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    return -1;
+    }
+
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    return -1;
+    }
+port = p;*/
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+uint16_t XR_CONFIG_SETTINGS::GetPort()
+{
+return port;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return xrc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+const string XR_CONFIG::GetVersion() const
+{
+return "XR_configurator v.0.01";
+}
+//-----------------------------------------------------------------------------
+XR_CONFIG::XR_CONFIG()
+{
+isRunning = false;
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+void XR_CONFIG::SetUsers(USERS * u)
+{
+users = u;
+}
+//-----------------------------------------------------------------------------
+void XR_CONFIG::SetTariffs(TARIFFS * t)
+{
+tariffs = t;
+}
+//-----------------------------------------------------------------------------
+void XR_CONFIG::SetAdmins(ADMINS * a)
+{
+admins = a;
+}
+//-----------------------------------------------------------------------------
+void XR_CONFIG::SetStore(BASE_STORE * s)
+{
+store = s;
+}
+//-----------------------------------------------------------------------------
+void XR_CONFIG::SetStgSettings(const SETTINGS * s)
+{
+stgSettings = s;
+}
+//-----------------------------------------------------------------------------
+void XR_CONFIG::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int XR_CONFIG::ParseSettings()
+{
+int ret = xrConfigSettings.ParseSettings(settings);
+if (ret)
+    errorStr = xrConfigSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+const string & XR_CONFIG::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int XR_CONFIG::Start()
+{
+if (isRunning)
+    return 0;
+
+nonstop = true;
+
+config.SetPort(xrConfigSettings.GetPort());
+config.SetAdmins(admins);
+config.SetUsers(users);
+config.SetTariffs(tariffs);
+config.SetStgSettings(stgSettings);
+config.SetStore(store);
+
+if (config.Prepare())
+    {
+    errorStr = config.GetStrError();
+    return -1;
+    }
+
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    errorStr = "Cannot create thread.";
+    printfd(__FILE__, "Cannot create thread\n");
+    return -1;
+    }
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int XR_CONFIG::Stop()
+{
+if (!isRunning)
+    return 0;
+
+config.Stop();
+
+//5 seconds to thread stops itself
+int i;
+for (i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    stgUsleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now killing it
+if (isRunning)
+    {
+    //TODO pthread_cancel()
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill thread.";
+        printfd(__FILE__, "Cannot kill thread\n");
+        return -1;
+        }
+    printfd(__FILE__, "XR_CONFIG killed\n");
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool XR_CONFIG::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * XR_CONFIG::Run(void * d)
+{
+XR_CONFIG * stgConf = (XR_CONFIG *)d;
+stgConf->isRunning = true;
+
+stgConf->config.Run(&stgConf->config);
+
+stgConf->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t XR_CONFIG::GetStartPosition() const
+{
+return 221;
+}
+//-----------------------------------------------------------------------------
+uint16_t XR_CONFIG::GetStopPosition() const
+{
+return 221;
+}
+//-----------------------------------------------------------------------------
+int XR_CONFIG::SetUserCash(const string & admLogin, const string & usrLogin, double cash) const
+{
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/configuration/xrconfig/xrconfig.h b/projects/stargazer/plugins/configuration/xrconfig/xrconfig.h
new file mode 100644 (file)
index 0000000..79e099f
--- /dev/null
@@ -0,0 +1,78 @@
+#include <string>
+#include <pthread.h>
+#include "base_plugin.h"
+//#include "common_settings.h"
+#include "common.h"
+//#include "configproto.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class STG_CONFIG;
+
+//-----------------------------------------------------------------------------
+class XR_CONFIG_SETTINGS
+{
+public:
+                    XR_CONFIG_SETTINGS();
+    virtual         ~XR_CONFIG_SETTINGS(){};
+    const string &  GetStrError() const;
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    uint16_t        GetPort();
+
+private:
+    int     ParseIntInRange(const string & str, int min, int max, int * val);
+    string  errorStr;
+    int     port;
+};
+//-----------------------------------------------------------------------------
+class XR_CONFIG :public BASE_PLUGIN
+{
+public:
+    XR_CONFIG();
+    virtual ~XR_CONFIG(){};
+
+    void                SetUsers(USERS * u);
+    void                SetTariffs(TARIFFS * t);
+    void                SetAdmins(ADMINS * a);
+    void                SetStore(BASE_STORE * s);
+    void                SetTraffcounter(TRAFFCOUNTER * tc){};
+    void                SetStgSettings(const SETTINGS * s);
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+private:
+
+
+    int                 SetUserCash(const string & admLogin, const string & usrLogin, double cash) const;
+
+    static void *       Run(void *);
+    mutable string      errorStr;
+    XR_CONFIG_SETTINGS  xrConfigSettings;
+    pthread_t           thread;
+    bool                nonstop;
+    bool                isRunning;
+
+    //CONFIGPROTO         config;
+
+    USERS *             users;
+    ADMINS *            admins;
+    TARIFFS *           tariffs;
+    BASE_STORE *        store;
+    MODULE_SETTINGS     settings;
+    const SETTINGS *    stgSettings;
+};
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/plugins/other/ping/Makefile b/projects/stargazer/plugins/other/ping/Makefile
new file mode 100644 (file)
index 0000000..3e4d36d
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.11 2008/12/04 17:21:14 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+LIBS += $(LIB_THREAD)
+
+PROG = mod_ping.so
+
+SRCS = ./ping.cpp
+
+STGLIBS = -lstg_pinger -lstg_common
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/other/ping/ping.cpp b/projects/stargazer/plugins/other/ping/ping.cpp
new file mode 100644 (file)
index 0000000..7fa5aec
--- /dev/null
@@ -0,0 +1,421 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "ping.h"
+#include "../../../user.h"
+
+class PING_CREATOR
+{
+private:
+    PING * ping;
+
+public:
+    PING_CREATOR()
+        : ping(new PING())
+        {
+        };
+    ~PING_CREATOR()
+        {
+        delete ping;
+        };
+
+    PING * GetPlugin()
+        {
+        return ping;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PING_CREATOR pc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// ëÌÁÓÓ ÄÌÑ ÐÏÉÓËÁ ÀÚÅÒÁ × ÓÐÉÓËÅ ÎÏÔÉÆÉËÁÔÏÒÏ×
+template <typename varType>
+class IS_CONTAINS_USER: public binary_function<varType, user_iter, bool>
+{
+public:
+    bool operator()(varType notifier, user_iter user) const
+        {
+        return notifier.GetUser() == user;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return pc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PING_SETTINGS::PING_SETTINGS()
+    : pingDelay(0),
+      errorStr()
+{
+}
+//-----------------------------------------------------------------------------
+int PING_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+
+pv.param = "PingDelay";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'PingDelay\' not found.";
+    printfd(__FILE__, "Parameter 'PingDelay' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 5, 3600, &pingDelay))
+    {
+    errorStr = "Cannot parse parameter \'PingDelay\': " + errorStr;
+    printfd(__FILE__, "Canot parse parameter 'PingDelay'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PING_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+PING::PING()
+{
+pthread_mutex_init(&mutex, NULL);
+isRunning = false;
+}
+//-----------------------------------------------------------------------------
+PING::~PING()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+const string PING::GetVersion() const
+{
+return "Pinger v.1.01";
+}
+//-----------------------------------------------------------------------------
+void PING::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int PING::ParseSettings()
+{
+int ret = pingSettings.ParseSettings(settings);
+if (ret)
+    errorStr = pingSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+void PING::SetUsers(USERS * u)
+{
+users = u;
+}
+//-----------------------------------------------------------------------------
+const string & PING::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int PING::Start()
+{
+GetUsers();
+
+onAddUserNotifier.SetPinger(this);
+onDelUserNotifier.SetPinger(this);
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+nonstop = true;
+
+pinger.SetDelayTime(pingSettings.GetPingDelay());
+pinger.Start();
+
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    errorStr = "Cannot start thread.";
+    printfd(__FILE__, "Cannot start thread\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int PING::Stop()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (!isRunning)
+    return 0;
+
+pinger.Stop();
+nonstop = false;
+//5 seconds to thread stops itself
+for (int i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now kill it
+if (isRunning)
+    {
+    printfd(__FILE__, "kill PING thread.\n");
+    if (pthread_kill(thread, SIGINT))
+        {
+        errorStr = "Cannot kill PING thread.";
+        printfd(__FILE__, "Cannot kill PING thread.\n");
+        return -1;
+        }
+    printfd(__FILE__, "PING killed\n");
+    }
+
+users->DelNotifierUserAdd(&onAddUserNotifier);
+users->DelNotifierUserDel(&onDelUserNotifier);
+
+list<user_iter>::iterator users_iter;
+users_iter = usersList.begin();
+while (users_iter != usersList.end())
+    {
+    UnSetUserNotifiers(*users_iter);
+    users_iter++;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool PING::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+void * PING::Run(void * d)
+{
+PING * ping = (PING*)d;
+ping->isRunning = true;
+list<user_iter>::iterator iter;
+uint32_t ip;
+time_t t;
+
+while (ping->nonstop)
+    {
+    iter = ping->usersList.begin();
+        {
+        STG_LOCKER lock(&ping->mutex, __FILE__, __LINE__);
+        while (iter != ping->usersList.end())
+            {
+            if ((*iter)->property.ips.ConstData().OnlyOneIP())
+                {
+                ip = (*iter)->property.ips.ConstData()[0].ip;
+                if (ping->pinger.GetIPTime(ip, &t) == 0)
+                    {
+                    if (t)
+                        (*iter)->UpdatePingTime(t);
+                    }
+                }
+            else
+                {
+                ip = (*iter)->GetCurrIP();
+                if (ip)
+                    {
+                    if (ping->pinger.GetIPTime(ip, &t) == 0)
+                        {
+                        if (t)
+                            (*iter)->UpdatePingTime(t);
+                        }
+                    }
+                }
+            iter++;
+            }
+        }
+    for (int i = 0; i < 100; i++)
+        {
+        if (ping->nonstop)
+            {
+            usleep((10000*ping->pingSettings.GetPingDelay())/3 + 50000);
+            }
+        }
+    }
+ping->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+uint16_t PING::GetStartPosition() const
+{
+return 100;
+}
+//-----------------------------------------------------------------------------
+uint16_t PING::GetStopPosition() const
+{
+return 100;
+}
+//-----------------------------------------------------------------------------
+void PING::SetUserNotifiers(user_iter u)
+{
+CHG_CURRIP_NOTIFIER_PING    ChgCurrIPNotifier;
+CHG_IPS_NOTIFIER_PING       ChgIPNotifier;
+
+ChgCurrIPNotifier.SetPinger(this);
+ChgCurrIPNotifier.SetUser(u);
+ChgCurrIPNotifierList.push_front(ChgCurrIPNotifier);
+
+ChgIPNotifier.SetPinger(this);
+ChgIPNotifier.SetUser(u);
+ChgIPNotifierList.push_front(ChgIPNotifier);
+
+u->AddCurrIPAfterNotifier(&(*ChgCurrIPNotifierList.begin()));
+u->property.ips.AddAfterNotifier(&(*ChgIPNotifierList.begin()));
+}
+//-----------------------------------------------------------------------------
+void PING::UnSetUserNotifiers(user_iter u)
+{
+// ---          CurrIP              ---
+IS_CONTAINS_USER<CHG_CURRIP_NOTIFIER_PING>   IsContainsUserCurrIP;
+IS_CONTAINS_USER<CHG_IPS_NOTIFIER_PING>      IsContainsUserIP;
+
+list<CHG_CURRIP_NOTIFIER_PING>::iterator     currIPter;
+list<CHG_IPS_NOTIFIER_PING>::iterator        IPIter;
+
+currIPter = find_if(ChgCurrIPNotifierList.begin(),
+                    ChgCurrIPNotifierList.end(),
+                    bind2nd(IsContainsUserCurrIP, u));
+
+if (currIPter != ChgCurrIPNotifierList.end())
+    {
+    currIPter->GetUser()->DelCurrIPAfterNotifier(&(*currIPter));
+    ChgCurrIPNotifierList.erase(currIPter);
+    }
+// ---         CurrIP end          ---
+
+// ---          IP              ---
+IPIter = find_if(ChgIPNotifierList.begin(),
+                 ChgIPNotifierList.end(),
+                 bind2nd(IsContainsUserIP, u));
+
+if (IPIter != ChgIPNotifierList.end())
+    {
+    IPIter->GetUser()->property.ips.DelAfterNotifier(&(*IPIter));
+    ChgIPNotifierList.erase(IPIter);
+    }
+// ---          IP end          ---
+}
+//-----------------------------------------------------------------------------
+void PING::GetUsers()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+user_iter u;
+int h = users->OpenSearch();
+if (!h)
+    {
+    printfd(__FILE__, "users->OpenSearch() error\n");
+    return;
+    }
+
+while (users->SearchNext(h, &u) == 0)
+    {
+    usersList.push_back(u);
+    SetUserNotifiers(u);
+    if (u->property.ips.ConstData().OnlyOneIP())
+        {
+        pinger.AddIP(u->property.ips.ConstData()[0].ip);
+        }
+    else
+        {
+        uint32_t ip = u->GetCurrIP();
+        if (ip)
+            {
+            pinger.AddIP(ip);
+            }
+        }
+    }
+
+users->CloseSearch(h);
+}
+//-----------------------------------------------------------------------------
+void PING::AddUser(user_iter u)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+SetUserNotifiers(u);
+usersList.push_back(u);
+}
+//-----------------------------------------------------------------------------
+void PING::DelUser(user_iter u)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+UnSetUserNotifiers(u);
+
+list<user_iter>::iterator users_iter;
+users_iter = usersList.begin();
+
+while (users_iter != usersList.end())
+    {
+    if (u == *users_iter)
+        {
+        usersList.erase(users_iter);
+        break;
+        }
+    users_iter++;
+    }
+}
+//-----------------------------------------------------------------------------
+void CHG_CURRIP_NOTIFIER_PING::Notify(const uint32_t & oldIP, const uint32_t & newIP)
+{
+ping->pinger.DelIP(oldIP);
+if (newIP)
+    {
+    ping->pinger.AddIP(newIP);
+    }
+}
+//-----------------------------------------------------------------------------
+void CHG_IPS_NOTIFIER_PING::Notify(const USER_IPS & oldIPS, const USER_IPS & newIPS)
+{
+if (oldIPS.OnlyOneIP())
+    {
+    ping->pinger.DelIP(oldIPS[0].ip);
+    }
+
+if (newIPS.OnlyOneIP())
+    {
+    ping->pinger.AddIP(newIPS[0].ip);
+    }
+}
+//-----------------------------------------------------------------------------
+void ADD_USER_NONIFIER_PING::Notify(const user_iter & user)
+{
+ping->AddUser(user);
+}
+//-----------------------------------------------------------------------------
+void DEL_USER_NONIFIER_PING::Notify(const user_iter & user)
+{
+ping->DelUser(user);
+}
+//-----------------------------------------------------------------------------
+
+
+
+
+
+
diff --git a/projects/stargazer/plugins/other/ping/ping.h b/projects/stargazer/plugins/other/ping/ping.h
new file mode 100644 (file)
index 0000000..c94c17e
--- /dev/null
@@ -0,0 +1,155 @@
+ /*
+ $Revision: 1.16 $
+ $Date: 2009/06/23 11:32:28 $
+ $Author: faust $
+ */
+
+#ifndef PING_H
+#define PING_H
+
+#include <string>
+#include <pthread.h>
+
+#include "os_int.h"
+#include "base_plugin.h"
+#include "notifer.h"
+#include "user_ips.h"
+#include "pinger.h"
+#include "../../../users.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+class PING;
+//-----------------------------------------------------------------------------*/
+class CHG_CURRIP_NOTIFIER_PING: public PROPERTY_NOTIFIER_BASE<uint32_t>
+{
+public:
+    void        Notify(const uint32_t & oldIP, const uint32_t & newIP);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetPinger(const PING * p) { ping = p; }
+
+private:
+    user_iter   user;
+    const PING * ping;
+};
+//-----------------------------------------------------------------------------
+class CHG_IPS_NOTIFIER_PING: public PROPERTY_NOTIFIER_BASE<USER_IPS>
+{
+public:
+    void        Notify(const USER_IPS & oldIPS, const USER_IPS & newIPS);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetPinger(const PING * p) { ping = p; }
+
+private:
+    user_iter   user;
+    const PING * ping;
+};
+//-----------------------------------------------------------------------------
+class ADD_USER_NONIFIER_PING: public NOTIFIER_BASE<user_iter>
+{
+public:
+    ADD_USER_NONIFIER_PING(){};
+    virtual ~ADD_USER_NONIFIER_PING(){};
+
+    void SetPinger(PING * p) { ping = p; }
+    void Notify(const user_iter & user);
+
+private:
+    PING * ping;
+};
+//-----------------------------------------------------------------------------
+class DEL_USER_NONIFIER_PING: public NOTIFIER_BASE<user_iter>
+{
+public:
+    DEL_USER_NONIFIER_PING(){};
+    virtual ~DEL_USER_NONIFIER_PING(){};
+
+    void SetPinger(PING * p) { ping = p; }
+    void Notify(const user_iter & user);
+
+private:
+    PING * ping;
+};
+//-----------------------------------------------------------------------------
+class PING_SETTINGS
+{
+public:
+                    PING_SETTINGS();
+    virtual         ~PING_SETTINGS(){};
+    const string&   GetStrError() const { return errorStr; }
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    int             GetPingDelay(){ return pingDelay; };
+private:
+    int             ParseIntInRange(const string & str, int min, int max, int * val);
+    int             pingDelay;
+    mutable string  errorStr;
+};
+//-----------------------------------------------------------------------------
+class PING: public BASE_PLUGIN
+{
+friend class CHG_CURRIP_NOTIFIER_PING;
+friend class CHG_IPS_NOTIFIER_PING;
+public:
+    PING();
+    virtual ~PING();
+
+    void                SetUsers(USERS * u);
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER *){};
+    void                SetStore(BASE_STORE *){};
+    void                SetStgSettings(const SETTINGS *){};
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    const string      & GetStrError() const;
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+    void                AddUser(user_iter u);
+    void                DelUser(user_iter u);
+
+private:
+    void                GetUsers();
+    void                SetUserNotifiers(user_iter u);
+    void                UnSetUserNotifiers(user_iter u);
+    static void *       Run(void * d);
+    mutable string      errorStr;
+    PING_SETTINGS       pingSettings;
+    MODULE_SETTINGS     settings;
+    USERS             * users;
+    list<user_iter>     usersList;
+
+    /*
+    ÍÙ ÄÏÌÖÎÙ ÐÅÒÅÐÒÏ×ÅÒÉÔØ ×ÏÚÍÏÖÎÏÓÔØ ÐÉÎÇÏ×ÁÎÉÑ ÀÚÅÒÁ ÐÒÉ ÉÚÍÅÎÅÎÉÉ
+    ÓÌÅÄÕÀÝÉÈ ÅÇÏ ÐÁÒÁÍÅÔÒÏ×:
+    - currIP
+    - ips
+    */
+    pthread_t           thread;
+    pthread_mutex_t     mutex;
+    bool                nonstop;
+    bool                isRunning;
+    mutable STG_PINGER  pinger;
+
+    list<CHG_CURRIP_NOTIFIER_PING>   ChgCurrIPNotifierList;
+    list<CHG_IPS_NOTIFIER_PING>      ChgIPNotifierList;
+
+    ADD_USER_NONIFIER_PING      onAddUserNotifier;
+    DEL_USER_NONIFIER_PING      onDelUserNotifier;
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
+
diff --git a/projects/stargazer/plugins/other/radius/Makefile b/projects/stargazer/plugins/other/radius/Makefile
new file mode 100644 (file)
index 0000000..68be761
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.3 2010/04/26 12:44:42 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+LIBS += $(LIB_THREAD)
+
+PROG = mod_radius.so
+
+SRCS = ./radius.cpp
+
+STGLIBS = -lstg_common -lstg_crypto
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/other/radius/radius.cpp b/projects/stargazer/plugins/other/radius/radius.cpp
new file mode 100644 (file)
index 0000000..591f4b6
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ *    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>
+ */
+
+/*
+ *  This file contains a realization of radius data access plugin for Stargazer
+ *
+ *  $Revision: 1.14 $
+ *  $Date: 2009/12/13 14:17:13 $
+ *
+ */
+
+#include <algorithm>
+#include <signal.h>
+
+#include "radius.h"
+#include "common.h"
+
+extern volatile const time_t stgTime;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+class RAD_CREATOR
+{
+private:
+    RADIUS * rad;
+
+public:
+    RAD_CREATOR()
+        : rad(new RADIUS())
+        {
+        };
+    ~RAD_CREATOR()
+        {
+        delete rad;
+        };
+
+    RADIUS * GetPlugin()
+        {
+        return rad;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+RAD_CREATOR radc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return radc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+uint16_t RAD_SETTINGS::GetPort() const
+{
+return port;
+}
+//-----------------------------------------------------------------------------
+uint32_t RAD_SETTINGS::GetServerIP() const
+{
+return serverIP;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::GetPassword(string * password) const
+{
+*password = RAD_SETTINGS::password;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::GetAuthServices(list<string> * svcs) const
+{
+*svcs = authServices;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::GetAcctServices(list<string> * svcs) const
+{
+*svcs = acctServices;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::ParseIP(const string & str, uint32_t * IP)
+{
+*IP = inet_addr(str.c_str());
+return *IP == INADDR_NONE ? -1 : 0;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::ParseServices(const vector<string> & str, list<string> * lst)
+{
+    copy(str.begin(), str.end(), back_inserter(*lst));
+    list<string>::iterator it(find(lst->begin(),
+                                   lst->end(),
+                                   "empty"));
+    if (it != lst->end())
+        *it = "";
+
+    return 0;
+}
+//-----------------------------------------------------------------------------
+int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    printfd(__FILE__, "Parameter 'Port' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+    return -1;
+    }
+port = p;
+///////////////////////////
+pv.param = "ServerIP";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    serverIP = 0;
+    }
+else
+    {
+    if (ParseIP(pvi->value[0], &serverIP))
+        {
+        serverIP = 0;
+        }
+    }
+///////////////////////////
+pv.param = "Password";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Password\' not found.";
+    printfd(__FILE__, "Parameter 'Password' not found\n");
+    return -1;
+    }
+password = pvi->value[0];
+///////////////////////////
+pv.param = "AuthServices";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi != s.moduleParams.end())
+    {
+    ParseServices(pvi->value, &authServices);
+    }
+///////////////////////////
+pv.param = "AcctServices";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi != s.moduleParams.end())
+    {
+    ParseServices(pvi->value, &acctServices);
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+RADIUS::RADIUS()
+{
+isRunning = false;
+}
+//-----------------------------------------------------------------------------
+void RADIUS::SetUsers(USERS * u)
+{
+users = u;
+}
+//-----------------------------------------------------------------------------
+void RADIUS::SetStgSettings(const SETTINGS * s)
+{
+stgSettings = s;
+}
+//-----------------------------------------------------------------------------
+void RADIUS::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+void RADIUS::SetStore(BASE_STORE * s)
+{
+store = s;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ParseSettings()
+{
+int ret = radSettings.ParseSettings(settings);
+if (ret)
+    errorStr = radSettings.GetStrError();
+return ret;
+}
+//-----------------------------------------------------------------------------
+bool RADIUS::IsRunning()
+{
+return isRunning;
+}
+//-----------------------------------------------------------------------------
+const string RADIUS::GetVersion() const
+{
+return "RADIUS data access plugin v 0.6";
+}
+//-----------------------------------------------------------------------------
+uint16_t RADIUS::GetStartPosition() const
+{
+// Start before any authorizers!!!
+return 20;
+}
+//-----------------------------------------------------------------------------
+uint16_t RADIUS::GetStopPosition() const
+{
+return 20;
+}
+//-----------------------------------------------------------------------------
+void RADIUS::SetUserNotifier(user_iter)
+{
+}
+//-----------------------------------------------------------------------------
+void RADIUS::UnSetUserNotifier(user_iter)
+{
+}
+//-----------------------------------------------------------------------------
+int RADIUS::PrepareNet()
+{
+sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (sock < 0)
+    {
+    errorStr = "Cannot create socket.";
+    printfd(__FILE__, "Cannot create socket\n");
+    return -1;
+    }
+
+inAddr.sin_family = AF_INET;
+inAddr.sin_port = htons(port);
+inAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0)
+    {
+    errorStr = "RADIUS: Bind failed.";
+    printfd(__FILE__, "Cannot bind socket\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::FinalizeNet()
+{
+close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::Start()
+{
+string password;
+
+radSettings.GetPassword(&password);
+port = radSettings.GetPort();
+serverIP = radSettings.GetServerIP();
+radSettings.GetAuthServices(&authServices);
+radSettings.GetAcctServices(&acctServices);
+
+InitEncrypt(&ctx, password);
+
+nonstop = true;
+
+if (PrepareNet())
+    {
+    return -1;
+    }
+
+if (!isRunning)
+    {
+    if (pthread_create(&thread, NULL, Run, this))
+        {
+        errorStr = "Cannot create thread.";
+        printfd(__FILE__, "Cannot create thread\n");
+        return -1;
+        }
+    }
+
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::Stop()
+{
+if (!IsRunning())
+    return 0;
+
+nonstop = false;
+
+map<string, RAD_SESSION>::iterator it;
+for (it = sessions.begin(); it != sessions.end(); ++it)
+    {
+    user_iter ui;
+    if (users->FindByName(it->second.userName, &ui))
+        {
+        ui->Unauthorize(this);
+        }
+    }
+sessions.erase(sessions.begin(), sessions.end());
+
+FinalizeNet();
+
+if (isRunning)
+    {
+    //5 seconds to thread stops itself
+    for (int i = 0; i < 25 && isRunning; i++)
+        {
+        usleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (isRunning)
+        {
+        if (pthread_kill(thread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            printfd(__FILE__, "Cannot kill thread\n");
+            return -1;
+            }
+        printfd(__FILE__, "RADIUS::Stop killed Run\n");
+        }
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * RADIUS::Run(void * d)
+{
+RADIUS * rad = (RADIUS *)d;
+RAD_PACKET packet;
+
+rad->isRunning = true;
+
+while (rad->nonstop)
+    {
+    if (!rad->WaitPackets(rad->sock))
+        {
+        continue;
+        }
+    if (rad->RecvData(&packet))
+        {
+        printfd(__FILE__, "RADIUS::Run Error on RecvData\n");
+        }
+    else
+        {
+        if (rad->ProcessData(&packet))
+            {
+            packet.packetType = RAD_REJECT_PACKET;
+            }
+        rad->Send(packet);
+        }
+    }
+
+rad->isRunning = false;
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::RecvData(RAD_PACKET * packet)
+{
+    int8_t buf[RAD_MAX_PACKET_LEN];
+    outerAddrLen = sizeof(struct sockaddr_in);
+    int dataLen = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, (struct sockaddr *)&outerAddr, &outerAddrLen);
+    if (dataLen > 0) {
+        Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8);
+    }
+    if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
+        {
+        printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic);
+        return -1;
+        }
+    return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::Send(const RAD_PACKET & packet)
+{
+int res, len = sizeof(RAD_PACKET);
+char buf[1032];
+
+Encrypt(&ctx, buf, (char *)&packet, len / 8);
+res = sendto(sock, buf, len, 0, (struct sockaddr *)&outerAddr, outerAddrLen);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessData(RAD_PACKET * packet)
+{
+//struct in_addr addr = {packet->ip};
+if (strncmp((const char *)packet->protoVer, "01", 2))
+    {
+    printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n");
+    return -1;
+    }
+switch (packet->packetType)
+    {
+    case RAD_AUTZ_PACKET:
+        return ProcessAutzPacket(packet);
+    case RAD_AUTH_PACKET:
+        return ProcessAuthPacket(packet);
+    case RAD_POST_AUTH_PACKET:
+        return ProcessPostAuthPacket(packet);
+    case RAD_ACCT_START_PACKET:
+        return ProcessAcctStartPacket(packet);
+    case RAD_ACCT_STOP_PACKET:
+        return ProcessAcctStopPacket(packet);
+    case RAD_ACCT_UPDATE_PACKET:
+        return ProcessAcctUpdatePacket(packet);
+    case RAD_ACCT_OTHER_PACKET:
+        return ProcessAcctOtherPacket(packet);
+    default:
+        printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType);
+        return -1;
+    };
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessAutzPacket(RAD_PACKET * packet)
+{
+USER_CONF conf;
+
+if (!IsAllowedService((char *)packet->service))
+    {
+    printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service);
+    packet->packetType = RAD_REJECT_PACKET;
+    return 0;
+    }
+
+if (store->RestoreUserConf(&conf, (char *)packet->login))
+    {
+    packet->packetType = RAD_REJECT_PACKET;
+    printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login);
+    return 0;
+    }
+
+// At this point service can be authorized at least
+// So we send a plain-text password
+
+packet->packetType = RAD_ACCEPT_PACKET;
+strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessAuthPacket(RAD_PACKET * packet)
+{
+user_iter ui;
+
+if (!CanAcctService((char *)packet->service))
+    {
+
+    // There are no sense to check for allowed service
+    // It has allready checked at previous stage (authorization)
+
+    printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service);
+    packet->packetType = RAD_ACCEPT_PACKET;
+    return 0;
+    }
+
+// At this point we have an accountable service
+// All other services got a password if allowed or rejected
+
+if (!FindUser(&ui, (char *)packet->login))
+    {
+    packet->packetType = RAD_REJECT_PACKET;
+    printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login);
+    return 0;
+    }
+
+if (ui->IsInetable())
+    {
+    packet->packetType = RAD_ACCEPT_PACKET;
+    }
+else
+    {
+    packet->packetType = RAD_REJECT_PACKET;
+    }
+
+packet->packetType = RAD_ACCEPT_PACKET;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet)
+{
+user_iter ui;
+
+if (!CanAcctService((char *)packet->service))
+    {
+
+    // There are no sense to check for allowed service
+    // It has allready checked at previous stage (authorization)
+
+    packet->packetType = RAD_ACCEPT_PACKET;
+    return 0;
+    }
+
+if (!FindUser(&ui, (char *)packet->login))
+    {
+    packet->packetType = RAD_REJECT_PACKET;
+    printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login);
+    return 0;
+    }
+
+// I think that only Framed-User services has sense to be accountable
+// So we have to supply a Framed-IP
+
+USER_IPS ips = ui->property.ips;
+packet->packetType = RAD_ACCEPT_PACKET;
+
+// Additional checking for Framed-User service
+
+if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN))
+    packet->ip = ips[0].ip;
+else
+    packet->ip = 0;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet)
+{
+user_iter ui;
+
+if (!FindUser(&ui, (char *)packet->login))
+    {
+    packet->packetType = RAD_REJECT_PACKET;
+    printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login);
+    return 0;
+    }
+
+// At this point we have to unauthorize user only if it is an accountable service
+
+if (CanAcctService((char *)packet->service))
+    {
+    if (sessions.find((const char *)packet->sessid) != sessions.end())
+        {
+        printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n");
+        packet->packetType = RAD_REJECT_PACKET;
+        return -1;
+        }
+    USER_IPS ips = ui->property.ips;
+    if (ui->Authorize(ips[0].ip, "", 0xffFFffFF, this))
+        {
+        printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login);
+        packet->packetType = RAD_REJECT_PACKET;
+        return -1;
+        }
+    sessions[(const char *)packet->sessid].userName = (const char *)packet->login;
+    sessions[(const char *)packet->sessid].serviceType = (const char *)packet->service;
+    for_each(sessions.begin(), sessions.end(), SPrinter());
+    }
+else
+    {
+    printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service);
+    }
+
+packet->packetType = RAD_ACCEPT_PACKET;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet)
+{
+map<string, RAD_SESSION>::iterator sid;
+
+if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end())
+    {
+    printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n");
+    packet->packetType = RAD_REJECT_PACKET;
+    return -1;
+    }
+
+user_iter ui;
+
+if (!FindUser(&ui, sid->second.userName))
+    {
+    packet->packetType = RAD_REJECT_PACKET;
+    printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str());
+    return 0;
+    }
+
+sessions.erase(sid);
+
+ui->Unauthorize(this);
+
+packet->packetType = RAD_ACCEPT_PACKET;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet)
+{
+// Fake. May be used later
+packet->packetType = RAD_ACCEPT_PACKET;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet)
+{
+// Fake. May be used later
+packet->packetType = RAD_ACCEPT_PACKET;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void RADIUS::InitEncrypt(BLOWFISH_CTX * ctx, const string & password)
+{
+unsigned char keyL[RAD_PASSWORD_LEN];  // Пароль для шифровки
+memset(keyL, 0, RAD_PASSWORD_LEN);
+strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
+Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN);
+}
+//-----------------------------------------------------------------------------
+void RADIUS::Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
+{
+// len8 - длина в 8-ми байтовых блоках
+if (dst != src)
+    memcpy(dst, src, len8 * 8);
+
+for (int i = 0; i < len8; i++)
+    Blowfish_Encrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
+}
+//-----------------------------------------------------------------------------
+void RADIUS::Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
+{
+// len8 - длина в 8-ми байтовых блоках
+if (dst != src)
+    memcpy(dst, src, len8 * 8);
+
+for (int i = 0; i < len8; i++)
+    Blowfish_Decrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
+}
+//-----------------------------------------------------------------------------
+void RADIUS::PrintServices(const list<string> & svcs)
+{
+    for_each(svcs.begin(), svcs.end(), Printer());
+}
+//-----------------------------------------------------------------------------
+bool RADIUS::FindUser(user_iter * ui, const std::string & login) const
+{
+if (users->FindByName(login, ui))
+    {
+    return false;
+    }
+return true;
+}
+//-----------------------------------------------------------------------------
+bool RADIUS::CanAuthService(const std::string & svc) const
+{
+    return find(authServices.begin(), authServices.end(), svc) != authServices.end();
+}
+//-----------------------------------------------------------------------------
+bool RADIUS::CanAcctService(const std::string & svc) const
+{
+    return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end();
+}
+//-----------------------------------------------------------------------------
+bool RADIUS::IsAllowedService(const std::string & svc) const
+{
+    return CanAuthService(svc) || CanAcctService(svc);
+}
+//-----------------------------------------------------------------------------
+bool RADIUS::WaitPackets(int sd) const
+{
+fd_set rfds;
+FD_ZERO(&rfds);
+FD_SET(sd, &rfds);
+
+struct timeval tv;
+tv.tv_sec = 0;
+tv.tv_usec = 500000;
+
+int res = select(sd + 1, &rfds, NULL, NULL, &tv);
+if (res == -1) // Error
+    {
+    if (errno != EINTR)
+        {
+        printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
+        }
+    return false;
+    }
+
+if (res == 0) // Timeout
+    {
+    return false;
+    }
+
+return true;
+}
diff --git a/projects/stargazer/plugins/other/radius/radius.h b/projects/stargazer/plugins/other/radius/radius.h
new file mode 100644 (file)
index 0000000..b26a3bb
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Radius data access plugin for Stargazer
+ *
+ *  $Revision: 1.10 $
+ *  $Date: 2009/12/13 14:17:13 $
+ *
+ */
+
+#ifndef RADIUS_H
+#define RADIUS_H
+
+#include <string>
+#include <list>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "os_int.h"
+#include "base_auth.h"
+#include "notifer.h"
+#include "user_ips.h"
+#include "../../../user.h"
+#include "../../../users.h"
+#include "blowfish.h"
+#include "rad_packets.h"
+
+using namespace std;
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+#define RAD_DEBUG (1)
+
+class RADIUS;
+//-----------------------------------------------------------------------------
+class RAD_SETTINGS
+{
+public:
+    virtual         ~RAD_SETTINGS(){};
+    const string&   GetStrError() const { return errorStr; };
+    int             ParseSettings(const MODULE_SETTINGS & s);
+    uint16_t        GetPort() const;
+    uint32_t        GetServerIP() const;
+    int             GetPassword(string * password) const;
+    int             GetAuthServices(list<string> * svcs) const;
+    int             GetAcctServices(list<string> * svcs) const;
+
+private:
+    int             ParseIntInRange(const string & str, int min, int max, int * val);
+    int             ParseIP(const string & str, uint32_t * routerIP);
+    int             ParseServices(const vector<string> & str, list<string> * lst);
+
+    uint16_t            port;
+    string              errorStr;
+    string              password;
+    uint32_t            serverIP;
+    list<string>        authServices;
+    list<string>        acctServices;
+};
+//-----------------------------------------------------------------------------
+struct RAD_SESSION {
+    std::string userName;
+    std::string serviceType;
+};
+//-----------------------------------------------------------------------------
+class RADIUS :public BASE_AUTH
+{
+public:
+                        RADIUS();
+    virtual             ~RADIUS(){};
+
+    void                SetUsers(USERS * u);
+    void                SetTariffs(TARIFFS *){};
+    void                SetAdmins(ADMINS *){};
+    void                SetTraffcounter(TRAFFCOUNTER *){};
+    void                SetStore(BASE_STORE * );
+    void                SetStgSettings(const SETTINGS * s);
+    void                SetSettings(const MODULE_SETTINGS & s);
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload() { return 0; };
+    bool                IsRunning();
+
+    const string      & GetStrError() const { return errorStr; };
+    const string        GetVersion() const;
+    uint16_t            GetStartPosition() const;
+    uint16_t            GetStopPosition() const;
+
+    int SendMessage(const STG_MSG &, uint32_t) const { return 0; };
+
+private:
+    static void *       Run(void *);
+    int                 PrepareNet();
+    int                 FinalizeNet();
+
+    void                InitEncrypt(BLOWFISH_CTX * ctx, const string & password);
+    void                Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
+    void                Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
+
+    int                 Send(const RAD_PACKET & packet);
+    int                 RecvData(RAD_PACKET * packet);
+    int                 ProcessData(RAD_PACKET * packet);
+
+    int                 ProcessAutzPacket(RAD_PACKET * packet);
+    int                 ProcessAuthPacket(RAD_PACKET * packet);
+    int                 ProcessPostAuthPacket(RAD_PACKET * packet);
+    int                 ProcessAcctStartPacket(RAD_PACKET * packet);
+    int                 ProcessAcctStopPacket(RAD_PACKET * packet);
+    int                 ProcessAcctUpdatePacket(RAD_PACKET * packet);
+    int                 ProcessAcctOtherPacket(RAD_PACKET * packet);
+
+    bool                FindUser(user_iter * ui, const std::string & login) const;
+    bool                CanAuthService(const std::string & svc) const;
+    bool                CanAcctService(const std::string & svc) const;
+    bool                IsAllowedService(const std::string & svc) const;
+
+    void                SetUserNotifier(user_iter u);
+    void                UnSetUserNotifier(user_iter u);
+
+    bool                WaitPackets(int sd) const;
+
+    void                PrintServices(const std::list<std::string> & svcs);
+
+    struct Printer : public unary_function<std::string, void>
+    { 
+        void operator()(const std::string & line)
+        { 
+            printfd("radius.cpp", "'%s'\n", line.c_str()); 
+        }; 
+    };
+    struct SPrinter : public unary_function<std::pair<std::string, RAD_SESSION>, void>
+    { 
+        void operator()(const std::pair<std::string, RAD_SESSION> & it)
+        { 
+            printfd("radius.cpp", "%s - ('%s', '%s')\n", it.first.c_str(), it.second.userName.c_str(), it.second.serviceType.c_str()); 
+        }; 
+    };
+
+    BLOWFISH_CTX        ctx;
+
+    mutable string      errorStr;
+    RAD_SETTINGS        radSettings;
+    MODULE_SETTINGS     settings;
+    list<string>        authServices;
+    list<string>        acctServices;
+    map<string, RAD_SESSION> sessions;
+
+    bool                nonstop;
+
+    bool                isRunning;
+
+    USERS *             users;
+    const SETTINGS *    stgSettings;
+    const BASE_STORE *  store;
+
+    pthread_t           thread;
+    pthread_mutex_t     mutex;
+
+    int                 sock;
+    struct sockaddr_in  inAddr;
+    socklen_t           inAddrLen;
+    uint16_t            port;
+    uint32_t            serverIP;
+    struct sockaddr_in  outerAddr;
+    socklen_t           outerAddrLen;
+
+    RAD_PACKET          packet;
+
+};
+//-----------------------------------------------------------------------------
+
+#endif
+
diff --git a/projects/stargazer/plugins/other/rscript/Makefile b/projects/stargazer/plugins/other/rscript/Makefile
new file mode 100644 (file)
index 0000000..cad853c
--- /dev/null
@@ -0,0 +1,17 @@
+###############################################################################
+# $Id: Makefile,v 1.7 2010/02/16 11:41:00 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+LIBS += $(LIB_THREAD)
+
+PROG = mod_remote_script.so
+
+SRCS = ./rscript.cpp \
+       ./nrmap_parser.cpp
+
+STGLIBS = -lstg_common -lstg_crypto
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/other/rscript/nrmap_parser.cpp b/projects/stargazer/plugins/other/rscript/nrmap_parser.cpp
new file mode 100644 (file)
index 0000000..38caa1c
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.8 $
+ $Author: faust $
+ $Date: 2009/10/22 09:58:53 $
+ */
+
+#include <fstream>
+#include <cerrno>
+#include <cstring>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "common.h"
+
+#include "nrmap_parser.h"
+
+NRMapParser::NRMapParser()
+{
+}
+
+NRMapParser::~NRMapParser()
+{
+}
+
+bool NRMapParser::ReadFile(const std::string & fileName)
+{
+std::ifstream source(fileName.c_str());
+
+if (!source)
+    {
+    errorStr = "Error opening file ";
+    errorStr += fileName;
+    printfd(__FILE__, "NRMapParser::ReadFile(): %s\n", errorStr.c_str());
+    return true;
+    }
+
+int lineNumber = 0;
+std::string line;
+std::vector<NET_ROUTER> _nrmap;
+
+while (getline(source, line))
+    {
+    ++lineNumber;
+    NET_ROUTER nr;
+
+    if (Trim(line) == "")
+        {
+        continue;
+        }
+
+    if (ParseLine(line, nr))
+        {
+        printfd(__FILE__, "NRMapParser::ReadFile(): Error parsing line %d: '%s'\n", lineNumber, errorStr.c_str());
+        return true;
+        }
+
+    _nrmap.push_back(nr);
+    }
+
+nrmap = _nrmap;
+
+return false;
+}
+
+bool NRMapParser::ParseLine(const std::string & line, NET_ROUTER & nr) const
+{
+// xxx.xxx.xxx.xxx/yy zzz.zzz.zzz.zzz
+size_t pos = line.find_first_of(" \t");
+
+if (pos == std::string::npos)
+    {
+    errorStr = "No space between subnet and router";
+    return true;
+    }
+
+std::string subnet(line.substr(0, pos)); // xxx.xxx.xxx.xxx/yy
+
+uint32_t ip;
+uint32_t mask;
+
+if (ParseNet(subnet, ip, mask))
+    {
+    return true;
+    }
+
+nr.subnetIP = ip;
+nr.subnetMask = mask;
+
+pos = line.find_first_not_of(" \t", pos);
+
+if (pos == std::string::npos)
+    {
+    errorStr = "No router address found";
+    return true;
+    }
+
+size_t pos2 = line.find_first_of(" \t", pos);
+
+std::string router(line.substr(pos, pos2 == std::string::npos ? line.length() - pos2 - 1 : pos2 - pos)); //zzz.zzz.zzz.zzz
+
+uint32_t routerIP;
+
+if (ParseRouter(router, routerIP))
+    {
+    return true;
+    }
+
+std::vector<uint32_t>::iterator it;
+
+it = std::lower_bound(
+        nr.routers.begin(),
+        nr.routers.end(),
+        routerIP
+        );
+nr.routers.insert(it, routerIP);
+
+//nr.routers.push_back(routerIP);
+
+while (pos2 != std::string::npos)
+    {
+    pos = line.find_first_not_of(" \t", pos2);
+
+    if (pos == std::string::npos)
+        {
+        return false;
+        }
+
+    pos2 = line.find_first_of(" \t", pos);
+
+    if (ParseRouter(line.substr(
+                        pos,
+                        pos2 == std::string::npos ? line.length() - pos2 - 1 : pos2 - pos),
+                    routerIP))
+        {
+        return true;
+        }
+
+    it = std::lower_bound(
+            nr.routers.begin(),
+            nr.routers.end(),
+            routerIP
+            );
+    nr.routers.insert(it, routerIP);
+
+    //nr.routers.push_back(routerIP);
+
+    }
+
+return false;
+}
+
+bool NRMapParser::ParseNet(const std::string & line, uint32_t & ip, uint32_t & mask) const
+{
+// xxx.xxx.xxx.xxx/yy
+
+size_t pos = line.find_first_of('/');
+
+if (pos == std::string::npos)
+    {
+    errorStr = "Subnet is not in CIDR notation";
+    return true;
+    }
+
+int res = inet_pton(AF_INET, line.substr(0, pos).c_str(), &ip); //xxx.xxx.xxx.xxx
+
+if (res < 0)
+    {
+    errorStr = strerror(errno);
+    return true;
+    }
+else if (res == 0)
+    {
+    errorStr = "Invalid subnet address";
+    return true;
+    }
+
+if (str2x(line.substr(pos + 1, line.length() - pos - 1), mask)) //yy
+    {
+    errorStr = "Invalid subnet mask";
+    return true;
+    }
+if (mask > 32)
+    {
+    errorStr = "Subnet mask is out of range [0..32]";
+    return true;
+    }
+mask = htonl(0xffFFffFF << (32 - mask)); //bitmask
+
+return false;
+}
+
+bool NRMapParser::ParseRouter(const std::string & line, uint32_t & ip) const
+{
+int res = inet_pton(AF_INET, line.c_str(), &ip); //zzz.zzz.zzz.zzz
+
+if (res < 0)
+    {
+    errorStr = strerror(errno);
+    return true;
+    }
+else if (res == 0)
+    {
+    printfd(__FILE__, "NRMapParser::ParseRouter(): IP '%s' is invalid\n", line.c_str());
+    errorStr = "Invalid router address";
+    return true;
+    }
+return false;
+}
diff --git a/projects/stargazer/plugins/other/rscript/nrmap_parser.h b/projects/stargazer/plugins/other/rscript/nrmap_parser.h
new file mode 100644 (file)
index 0000000..d882c3a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.2 $
+ $Author: faust $
+ $Date: 2009/09/23 12:51:42 $
+ */
+
+#ifndef __NRMAP_PARSER_H__
+#define __NRMAP_PARSER_H__
+
+#include <string>
+#include <vector>
+#include "os_int.h"
+
+struct NET_ROUTER
+{
+uint32_t              subnetIP;
+uint32_t              subnetMask;
+std::vector<uint32_t> routers;
+};
+
+class NRMapParser {
+public:
+    NRMapParser();
+    ~NRMapParser();
+
+    bool ReadFile(const std::string & fileName);
+    const std::vector<NET_ROUTER> & GetMap() const { return nrmap; };
+    const std::string & GetErrorStr() const { return errorStr; };
+private:
+    std::vector<NET_ROUTER> nrmap;
+    mutable std::string errorStr;
+
+    bool ParseLine(const std::string & line, NET_ROUTER & nr) const;
+    bool ParseNet(const std::string & line, uint32_t & ip, uint32_t & mask) const;
+    bool ParseRouter(const std::string & line, uint32_t & ip) const;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/other/rscript/rscript.cpp b/projects/stargazer/plugins/other/rscript/rscript.cpp
new file mode 100644 (file)
index 0000000..3b00b3f
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.33 $
+ $Date: 2010/04/16 12:30:37 $
+ $Author: faust $
+*/
+
+#include <sys/time.h>
+
+#include <csignal>
+#include <cassert>
+#include <algorithm>
+
+#include "rscript.h"
+#include "common.h"
+#include "ur_functor.h"
+#include "send_functor.h"
+
+extern volatile const time_t stgTime;
+
+#define RS_MAX_ROUTERS  (100)
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+class RS_CREATOR
+{
+private:
+    REMOTE_SCRIPT * rs;
+
+public:
+    RS_CREATOR()
+        : rs(new REMOTE_SCRIPT())
+        {
+        };
+    ~RS_CREATOR()
+        {
+        delete rs;
+        };
+
+    REMOTE_SCRIPT * GetPlugin()
+        {
+        return rs;
+        };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+RS_CREATOR rsc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_PLUGIN * GetPlugin()
+{
+return rsc.GetPlugin();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+RS_USER::RS_USER()
+    : lastSentTime(0),
+      shortPacketsCount(0)
+{
+}
+//-----------------------------------------------------------------------------
+RS_USER::RS_USER(const std::vector<uint32_t> & r, user_iter it)
+    : lastSentTime(0),
+      user(it),
+      routers(r),
+      shortPacketsCount(0)
+{
+}
+//-----------------------------------------------------------------------------
+RS_SETTINGS::RS_SETTINGS()
+    : sendPeriod(0),
+      port(0)
+{
+}
+//-----------------------------------------------------------------------------
+int RS_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
+{
+if (str2x(str.c_str(), *val))
+    {
+    errorStr = "Incorrect value \'" + str + "\'.";
+    return -1;
+    }
+if (*val < min || *val > max)
+    {
+    errorStr = "Value \'" + str + "\' out of range.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RS_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+int p;
+PARAM_VALUE pv;
+vector<PARAM_VALUE>::const_iterator pvi;
+netRouters.clear();
+///////////////////////////
+pv.param = "Port";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Port\' not found.";
+    printfd(__FILE__, "Parameter 'Port' not found\n");
+    return -1;
+    }
+if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
+    {
+    errorStr = "Cannot parse parameter \'Port\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'Port'\n");
+    return -1;
+    }
+port = p;
+///////////////////////////
+pv.param = "SendPeriod";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'SendPeriod\' not found.";
+    printfd(__FILE__, "Parameter 'SendPeriod' not found\n");
+    return -1;
+    }
+
+if (ParseIntInRange(pvi->value[0], 5, 600, &sendPeriod))
+    {
+    errorStr = "Cannot parse parameter \'SendPeriod\': " + errorStr;
+    printfd(__FILE__, "Cannot parse parameter 'SendPeriod'\n");
+    return -1;
+    }
+///////////////////////////
+pv.param = "UserParams";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'UserParams\' not found.";
+    printfd(__FILE__, "Parameter 'UserParams' not found\n");
+    return -1;
+    }
+userParams = pvi->value;
+///////////////////////////
+pv.param = "Password";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'Password\' not found.";
+    printfd(__FILE__, "Parameter 'Password' not found\n");
+    return -1;
+    }
+password = pvi->value[0];
+///////////////////////////
+pv.param = "SubnetFile";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'SubnetFile\' not found.";
+    printfd(__FILE__, "Parameter 'SubnetFile' not found\n");
+    return -1;
+    }
+subnetFile = pvi->value[0];
+
+NRMapParser nrMapParser;
+
+if (nrMapParser.ReadFile(subnetFile))
+    {
+    errorStr = nrMapParser.GetErrorStr();
+    return -1;
+    }
+
+netRouters = nrMapParser.GetMap();
+
+if (netRouters.empty())
+    {
+    errorStr = "Parameter(s) \'Subnet*\' not found.";
+    printfd(__FILE__, "Parameter(s) 'Subnet*' not found\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+REMOTE_SCRIPT::REMOTE_SCRIPT()
+    : sendPeriod(15),
+      halfPeriod(8),
+      nonstop(false),
+      isRunning(false),
+      users(NULL),
+      sock(0)
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+REMOTE_SCRIPT::~REMOTE_SCRIPT()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+void * REMOTE_SCRIPT::Run(void * d)
+{
+REMOTE_SCRIPT * rs = static_cast<REMOTE_SCRIPT *>(d);
+
+rs->isRunning = true;
+
+while (rs->nonstop)
+    {
+    rs->PeriodicSend();
+    sleep(2);
+    }
+
+rs->isRunning = false;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::ParseSettings()
+{
+int ret = rsSettings.ParseSettings(settings);
+if (ret)
+    errorStr = rsSettings.GetStrError();
+
+sendPeriod = rsSettings.GetSendPeriod();
+halfPeriod = sendPeriod / 2;
+
+return ret;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::Start()
+{
+netRouters = rsSettings.GetSubnetsMap();
+
+InitEncrypt(&ctx, rsSettings.GetPassword());
+
+onAddUserNotifier.SetRemoteScript(this);
+onDelUserNotifier.SetRemoteScript(this);
+
+users->AddNotifierUserAdd(&onAddUserNotifier);
+users->AddNotifierUserDel(&onDelUserNotifier);
+
+nonstop = true;
+
+if (GetUsers())
+    {
+    return -1;
+    }
+
+if (PrepareNet())
+    {
+    return -1;
+    }
+
+if (!isRunning)
+    {
+    if (pthread_create(&thread, NULL, Run, this))
+        {
+        errorStr = "Cannot create thread.";
+        printfd(__FILE__, "Cannot create thread\n");
+        return -1;
+        }
+    }
+
+errorStr = "";
+return 0;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::Stop()
+{
+if (!IsRunning())
+    return 0;
+
+nonstop = false;
+
+std::for_each(
+        authorizedUsers.begin(),
+        authorizedUsers.end(),
+        DisconnectUser(*this)
+        );
+
+FinalizeNet();
+
+if (isRunning)
+    {
+    //5 seconds to thread stops itself
+    for (int i = 0; i < 25 && isRunning; i++)
+        {
+        usleep(200000);
+        }
+
+    //after 5 seconds waiting thread still running. now killing it
+    if (isRunning)
+        {
+        if (pthread_kill(thread, SIGINT))
+            {
+            errorStr = "Cannot kill thread.";
+            printfd(__FILE__, "Cannot kill thread\n");
+            return -1;
+            }
+        printfd(__FILE__, "REMOTE_SCRIPT killed Run\n");
+        }
+    }
+
+users->DelNotifierUserDel(&onDelUserNotifier);
+users->DelNotifierUserAdd(&onAddUserNotifier);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int REMOTE_SCRIPT::Reload()
+{
+NRMapParser nrMapParser;
+
+if (nrMapParser.ReadFile(rsSettings.GetMapFileName()))
+    {
+    errorStr = nrMapParser.GetErrorStr();
+    return -1;
+    }
+
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+    printfd(__FILE__, "REMOTE_SCRIPT::Reload()\n");
+
+    netRouters = nrMapParser.GetMap();
+    }
+
+std::for_each(authorizedUsers.begin(),
+              authorizedUsers.end(),
+              UpdateRouter(*this));
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::PrepareNet()
+{
+sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+if (sock < 0)
+    {
+    errorStr = "Cannot create socket.";
+    printfd(__FILE__, "Cannot create socket\n");
+    return true;
+    }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::FinalizeNet()
+{
+close(sock);
+return false;
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::PeriodicSend()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+map<uint32_t, RS_USER>::iterator it(authorizedUsers.begin());
+while (it != authorizedUsers.end())
+    {
+    if (difftime(stgTime, it->second.lastSentTime) - (rand() % halfPeriod) > sendPeriod)
+    //if (stgTime - it->second.lastSentTime > sendPeriod)
+        {
+        Send(it->first, it->second);
+        }
+    ++it;
+    }
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::PreparePacket(char * buf, size_t bufSize, uint32_t ip, RS_USER & rsu, bool forceDisconnect) const
+{
+RS_PACKET_HEADER packetHead;
+
+memset(packetHead.padding, 0, sizeof(packetHead.padding));
+strcpy((char*)packetHead.magic, RS_ID);
+packetHead.protoVer[0] = '0';
+packetHead.protoVer[1] = '2';
+if (forceDisconnect)
+    {
+    packetHead.packetType = RS_DISCONNECT_PACKET;
+    }
+else
+    {
+    if (rsu.shortPacketsCount % MAX_SHORT_PCKT == 0)
+        {
+        //SendLong
+        packetHead.packetType = rsu.user->IsInetable() ? RS_CONNECT_PACKET : RS_DISCONNECT_PACKET;
+        }
+    else
+        {
+        //SendShort
+        packetHead.packetType = rsu.user->IsInetable() ? RS_ALIVE_PACKET : RS_DISCONNECT_PACKET;
+        }
+    }
+rsu.shortPacketsCount++;
+rsu.lastSentTime = stgTime;
+
+packetHead.ip = htonl(ip);
+packetHead.id = htonl(rsu.user->GetID());
+strncpy((char*)packetHead.login, rsu.user->GetLogin().c_str(), RS_LOGIN_LEN);
+packetHead.login[RS_LOGIN_LEN - 1] = 0;
+
+memcpy(buf, &packetHead, sizeof(packetHead));
+
+if (packetHead.packetType == RS_ALIVE_PACKET)
+    {
+    return false;
+    }
+
+RS_PACKET_TAIL packetTail;
+
+memset(packetTail.padding, 0, sizeof(packetTail.padding));
+strcpy((char*)packetTail.magic, RS_ID);
+vector<string>::const_iterator it;
+std::string params;
+for(it = rsSettings.GetUserParams().begin();
+    it != rsSettings.GetUserParams().end();
+    ++it)
+    {
+    std::string parameter(GetUserParam(rsu.user, *it));
+    if (params.length() + parameter.length() > RS_PARAMS_LEN - 1)
+        break;
+    params += parameter + " ";
+    }
+strncpy((char *)packetTail.params, params.c_str(), RS_PARAMS_LEN);
+packetTail.params[RS_PARAMS_LEN - 1] = 0;
+
+assert(sizeof(packetHead) + sizeof(packetTail) <= bufSize && "Insufficient buffer space");
+
+Encrypt(&ctx, buf + sizeof(packetHead), (char *)&packetTail, sizeof(packetTail) / 8);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::Send(uint32_t ip, RS_USER & rsu, bool forceDisconnect) const
+{
+char buffer[RS_MAX_PACKET_LEN];
+
+memset(buffer, 0, sizeof(buffer));
+
+if (PreparePacket(buffer, sizeof(buffer), ip, rsu, forceDisconnect))
+    {
+    printfd(__FILE__, "REMOTE_SCRIPT::Send() - Invalid packet length!\n");
+    return true;
+    }
+
+std::for_each(
+        rsu.routers.begin(),
+        rsu.routers.end(),
+        PacketSender(sock, buffer, sizeof(buffer), htons(rsSettings.GetPort()))
+        );
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::SendDirect(uint32_t ip, RS_USER & rsu, uint32_t routerIP, bool forceDisconnect) const
+{
+char buffer[RS_MAX_PACKET_LEN];
+
+if (PreparePacket(buffer, sizeof(buffer), ip, rsu, forceDisconnect))
+    {
+    printfd(__FILE__, "REMOTE_SCRIPT::SendDirect() - Invalid packet length!\n");
+    return true;
+    }
+
+struct sockaddr_in sendAddr;
+
+sendAddr.sin_family = AF_INET;
+sendAddr.sin_port = htons(rsSettings.GetPort());
+sendAddr.sin_addr.s_addr = routerIP;
+
+int res = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&sendAddr, sizeof(sendAddr));
+
+return (res != sizeof(buffer));
+}
+//-----------------------------------------------------------------------------
+bool REMOTE_SCRIPT::GetUsers()
+{
+user_iter u;
+
+int h = users->OpenSearch();
+if (!h)
+    {
+    errorStr = "users->OpenSearch() error.";
+    printfd(__FILE__, "OpenSearch() error\n");
+    return true;
+    }
+
+while (!users->SearchNext(h, &u))
+    {
+    SetUserNotifier(u);
+    }
+
+users->CloseSearch(h);
+return false;
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::ChangedIP(user_iter u, uint32_t oldIP, uint32_t newIP)
+{
+/*
+ * When ip changes process looks like:
+ * old => 0, 0 => new
+ *
+ */
+if (newIP)
+    {
+    RS_USER rsu(IP2Routers(newIP), u);
+    Send(newIP, rsu);
+
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    authorizedUsers[newIP] = rsu;
+    }
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    const map<uint32_t, RS_USER>::iterator it(
+            authorizedUsers.find(oldIP)
+            );
+    if (it != authorizedUsers.end())
+        {
+        Send(oldIP, it->second, true);
+        authorizedUsers.erase(it);
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+std::vector<uint32_t> REMOTE_SCRIPT::IP2Routers(uint32_t ip)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+for (size_t i = 0; i < netRouters.size(); ++i)
+    {
+    if ((ip & netRouters[i].subnetMask) == (netRouters[i].subnetIP & netRouters[i].subnetMask))
+        {
+        return netRouters[i].routers;
+        }
+    }
+return std::vector<uint32_t>();
+}
+//-----------------------------------------------------------------------------
+string REMOTE_SCRIPT::GetUserParam(user_iter u, const string & paramName) const
+{
+string value = "";
+if (strcasecmp(paramName.c_str(), "cash") == 0)
+    strprintf(&value, "%f", u->property.cash.Get());
+else
+if (strcasecmp(paramName.c_str(), "freeMb") == 0)
+    strprintf(&value, "%f", u->property.freeMb.Get());
+else
+if (strcasecmp(paramName.c_str(), "passive") == 0)
+    strprintf(&value, "%d", u->property.passive.Get());
+else
+if (strcasecmp(paramName.c_str(), "disabled") == 0)
+    strprintf(&value, "%d", u->property.disabled.Get());
+else
+if (strcasecmp(paramName.c_str(), "alwaysOnline") == 0)
+    strprintf(&value, "%d", u->property.alwaysOnline.Get());
+else
+if (strcasecmp(paramName.c_str(), "tariffName") == 0 ||
+    strcasecmp(paramName.c_str(), "tariff") == 0)
+    value = "\"" + u->property.tariffName.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "nextTariff") == 0)
+    value = "\"" + u->property.nextTariff.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "address") == 0)
+    value = "\"" + u->property.address.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "note") == 0)
+    value = "\"" + u->property.note.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "group") == 0)
+    value = "\"" + u->property.group.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "email") == 0)
+    value = "\"" + u->property.email.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "realName") == 0)
+    value = "\"" + u->property.realName.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "credit") == 0)
+    strprintf(&value, "%f", u->property.credit.Get());
+else
+if (strcasecmp(paramName.c_str(), "userdata0") == 0)
+    value = "\"" + u->property.userdata0.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata1") == 0)
+    value = "\"" + u->property.userdata1.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata2") == 0)
+    value = "\"" + u->property.userdata2.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata3") == 0)
+    value = "\"" + u->property.userdata3.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata4") == 0)
+    value = "\"" + u->property.userdata4.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata5") == 0)
+    value = "\"" + u->property.userdata5.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata6") == 0)
+    value = "\"" + u->property.userdata6.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata7") == 0)
+    value = "\"" + u->property.userdata7.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata8") == 0)
+    value = "\"" + u->property.userdata8.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "userdata9") == 0)
+    value = "\"" + u->property.userdata9.Get() + "\"";
+else
+if (strcasecmp(paramName.c_str(), "enabledDirs") == 0)
+    value = u->GetEnabledDirs();
+else
+    printfd(__FILE__, "Unknown value name: %s\n", paramName.c_str());
+return value;
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::SetUserNotifier(user_iter u)
+{
+RS_CHG_AFTER_NOTIFIER<uint32_t>  AfterChgIPNotifier;
+
+AfterChgIPNotifier.SetRemoteScript(this);
+AfterChgIPNotifier.SetUser(u);
+AfterChgIPNotifierList.push_front(AfterChgIPNotifier);
+
+u->AddCurrIPAfterNotifier(&(*AfterChgIPNotifierList.begin()));
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::UnSetUserNotifier(user_iter u)
+{
+list<RS_CHG_AFTER_NOTIFIER<uint32_t> >::iterator  ipAIter;
+std::list<list<RS_CHG_AFTER_NOTIFIER<uint32_t> >::iterator> toErase;
+
+for (ipAIter = AfterChgIPNotifierList.begin(); ipAIter != AfterChgIPNotifierList.end(); ++ipAIter)
+    {
+    if (ipAIter->GetUser() == u)
+        {
+        u->DelCurrIPAfterNotifier(&(*ipAIter));
+        toErase.push_back(ipAIter);
+        }
+    }
+
+std::list<list<RS_CHG_AFTER_NOTIFIER<uint32_t> >::iterator>::iterator eIter;
+
+for (eIter = toErase.begin(); eIter != toErase.end(); ++eIter)
+    {
+    AfterChgIPNotifierList.erase(*eIter);
+    }
+}
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+void RS_CHG_AFTER_NOTIFIER<varParamType>::Notify(const varParamType & oldValue, const varParamType & newValue)
+{
+rs->ChangedIP(user, oldValue, newValue);
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::InitEncrypt(BLOWFISH_CTX * ctx, const string & password) const
+{
+unsigned char keyL[PASSWD_LEN];  // Пароль для шифровки
+memset(keyL, 0, PASSWD_LEN);
+strncpy((char *)keyL, password.c_str(), PASSWD_LEN);
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+}
+//-----------------------------------------------------------------------------
+void REMOTE_SCRIPT::Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, size_t len8) const
+{
+if (dst != src)
+    memcpy(dst, src, len8 * 8);
+for (size_t i = 0; i < len8; ++i)
+    Blowfish_Encrypt(ctx, (uint32_t *)(dst + i * 8), (uint32_t *)(dst + i * 8 + 4));
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/other/rscript/rscript.h b/projects/stargazer/plugins/other/rscript/rscript.h
new file mode 100644 (file)
index 0000000..ed08e2b
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.16 $
+ $Date: 2010/09/10 06:43:59 $
+ $Author: faust $
+*/
+
+#ifndef RSCRIPT_H
+#define RSCRIPT_H
+
+#include <pthread.h>
+
+#include <cstring>
+#include <string>
+#include <map>
+#include <functional>
+#include <utility>
+
+#include "base_store.h"
+#include "os_int.h"
+#include "notifer.h"
+#include "user_ips.h"
+#include "../../../user.h"
+#include "../../../users.h"
+#include "blowfish.h"
+#include "rs_packets.h"
+#include "nrmap_parser.h"
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+#define RS_DEBUG (1)
+
+#define MAX_SHORT_PCKT  (3)
+
+class REMOTE_SCRIPT;
+//-----------------------------------------------------------------------------
+class RS_ADD_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+{
+public:
+    RS_ADD_USER_NONIFIER() {};
+    virtual ~RS_ADD_USER_NONIFIER() {};
+
+    void SetRemoteScript(REMOTE_SCRIPT * a) { rs = a; }
+    void Notify(const user_iter & user);
+
+private:
+    REMOTE_SCRIPT * rs;
+};
+//-----------------------------------------------------------------------------
+class RS_DEL_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+{
+public:
+    RS_DEL_USER_NONIFIER() {};
+    virtual ~RS_DEL_USER_NONIFIER() {};
+
+    void SetRemoteScript(REMOTE_SCRIPT * a) { rs = a; }
+    void Notify(const user_iter & user);
+
+private:
+    REMOTE_SCRIPT * rs;
+};
+//-----------------------------------------------------------------------------
+template <typename varParamType>
+class RS_CHG_AFTER_NOTIFIER: public PROPERTY_NOTIFIER_BASE<varParamType>
+{
+public:
+    void        Notify(const varParamType & oldValue, const varParamType & newValue);
+    void        SetUser(user_iter u) { user = u; }
+    user_iter   GetUser() {return user; }
+    void        SetRemoteScript(REMOTE_SCRIPT * a) { rs = a; }
+
+private:
+    user_iter   user;
+    REMOTE_SCRIPT * rs;
+};
+//-----------------------------------------------------------------------------
+struct RS_USER
+{
+                      RS_USER();
+                      RS_USER(const std::vector<uint32_t> & r, user_iter it);
+time_t                lastSentTime;
+user_iter             user;
+std::vector<uint32_t> routers;
+int                   shortPacketsCount;
+};
+//-----------------------------------------------------------------------------
+class RS_SETTINGS
+{
+public:
+                        RS_SETTINGS();
+    virtual             ~RS_SETTINGS() {};
+    const std::string & GetStrError() const { return errorStr; };
+    int                 ParseSettings(const MODULE_SETTINGS & s);
+    int                 GetSendPeriod() const { return sendPeriod; };
+    int                 GetPort() const { return port; };
+    const std::vector<NET_ROUTER> & GetSubnetsMap() const { return netRouters; };
+    const std::vector<std::string> & GetUserParams() const { return userParams; };
+    const std::string & GetPassword() const { return password; };
+    const std::string & GetMapFileName() const { return subnetFile; };
+
+private:
+    int                 ParseIntInRange(const std::string & str, int min, int max, int * val);
+    int                 sendPeriod;
+    uint16_t            port;
+    string              errorStr;
+    std::vector<NET_ROUTER> netRouters;
+    std::vector<string>     userParams;
+    string              password;
+    string              subnetFile;
+};
+//-----------------------------------------------------------------------------
+class REMOTE_SCRIPT : public BASE_PLUGIN
+{
+public:
+                        REMOTE_SCRIPT();
+    virtual             ~REMOTE_SCRIPT();
+
+    void                SetUsers(USERS * u) { users = u; };
+    void                SetTariffs(TARIFFS *) {};
+    void                SetAdmins(ADMINS *) {};
+    void                SetTraffcounter(TRAFFCOUNTER *) {};
+    void                SetStore(BASE_STORE *) {};
+    void                SetStgSettings(const SETTINGS *) {};
+    void                SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int                 ParseSettings();
+
+    int                 Start();
+    int                 Stop();
+    int                 Reload();
+    bool                IsRunning() { return isRunning; };
+
+    const std::string & GetStrError() const { return errorStr; };
+    const std::string   GetVersion() const { return "Remote script v 0.3"; };
+    uint16_t            GetStartPosition() const { return 20; };
+    uint16_t            GetStopPosition() const { return 20; };
+
+    void                DelUser(user_iter u) { UnSetUserNotifier(u); };
+    void                AddUser(user_iter u) { SetUserNotifier(u); };
+
+    void                ChangedIP(user_iter u, uint32_t oldIP, uint32_t newIP);
+
+private:
+    static void *       Run(void *);
+    bool                PrepareNet();
+    bool                FinalizeNet();
+
+    bool                Send(uint32_t ip, RS_USER & rsu, bool forceDisconnect = false) const;
+    bool                SendDirect(uint32_t ip, RS_USER & rsu, uint32_t routerIP, bool forceDisconnect = false) const;
+    bool                PreparePacket(char * buf, size_t bufSize, uint32_t ip, RS_USER &rsu, bool forceDisconnect = false) const;
+    void                PeriodicSend();
+
+    std::vector<uint32_t> IP2Routers(uint32_t ip);
+    bool                GetUsers();
+    std::string         GetUserParam(user_iter u, const std::string & paramName) const;
+
+    void                SetUserNotifier(user_iter u);
+    void                UnSetUserNotifier(user_iter u);
+
+    void                InitEncrypt(BLOWFISH_CTX * ctx, const string & password) const;
+    void                Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, size_t len8) const;
+
+    mutable BLOWFISH_CTX ctx;
+
+    std::list<RS_CHG_AFTER_NOTIFIER<uint32_t> > AfterChgIPNotifierList;
+    std::map<uint32_t, RS_USER> authorizedUsers;
+
+    mutable std::string errorStr;
+    RS_SETTINGS         rsSettings;
+    MODULE_SETTINGS     settings;
+    int                 sendPeriod;
+    int                 halfPeriod;
+
+    bool                nonstop;
+    bool                isRunning;
+
+    USERS *             users;
+
+    std::vector<NET_ROUTER> netRouters;
+
+    pthread_t           thread;
+    pthread_mutex_t     mutex;
+
+    int                 sock;
+
+    RS_ADD_USER_NONIFIER onAddUserNotifier;
+    RS_DEL_USER_NONIFIER onDelUserNotifier;
+
+    friend class UpdateRouter;
+    friend class DisconnectUser;
+};
+//-----------------------------------------------------------------------------
+class DisconnectUser : public std::unary_function<std::pair<const uint32_t, RS_USER> &, void>
+{
+    public:
+        DisconnectUser(REMOTE_SCRIPT & rs) : rscript(rs) {};
+        void operator()(std::pair<const uint32_t, RS_USER> & p)
+        {
+            rscript.Send(p.first, p.second, true);
+        }
+    private:
+        REMOTE_SCRIPT & rscript;
+};
+//-----------------------------------------------------------------------------
+inline void RS_ADD_USER_NONIFIER::Notify(const user_iter & user)
+{
+printfd(__FILE__, "ADD_USER_NONIFIER\n");
+rs->AddUser(user);
+}
+//-----------------------------------------------------------------------------
+inline void RS_DEL_USER_NONIFIER::Notify(const user_iter & user)
+{
+printfd(__FILE__, "DEL_USER_NONIFIER\n");
+rs->DelUser(user);
+}
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/projects/stargazer/plugins/other/rscript/send_functor.h b/projects/stargazer/plugins/other/rscript/send_functor.h
new file mode 100644 (file)
index 0000000..479cdc3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2010/03/04 12:11:09 $
+ $Author: faust $
+*/
+
+#ifndef __SEND_FUNCTOR_H__
+#define __SEND_FUNCTOR_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <functional>
+
+#include "os_int.h"
+
+class PacketSender : public std::unary_function<uint32_t, void> {
+    public:
+        PacketSender(int s, char * b, int l, uint16_t p)
+            : sock(s),
+              buffer(b),
+              length(l),
+              port(p) {};
+        void operator() (uint32_t ip)
+        {
+        int res;
+        struct sockaddr_in sendAddr;
+
+        sendAddr.sin_family = AF_INET;
+        sendAddr.sin_port = port;
+        sendAddr.sin_addr.s_addr = ip;
+
+        res = sendto(sock, buffer, length, 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
+        }
+    private:
+        int sock;
+        char * buffer;
+        int length;
+        uint16_t port;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/other/rscript/ur_functor.h b/projects/stargazer/plugins/other/rscript/ur_functor.h
new file mode 100644 (file)
index 0000000..d9706a7
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.3 $
+ $Date: 2010/03/04 12:07:03 $
+ $Author: faust $
+*/
+
+#ifndef __UR_FUNCTOR_H__
+#define __UR_FUNCTOR_H__
+
+#include <functional>
+#include <algorithm>
+#include <utility>
+
+#include "rscript.h"
+#include "os_int.h"
+
+#include "common.h"
+
+class UpdateRouter : public std::unary_function<std::pair<const uint32_t, RS_USER>, void>
+{
+public:
+    UpdateRouter(REMOTE_SCRIPT & t)
+        : obj(t) {};
+
+    void operator() (std::pair<const uint32_t, RS_USER> & val)
+        {
+        std::vector<uint32_t> newRouters = obj.IP2Routers(val.first);
+        std::vector<uint32_t>::const_iterator oldIt(val.second.routers.begin());
+        std::vector<uint32_t>::const_iterator newIt(newRouters.begin());
+        val.second.shortPacketsCount = 0;
+        while (oldIt != val.second.routers.end() ||
+               newIt != newRouters.end())
+            {
+            if (oldIt == val.second.routers.end())
+                {
+                if (newIt != newRouters.end())
+                    {
+                    obj.SendDirect(val.first, val.second, *newIt); // Connect on new router
+                    ++newIt;
+                    }
+                }
+            else if (newIt == newRouters.end())
+                {
+                //if (oldIt != newRouters.end())
+                    //{ // Already checked it
+                    obj.SendDirect(val.first, val.second, *oldIt, true); // Disconnect on old router
+                    ++oldIt;
+                    //}
+                } 
+            else if (*oldIt < *newIt)
+                {
+                obj.SendDirect(val.first, val.second, *oldIt, true); // Disconnect on old router
+                ++oldIt;
+                }
+            else if (*oldIt > *newIt)
+                {
+                obj.SendDirect(val.first, val.second, *newIt); // Connect on new router
+                ++newIt;
+                }
+            else
+                {
+                if (oldIt != val.second.routers.end())
+                    ++oldIt;
+                if (newIt != newRouters.end())
+                    ++newIt;
+                }
+            }
+        val.second.routers = newRouters;
+        /*if (val.second.souters != newRouters)
+            {
+            obj.Send(val.first, val.second, true); // Disconnect on old router
+            val.second.routerIP = obj.IP2Router(val.first); // Change router
+            val.second.shortPacketsCount = 0; // Reset packets count (to prevent alive send)
+            obj.Send(val.first, val.second); // Connect on new router
+            }*/
+        }
+private:
+    REMOTE_SCRIPT & obj;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/other/userstat/Makefile b/projects/stargazer/plugins/other/userstat/Makefile
new file mode 100644 (file)
index 0000000..23470f8
--- /dev/null
@@ -0,0 +1,29 @@
+###############################################################################
+# $Id: Makefile,v 1.1 2008/07/05 12:35:53 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+LIBS += -lexpat
+
+ifeq ($(OS),linux)
+LIBS += -lpthread
+endif
+
+ifeq ($(OS),bsd)
+LIBS += -lc_r
+endif
+
+ifeq ($(OS),bsd5)
+LIBS += -lc_r
+endif
+
+PROG = mod_userstat.so
+
+SRCS = ./userstat.cpp
+
+LIBS += -lstg_common \
+       -lstg_crypto
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/other/userstat/datathread.cpp b/projects/stargazer/plugins/other/userstat/datathread.cpp
new file mode 100644 (file)
index 0000000..40d4430
--- /dev/null
@@ -0,0 +1,193 @@
+#include "datathread.h"
+
+bool DataThread::Init()
+{
+    parser = XML_ParserCreate(NULL);
+    if (!parser) {
+        printfd(__FILE__, "Error creating XML parser\n");
+    }
+    XML_SetStartElementHandler(parser, StartHandler);
+    XML_SetEndElementHandler(parser, EndHandler);
+    XML_SetCharacterDataHandler(parser, DataHandler);
+}
+
+DataThread::~DataThread()
+{
+    XML_ParserFree(parser);
+}
+
+void * DataThread::Run(void * val)
+{
+    DataThread * dt = reinterpret_cast<DataThread *>(val);
+
+    running = true;
+    stoppped = false;
+    while (running) {
+        if (sock >= 0) {
+            done = false;
+            dt->Handle();
+            done = true;
+            close(sock);
+            sock = -1;
+        } else {
+            usleep(1000);
+        }
+    }
+    stopped = true;
+    running = false;
+
+    return NULL;
+}
+
+void DataThread::Handle()
+{
+    int32_t size;
+    unsigned char * buf;
+
+    if (!PrepareContext())
+        return;
+
+    res = read(sock, &size, sizeof(size));
+    if (res != sizeof(size))
+    {
+        printfd(__FILE__, "Reading stream size failed! Wanted %d bytes, got %d bytes.\n", sizeof(size), res);
+        return;
+    }
+
+    printfd(__FILE__, "DataThread::Handle() size = %d\n", size);
+
+    if (size < 0) {
+        printfd(__FILE__, "DataThread::Handle() Invalid data size.\n");
+        return;
+    }
+
+    buf = new unsigned char[size];
+    res = read(sock, buf, size);
+    if (res != size)
+    {
+        printfd(__FILE__, "Reading stream failed! Wanted %d bytes, got %d bytes.\n", size, res);
+        return;
+    }
+
+    std::string data;
+    Decode(buf, data, size);
+
+    printfd(__FILE__, "Received XML: %s\n", data.c_str());
+
+    XML_ParserReset(parser, NULL);
+
+    if (XML_Parse(parser, data.c_str(), data.length(), true) == XML_STATUS_OK) {
+        SendReply();
+    } else {
+        SendError();
+    }
+
+    delete[] buf;
+
+    return;
+}
+
+bool DataThread::PrepareContext()
+{
+    int32_t size;
+    char * login;
+
+    int res = read(sock, &size, sizeof(size));
+    if (res != sizeof(size))
+    {
+        printfd(__FILE__, "Reading stream size failed! Wanted %d bytes, got %d bytes.\n", sizeof(size), res);
+        return;
+    }
+
+    printfd(__FILE__, "DataThread::Handle() size = %d\n", size);
+
+    if (size < 0) {
+        printfd(__FILE__, "DataThread::Handle() Invalid data size.\n");
+        return;
+    }
+
+    login = new char[size];
+
+    res = read(sock, login, size);
+    if (res != size)
+    {
+        printfd(__FILE__, "Reading login failed! Wanted %d bytes, got %d bytes.\n", 32, res);
+        return;
+    }
+
+    std::string l;
+    l.assign(login, size);
+    delete[] login;
+
+    user_iter it;
+    if (users->FindByName(l, &it))
+    {
+        printfd(__FILE__, "User '%s' not found.\n", login);
+        return;
+    }
+
+    password = it->property.password;
+    
+    printfd(__FILE__, "DataThread::Handle() Requested user: '%s'\n", login);
+    printfd(__FILE__, "DataThread::Handle() Encryption initiated using password: '%s'\n", password.c_str());
+
+    char * key = new char[password.length()];
+    strncpy(key, password.c_str(), password.length());
+
+    Blowfish_Init(&ctx,
+                  reinterpret_cast<unsigned char *>(key),
+                  password.length());
+    delete[] key;
+
+    return true;
+}
+
+void DataThread::Encode(const std::string & src, char * dst, int size)
+{
+    const char * ptr = src.c_str();
+    for (int i = 0; i < size / 8; ++i) {
+        uint32_t a;
+        uint32_t b;
+        a = n2l(ptr + i * 8);
+        b = n2l(ptr + i * 8 + 4);
+        Blowfish_Encrypt(&ctx,
+                         &a,
+                         &b);
+        l2n(a, dst + i * 8);
+        l2n(b, dst + i * 8 + 4);
+    }
+}
+
+void DataThread::Decode(char * src, std::string & dst, int size)
+{
+    char tmp[9];
+    tmp[8] = 0;
+    dst = "";
+
+    for (int i = 0; i < size / 8; ++i) {
+        uint32_t a;
+        uint32_t b;
+        a = n2l(src + i * 8);
+        b = n2l(src + i * 8 + 4);
+        Blowfish_Decrypt(&ctx,
+                         &a,
+                         &b);
+        l2n(a, tmp);
+        l2n(b, tmp + 4);
+
+        dst += tmp;
+    }
+}
+
+void StartHandler(void *data, const char *el, const char **attr)
+{
+    printfd(__FILE__, "Node: %s\n", el);
+}
+
+void EndHandler(void *data, const char *el)
+{
+}
+
+void DataHandler(void *data, const char *el)
+{
+}
diff --git a/projects/stargazer/plugins/other/userstat/datathread.h b/projects/stargazer/plugins/other/userstat/datathread.h
new file mode 100644 (file)
index 0000000..cd9a87b
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __DATATHREAD_H__
+#define __DATATHREAD_H__
+
+#include "../../../users.h"
+#include "base_store.h"
+#include <pthread.h>
+#include <expat.h>
+
+class DataThread {
+public:
+    DataThread() : done(false), sock(-1) { Init(); };
+    DataThread(USERS * u, BASE_STORE * s, int sd)
+        : users(u),
+          store(s),
+          sock(sd),
+          done(false)
+    {
+        Init();
+    };
+    ~DataThread();
+
+    void SetUsers(USERS * u) { users = u; };
+    void SetStore(BASE_STORE * s) { store = s; };
+    void SetSocket(int s) { sock = s; };
+
+    bool isDone() const { return done; };
+    bool Init();
+
+    bool Start();
+    bool Stop();
+
+    static void * Run(void *);
+
+
+private:
+    pthread_t thread;
+    USERS * users;
+    BASE_STORE * store;
+    XML_Parser parser;
+    int sock;
+    bool done;
+    bool running;
+    bool stopped;
+    BLOWFISH_CTX ctx;
+    std::string password;
+    std::string reply;
+
+    void Handle();
+    bool PrepareContect();
+    void Encode(const std::string &, char *);
+    void Decode(char *, const std::string &);
+
+    friend void StartHandler(void *data, const char *el, const char **attr);
+    friend void EndHandler(void *data, const char *el);
+    friend void DataHandler(void *data, const char *el);
+};
+
+#endif
diff --git a/projects/stargazer/plugins/other/userstat/userstat.cpp b/projects/stargazer/plugins/other/userstat/userstat.cpp
new file mode 100644 (file)
index 0000000..eca424e
--- /dev/null
@@ -0,0 +1,296 @@
+#include <algorithm>
+#include <cstring>
+#include <cerrno>
+#include <arpa/inet.h>
+#include <csignal>
+
+#include "common.h"
+#include "../../../users.h"
+
+#include "userstat.h"
+
+BASE_PLUGIN * GetPlugin()
+{
+return new USERSTAT();
+}
+
+USERSTAT::USERSTAT()
+    : maxThreads(16),
+      port(5555)
+{
+xmlParser = XML_ParserCreate(NULL);
+pthread_mutex_init(&mutex, NULL);
+}
+
+USERSTAT::~USERSTAT()
+{
+XML_ParserFree(xmlParser);
+}
+
+int USERSTAT::ParseSettings()
+{
+vector<PARAM_VALUE>::iterator i;
+string s;
+
+for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
+    {
+    s = i->param;
+    transform(s.begin(), s.end(), s.begin(), USERSTAT::ToLower());
+    if (s == "port")
+        {
+        if (str2x<uint16_t>(*(i->value.begin()), port)) 
+            {
+            errorStr = "'Port' parameter must be a numeric value";
+            return -1;
+            }
+        }
+    if (s == "maxthreads")
+        {
+        if (str2x<unsigned>(*(i->value.begin()), maxThreads)) 
+            {
+            errorStr = "'MaxThreads' parameter must be a numeric value";
+            return -1;
+            }
+        }
+    }
+
+return 0;
+}
+
+int USERSTAT::Prepare()
+{
+listenSocket = socket(PF_INET, SOCK_STREAM, 0);
+
+if (listenSocket < 0)
+    {
+    errorStr = "Create USERSTAT socket failed.";
+    return -1;
+    }
+
+printfd(__FILE__, "USERSTAT::Prepare() socket - ok\n");
+
+listenAddr.sin_family = PF_INET;
+listenAddr.sin_port = htons(port);
+listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+int lng = 1;
+
+if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
+    {
+    errorStr = "Setsockopt failed. " + string(strerror(errno));
+    return -1;
+    }
+
+printfd(__FILE__, "USERSTAT::Prepare() setsockopt - ok\n");
+
+int res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
+
+if (res == -1)
+    {
+    errorStr = "Bind USERSTAT socket failed";
+    return -1;
+    }
+
+printfd(__FILE__, "USERSTAT::Prepare() bind - ok port: %d\n", port);
+
+res = listen(listenSocket, 0);
+if (res == -1)
+    {
+    errorStr = "Listen USERSTAT socket failed";
+    return -1;
+    }
+printfd(__FILE__, "USERSTAT::Prepare() listen - ok\n");
+
+errorStr = "";
+return 0;
+}
+
+int USERSTAT::Finalize()
+{
+return close(listenSocket);
+}
+
+int USERSTAT::Start()
+{
+if (Prepare())
+    {
+    return -1;
+    }
+nonstop = true;
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    errorStr = "Cannot create thread";
+    return -1;
+    }
+
+return 0;
+}
+
+int USERSTAT::Stop()
+{
+nonstop = false;
+if (pthread_kill(thread, SIGTERM))
+    {
+    errorStr = "Cannot send signal to thread";
+    return -1;
+    }
+for (int i = 0; i < 25; i++)
+    {
+    if (!isRunning)
+        break;
+
+    usleep(200000);
+    }
+if (isRunning)
+    {
+    errorStr = "Cannot stop thread";
+    return -1;
+    }
+return 0;
+}
+
+void * USERSTAT::Run(void * t)
+{
+USERSTAT * us = reinterpret_cast<USERSTAT *>(t);
+pthread_t thread;
+int outerSocket;
+struct sockaddr_in outerAddr;
+socklen_t outerAddrLen;
+THREAD_INFO info;
+
+us->isRunning = true;
+while (us->nonstop)
+    {
+    outerSocket = accept(us->listenSocket, (struct sockaddr *)&outerAddr, &outerAddrLen); 
+    if (outerSocket > 0)
+        {
+        std::vector<THREAD_INFO>::iterator it;
+        us->pool.erase(remove_if(us->pool.begin(), us->pool.end(), USERSTAT::IsDone()), us->pool.end());
+
+        while (us->pool.size() >= us->maxThreads)
+            usleep(200000);
+        
+        info.users = us->users;
+        info.store = us->store;
+        info.outerSocket = outerSocket;
+        info.done = false;
+        us->pool.push_back(info);
+        it = us->pool.end();
+        --it;
+
+        if (pthread_create(&thread, NULL, Operate, &(*it)))
+            {
+            us->errorStr = "Cannot create thread";
+            printfd(__FILE__, "Cannot create thread\n");
+            }
+        it->thread = thread;
+        }
+    }
+us->isRunning = false;
+return NULL;
+}
+
+void * USERSTAT::Operate(void * i)
+{
+    THREAD_INFO * info = reinterpret_cast<THREAD_INFO *>(i);
+    unsigned char * buf;
+    int32_t size;
+    char * login;
+
+    int res = read(info->outerSocket, &size, sizeof(size));
+    if (res != sizeof(size))
+    {
+        printfd(__FILE__, "Reading stream size failed! Wanted %d bytes, got %d bytes.\n", sizeof(size), res);
+        info->done = true;
+        return NULL;
+    }
+
+    printfd(__FILE__, "USERSTAT::Operate() size = %d\n", size);
+
+    if (size < 0) {
+        printfd(__FILE__, "USERSTAT::Operate() Invalid data size.\n");
+        info->done = true;
+        return NULL;
+    }
+
+    login = new char[size];
+
+    res = read(info->outerSocket, login, size);
+    if (res != size)
+    {
+        printfd(__FILE__, "Reading login failed! Wanted %d bytes, got %d bytes.\n", 32, res);
+        info->done = true;
+        return NULL;
+    }
+
+    std::string l;
+    l.assign(login, size);
+
+    res = read(info->outerSocket, &size, sizeof(size));
+    if (res != sizeof(size))
+    {
+        printfd(__FILE__, "Reading stream size failed! Wanted %d bytes, got %d bytes.\n", sizeof(size), res);
+        info->done = true;
+        return NULL;
+    }
+
+    printfd(__FILE__, "USERSTAT::Operate() size = %d\n", size);
+
+    if (size < 0) {
+        printfd(__FILE__, "USERSTAT::Operate() Invalid data size.\n");
+        info->done = true;
+        return NULL;
+    }
+
+    buf = new unsigned char[size];
+    res = read(info->outerSocket, buf, size);
+    if (res != size)
+    {
+        printfd(__FILE__, "Reading stream failed! Wanted %d bytes, got %d bytes.\n", size, res);
+        info->done = true;
+        return NULL;
+    }
+
+    printfd(__FILE__, "Received data: %s\n", buf);
+
+    user_iter it;
+    if (info->users->FindByName(l, &it))
+    {
+        printfd(__FILE__, "User '%s' not found.\n", login);
+        info->done = true;
+        return NULL;
+    }
+
+    std::string password = it->property.password;
+    
+    printfd(__FILE__, "USERSTAT::Operate() Requested user: '%s'\n", login);
+    printfd(__FILE__, "USERSTAT::Operate() Encription init using password: '%s'\n", password.c_str());
+
+    BLOWFISH_CTX ctx;
+    char * key = new char[password.length()];
+    strncpy(key, password.c_str(), password.length());
+
+    Blowfish_Init(&ctx,
+                  reinterpret_cast<unsigned char *>(key),
+                  password.length());
+
+    for (int i = 0; i < size / 8; ++i) {
+        uint32_t a;
+        uint32_t b;
+        a = n2l(buf + i * 8);
+        b = n2l(buf + i * 8 + 4);
+        Blowfish_Decrypt(&ctx,
+                         &a,
+                         &b);
+        l2n(a, buf + i * 8);
+        l2n(b, buf + i * 8 + 4);
+    }
+
+    delete[] key;
+
+    printfd(__FILE__, "Received XML: %s\n", buf);
+
+    info->done = true;
+    delete[] buf;
+    return NULL;
+}
diff --git a/projects/stargazer/plugins/other/userstat/userstat.h b/projects/stargazer/plugins/other/userstat/userstat.h
new file mode 100644 (file)
index 0000000..83f6620
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.1 $
+ $Date: 2008/07/05 12:35:53 $
+ $Author: faust $
+*/
+
+#ifndef __USERSTAT_H__
+#define __USERSTAT_H__
+
+#include <expat.h>
+#include <pthread.h>
+#include <netinet/in.h>
+
+#include "base_plugin.h"
+
+extern "C" BASE_PLUGIN * GetPlugin();
+
+struct THREAD_INFO
+{
+    pthread_t thread;
+    USERS * users;
+    BASE_STORE * store;
+    int outerSocket;
+    bool done;
+};
+
+uint32_t n2l(unsigned char * c)
+{
+    uint32_t t = *c++ << 24;
+    t += *c++ << 16;
+    t += *c++ << 8;
+    t += *c;
+    return t;
+}
+
+void l2n(uint32_t t, unsigned char * c)
+{
+    *c++ = t >> 24 & 0x000000FF;
+    *c++ = t >> 16 & 0x000000FF;
+    *c++ = t >> 8 & 0x000000FF;
+    *c++ = t & 0x000000FF;
+}
+
+class USERSTAT : public BASE_PLUGIN
+{
+public:
+    USERSTAT();
+    ~USERSTAT();
+
+    virtual void SetUsers(USERS * u) { users = u; };
+    virtual void SetTariffs(TARIFFS * t) {};
+    virtual void SetAdmins(ADMINS * a) {};
+    virtual void SetTraffcounter(TRAFFCOUNTER * tc) {};
+    virtual void SetStore(BASE_STORE * st) { store = st; };
+    virtual void SetStgSettings(const SETTINGS * s) {};
+    virtual void SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    virtual int  ParseSettings();
+
+    virtual int  Start();
+    virtual int  Stop();
+    virtual bool IsRunning() { return isRunning; };
+    virtual const string  & GetStrError() const { return errorStr; };
+    virtual const string    GetVersion() const { return version; };
+    virtual uint16_t        GetStartPosition() const { return 0; };
+    virtual uint16_t        GetStopPosition() const { return 0; };
+
+private:
+    struct IsDone : public unary_function<THREAD_INFO, bool>
+    {
+        bool operator()(const THREAD_INFO & info) { return info.done; };
+    };
+    struct ToLower : public unary_function<char, char>
+    {
+        char operator() (char c) const  { return std::tolower(c); }
+    };
+    bool isRunning;
+    bool nonstop;
+    std::string errorStr;
+    std::string version;
+    std::vector<THREAD_INFO> pool;
+    int listenSocket;
+    int threads;
+    unsigned maxThreads;
+    uint16_t port;
+    struct sockaddr_in listenAddr;
+    pthread_t thread;
+    pthread_mutex_t mutex;
+    USERS * users;
+    BASE_STORE * store;
+
+    MODULE_SETTINGS settings;
+
+    XML_Parser xmlParser;
+
+    int Prepare();
+    int Finalize();
+    static void * Run(void *);
+    static void * Operate(void *);
+
+    friend void ParseXMLStart(void * data, char * name, char ** attr);
+    friend void ParseXMLEnd(void * data, char * name);
+};
+
+#endif
diff --git a/projects/stargazer/plugins/store/db/.libs/pg_driver.la b/projects/stargazer/plugins/store/db/.libs/pg_driver.la
new file mode 120000 (symlink)
index 0000000..13e4dfc
--- /dev/null
@@ -0,0 +1 @@
+../pg_driver.la
\ No newline at end of file
diff --git a/projects/stargazer/plugins/store/db/Makefile b/projects/stargazer/plugins/store/db/Makefile
new file mode 100644 (file)
index 0000000..586dfe2
--- /dev/null
@@ -0,0 +1,20 @@
+SOURCES=$(wildcard *.cpp)
+
+all: test_pg_driver pg_driver.so
+
+test_pg_driver: test_pg_driver.o
+       $(CXX) $^ -ldl -o $@
+
+pg_driver.so: pg_driver.o
+       $(CXX) $^ -shared -lpq -o $@
+
+clean:
+       rm -f *.d *.o *.so test_pg_driver
+
+
+-include $(subst .cpp,.d,$(SOURCES))
+
+%.d: %.cpp
+       @$(CC) -MM $(CXXFLAGS) $< > $@.$$$$; \
+           sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+           rm -f $@.$$$$
diff --git a/projects/stargazer/plugins/store/db/pg_driver.cpp b/projects/stargazer/plugins/store/db/pg_driver.cpp
new file mode 100644 (file)
index 0000000..4dda25d
--- /dev/null
@@ -0,0 +1,107 @@
+#include <sstream>
+
+#include "pg_driver.h"
+
+BASE_DB * CreateDriver()
+{
+    return new PG_DRIVER();
+}
+
+void DestroyDriver(BASE_DB * drv)
+{
+    delete drv;
+}
+
+PG_DRIVER::~PG_DRIVER()
+{
+    if (conn != NULL)
+       PQfinish(conn);
+}
+
+bool PG_DRIVER::Connect()
+{
+    std::stringstream params;
+    params << "host=" << host << " "
+          << "dbname=" << database << " "
+          << "user=" << user << " "
+          << "password=" << password;
+    std::string str = params.str();
+    conn = PQconnectdb(str.c_str());
+    errorMsg = PQerrorMessage(conn);
+    return PQstatus(conn) != CONNECTION_OK;
+}
+
+bool PG_DRIVER::Disconnect()
+{
+    if (PQstatus(conn) == CONNECTION_OK) {
+       PQfinish(conn);
+       conn = NULL;
+    }
+
+    return false;
+}
+
+bool PG_DRIVER::Query(const std::string & query)
+{
+    PQclear(result);
+    result = PQexec(conn, query.c_str());
+    errorMsg = PQerrorMessage(conn);
+    tuples = PQntuples(result);
+    columns = PQnfields(result);
+    affected = atoi(PQcmdTuples(result));
+
+    cols.erase(cols.begin(), cols.end());
+    cols.reserve(columns);
+
+    if (tuples) {
+       for (int i = 0; i < columns; ++i) {
+           cols.push_back(PQfname(result, i));
+       }
+    }
+
+    if (!result)
+       return true;
+
+    if (PQresultStatus(result) == PGRES_COMMAND_OK)
+       return false;
+
+    if (PQresultStatus(result) == PGRES_TUPLES_OK)
+       return false;
+
+    return true;
+}
+
+bool PG_DRIVER::Start()
+{
+    return Query("BEGIN");
+}
+
+bool PG_DRIVER::Commit()
+{
+    return Query("COMMIT");
+}
+
+bool PG_DRIVER::Rollback()
+{
+    return Query("ROLLBACK");
+}
+
+BASE_DB::TUPLE PG_DRIVER::GetTuple(int n) const
+{
+    BASE_DB::TUPLE tuple;
+
+    for (int i = 0; i < columns; ++i)
+       tuple[cols[i]] = PQgetvalue(result, n, i);
+
+    return tuple;
+}
+
+BASE_DB::TUPLES PG_DRIVER::GetResult() const
+{
+    BASE_DB::TUPLES tpls;
+
+    for (int i = 0; i < tuples; ++i)
+       tpls.push_back(GetTuple(i));
+
+    return tpls;
+}
diff --git a/projects/stargazer/plugins/store/db/pg_driver.h b/projects/stargazer/plugins/store/db/pg_driver.h
new file mode 100644 (file)
index 0000000..a6cee6e
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __PG_DRIVER_H__
+#define __PG_DRIVER_H__
+
+#include <libpq-fe.h>
+
+#include "base_db.h"
+
+class PG_DRIVER : public BASE_DB {
+public:
+    virtual ~PG_DRIVER();
+
+    virtual bool Connect();
+    virtual bool Disconnect();
+    virtual bool Query(const std::string &);
+    virtual bool Start();
+    virtual bool Commit();
+    virtual bool Rollback();
+
+    virtual BASE_DB::TUPLES GetResult() const;
+    virtual BASE_DB::TUPLE GetTuple(int n = 0) const;
+
+private:
+    PGconn * conn;
+    PGresult * result;
+};
+
+#endif
diff --git a/projects/stargazer/plugins/store/db/pg_driver.la b/projects/stargazer/plugins/store/db/pg_driver.la
new file mode 100644 (file)
index 0000000..f090c51
--- /dev/null
@@ -0,0 +1,35 @@
+# pg_driver.la - a libtool library file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='pg_driver.a'
+
+# Libraries that this one depends upon.
+dependency_libs=' -lpq'
+
+# Version information for pg_driver.
+current=
+age=
+revision=
+
+# Is this an already installed library?
+installed=no
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=yes
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir=''
diff --git a/projects/stargazer/plugins/store/db/pg_driver.lo b/projects/stargazer/plugins/store/db/pg_driver.lo
new file mode 100644 (file)
index 0000000..107fa03
--- /dev/null
@@ -0,0 +1,12 @@
+# pg_driver.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.493 2008/02/01 16:58:18)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/pg_driver.o'
+
+# Name of the non-PIC object.
+non_pic_object='pg_driver.o'
+
diff --git a/projects/stargazer/plugins/store/db/test_pg_driver.cpp b/projects/stargazer/plugins/store/db/test_pg_driver.cpp
new file mode 100644 (file)
index 0000000..57b94f3
--- /dev/null
@@ -0,0 +1,147 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#include <dlfcn.h>
+
+#include "base_db.h"
+
+int main(int argc, char ** argv)
+{
+    BASE_DB * db;
+
+    void * lh = dlopen("./pg_driver.so", RTLD_NOW | RTLD_GLOBAL);
+
+    if (lh == NULL) {
+       std::cout << "Error loading shared object file pg_driver.so. Reason: '" << dlerror() << "'" << std::endl;
+       return EXIT_FAILURE;
+    }
+
+    CreateDriverFn CreateDriver = reinterpret_cast<CreateDriverFn>(dlsym(lh, "CreateDriver"));
+    if (CreateDriver == NULL) {
+       std::cout << "Error getting symbol 'CreateDriver' address. Reason: '" << dlerror() << "'" << std::endl;
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+    DestroyDriverFn DestroyDriver = reinterpret_cast<DestroyDriverFn>(dlsym(lh, "DestroyDriver"));
+    if (DestroyDriver == NULL) {
+       std::cout << "Error getting symbol 'DestroyDriver' address. Reason: '" << dlerror() << "'" << std::endl;
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    db = CreateDriver();
+
+    db->SetHost("localhost");
+    db->SetDatabase("stargazer");
+    db->SetUser("stg");
+    db->SetPassword("123456");
+
+    if (db->Connect()) {
+       std::cout << "Error connecting db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    std::stringstream query;
+    query << "SELECT * FROM information_schema.tables";
+
+    if (db->Query(query.str())) {
+       std::cout << "Error querying db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       db->Disconnect();
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    std::cout << "Tuples: " << db->GetTuples() << std::endl;
+    std::cout << "Columns: " << db->GetColumns() << std::endl;
+    BASE_DB::COLUMNS cols;
+    BASE_DB::COLUMNS::iterator it;
+    cols = db->GetColumnsNames();
+    std::cout << "Cols count: " << cols.size() << std::endl;
+    std::cout << "Columns names:" << std::endl;
+    for (it = cols.begin(); it != cols.end(); ++it)
+       std::cout << *it << " ";
+    std::cout << std::endl;
+
+    for (int i = 0; i < db->GetTuples(); ++i) {
+       BASE_DB::TUPLE tuple(db->GetTuple(i));
+       BASE_DB::TUPLE::iterator it;
+       for (it = tuple.begin(); it != tuple.end(); ++it)
+           std::cout << it->second << " ";
+       std::cout << std::endl;
+    }
+
+    query.str("");
+    query << "create table test ( id bigserial, message text )";
+    if (db->Query(query.str())) {
+       std::cout << "Error querying db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       db->Disconnect();
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    query.str("");
+    query << "insert into test (message) values ('abc');";
+    query << "insert into test (message) values ('def');";
+    query << "insert into test (message) values ('zxc');";
+    if (db->Query(query.str())) {
+       std::cout << "Error querying db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       db->Disconnect();
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    query.str("");
+    query << "SELECT * FROM test";
+    if (db->Query(query.str())) {
+       std::cout << "Error querying db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       db->Disconnect();
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+    std::cout << "Tuples: " << db->GetTuples() << std::endl;
+    std::cout << "Columns: " << db->GetColumns() << std::endl;
+    cols = db->GetColumnsNames();
+    std::cout << "Cols count: " << cols.size() << std::endl;
+    std::cout << "Columns names:" << std::endl;
+    for (it = cols.begin(); it != cols.end(); ++it)
+       std::cout << *it << " ";
+    std::cout << std::endl;
+
+    for (int i = 0; i < db->GetTuples(); ++i) {
+       BASE_DB::TUPLE tuple(db->GetTuple(i));
+       BASE_DB::TUPLE::iterator it;
+       for (it = tuple.begin(); it != tuple.end(); ++it)
+           std::cout << it->second << " ";
+       std::cout << std::endl;
+    }
+
+    query.str("");
+    query << "drop table test";
+    if (db->Query(query.str())) {
+       std::cout << "Error querying db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       db->Disconnect();
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    if (db->Disconnect()) {
+       std::cout << "Error connecting db. Reason: '" << db->GetErrorMsg() << "'" << std::endl;
+       DestroyDriver(db);
+       dlclose(lh);
+       return EXIT_FAILURE;
+    }
+
+    DestroyDriver(db);
+
+    dlclose(lh);
+
+    return EXIT_SUCCESS;
+}
diff --git a/projects/stargazer/plugins/store/files/Makefile b/projects/stargazer/plugins/store/files/Makefile
new file mode 100644 (file)
index 0000000..3357a50
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.16 2010/03/04 10:47:45 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_store_files.so
+
+SRCS = ./file_store.cpp
+
+STGLIBS = -lconffiles -lstg_common -lstg_locker -lstg_crypto
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/store/files/file_store.cpp b/projects/stargazer/plugins/store/files/file_store.cpp
new file mode 100644 (file)
index 0000000..0763840
--- /dev/null
@@ -0,0 +1,2217 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.67 $
+ $Date: 2010/10/07 19:53:11 $
+ $Author: faust $
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <cstdio>
+#include <ctime>
+#include <cerrno>
+#include <cstring>
+#include <sstream>
+#include <algorithm>
+
+#include "common.h"
+#include "user_ips.h"
+#include "user_conf.h"
+#include "user_stat.h"
+#include "stg_const.h"
+#include "file_store.h"
+#include "blowfish.h"
+#include "stg_logger.h"
+#include "stg_locker.h"
+
+#define DELETED_USERS_DIR   "deleted_users"
+
+#define adm_enc_passwd "cjeifY8m3"
+
+using namespace std;
+
+const int pt_mega = 1024 * 1024;
+//-----------------------------------------------------------------------------
+class BAK_FILE
+{
+public:
+
+    //-------------------------------------------------------------------------
+    BAK_FILE(const string & fileName, bool removeBak)
+            : f(NULL),
+              removeBak(false)
+        {
+        bakSuccessed = false;
+        BAK_FILE::removeBak = removeBak;
+        fileNameBak = fileName + ".bak";
+        /*struct stat fileStat;
+        if (stat(fileName.c_str(), &fileStat) == 0)
+            {
+            char * buff = new char[fileStat.st_size];
+            f = fopen(fileName.c_str(), "rb");
+            if(f)
+                {
+                fread(buff, 1, fileStat.st_size, f);
+                fclose(f);
+
+                fileNameBak = fileName + ".bak";
+                f = fopen(fileNameBak.c_str(), "wb");
+                if(f)
+                    {
+                    fwrite(buff, 1, fileStat.st_size, f);
+                    fclose(f);
+                    }
+                }
+
+            delete[] buff;
+
+            bakSuccessed = true;
+            }*/
+        if (rename(fileName.c_str(), fileNameBak.c_str()))
+            {
+            printfd(__FILE__, "BAK_FILE::BAK_FILE - rename failed. Message: '%s'\n", strerror(errno));
+            }
+        else
+            {
+            bakSuccessed = true;
+            }
+
+        }
+    //-------------------------------------------------------------------------
+    ~BAK_FILE()
+        {
+        if(bakSuccessed && removeBak)
+            {
+            if (unlink(fileNameBak.c_str()))
+                {
+                printfd(__FILE__, "BAK_FILE::~BAK_FILE - unlink failed. Message: '%s'\n", strerror(errno));
+                }
+            }
+        }
+    //-------------------------------------------------------------------------
+
+private:
+    FILE * f;
+    bool bakSuccessed;
+    string fileNameBak;
+    bool removeBak;
+};
+//-----------------------------------------------------------------------------
+class FILES_STORE_CREATOR
+{
+private:
+    FILES_STORE * fs;
+
+public:
+    FILES_STORE_CREATOR()
+        : fs(new FILES_STORE())
+        {
+        };
+    ~FILES_STORE_CREATOR()
+        {
+        delete fs;
+        };
+
+    FILES_STORE * GetStore()
+    {
+        return fs;
+    };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+FILES_STORE_CREATOR fsc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_STORE * GetStore()
+{
+return fsc.GetStore();
+}
+//-----------------------------------------------------------------------------
+FILES_STORE_SETTINGS::FILES_STORE_SETTINGS()
+    : settings(NULL),
+      removeBak(true),
+      readBak(true)
+{
+}
+//-----------------------------------------------------------------------------
+FILES_STORE_SETTINGS::~FILES_STORE_SETTINGS()
+{
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseOwner(const vector<PARAM_VALUE> & moduleParams, const string & owner, uid_t * uid)
+{
+PARAM_VALUE pv;
+pv.param = owner;
+vector<PARAM_VALUE>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end())
+    {
+    errorStr = "Parameter \'" + owner + "\' not found.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+if (User2UID(pvi->value[0].c_str(), uid) < 0)
+    {
+    errorStr = "Parameter \'" + owner + "\': Unknown user \'" + pvi->value[0] + "\'";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseGroup(const vector<PARAM_VALUE> & moduleParams, const string & group, gid_t * gid)
+{
+PARAM_VALUE pv;
+pv.param = group;
+vector<PARAM_VALUE>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end())
+    {
+    errorStr = "Parameter \'" + group + "\' not found.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+if (Group2GID(pvi->value[0].c_str(), gid) < 0)
+    {
+    errorStr = "Parameter \'" + group + "\': Unknown group \'" + pvi->value[0] + "\'";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseYesNo(const string & value, bool * val)
+{
+if (0 == strcasecmp(value.c_str(), "yes"))
+    {
+    *val = true;
+    return 0;
+    }
+if (0 == strcasecmp(value.c_str(), "no"))
+    {
+    *val = false;
+    return 0;
+    }
+
+errorStr = "Incorrect value \'" + value + "\'.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseMode(const vector<PARAM_VALUE> & moduleParams, const string & modeStr, mode_t * mode)
+{
+PARAM_VALUE pv;
+pv.param = modeStr;
+vector<PARAM_VALUE>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end())
+    {
+    errorStr = "Parameter \'" + modeStr + "\' not found.";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+if (Str2Mode(pvi->value[0].c_str(), mode) < 0)
+    {
+    errorStr = "Parameter \'" + modeStr + "\': Incorrect mode \'" + pvi->value[0] + "\'";
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+if (ParseOwner(s.moduleParams, "StatOwner", &statUID) < 0)
+    return -1;
+if (ParseGroup(s.moduleParams, "StatGroup", &statGID) < 0)
+    return -1;
+if (ParseMode(s.moduleParams, "StatMode", &statMode) < 0)
+    return -1;
+
+if (ParseOwner(s.moduleParams, "ConfOwner", &confUID) < 0)
+    return -1;
+if (ParseGroup(s.moduleParams, "ConfGroup", &confGID) < 0)
+    return -1;
+if (ParseMode(s.moduleParams, "ConfMode", &confMode) < 0)
+    return -1;
+
+if (ParseOwner(s.moduleParams, "UserLogOwner", &userLogUID) < 0)
+    return -1;
+if (ParseGroup(s.moduleParams, "UserLogGroup", &userLogGID) < 0)
+    return -1;
+if (ParseMode(s.moduleParams, "UserLogMode", &userLogMode) < 0)
+    return -1;
+
+vector<PARAM_VALUE>::const_iterator pvi;
+PARAM_VALUE pv;
+pv.param = "RemoveBak";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    removeBak = true;
+    }
+else
+    {
+    if (ParseYesNo(pvi->value[0], &removeBak))
+        {
+        printfd(__FILE__, "Cannot parse parameter 'RemoveBak'\n");
+        return -1;
+        }
+    }
+
+pv.param = "ReadBak";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    readBak = false;
+    }
+else
+    {
+    if (ParseYesNo(pvi->value[0], &readBak))
+        {
+        printfd(__FILE__, "Cannot parse parameter 'ReadBak'\n");
+        return -1;
+        }
+    }
+
+pv.param = "WorkDir";
+pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
+if (pvi == s.moduleParams.end())
+    {
+    errorStr = "Parameter \'WorkDir\' not found.";
+    printfd(__FILE__, "Parameter 'WorkDir' not found\n");
+    return -1;
+    }
+
+workDir = pvi->value[0];
+if (workDir.size() && workDir[workDir.size() - 1] == '/')
+    {
+    workDir.resize(workDir.size() - 1);
+    }
+usersDir = workDir + "/users/";
+tariffsDir = workDir + "/tariffs/";
+adminsDir = workDir + "/admins/";
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & FILES_STORE_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::User2UID(const char * user, uid_t * uid)
+{
+struct passwd * pw;
+pw = getpwnam(user);
+if (!pw)
+    {
+    errorStr = string("User \'") + string(user) + string("\' not found in system.");
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+*uid = pw->pw_uid;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::Group2GID(const char * gr, gid_t * gid)
+{
+struct group * grp;
+grp = getgrnam(gr);
+if (!grp)
+    {
+    errorStr = string("Group \'") + string(gr) + string("\' not found in system.");
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+*gid = grp->gr_gid;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE_SETTINGS::Str2Mode(const char * str, mode_t * mode)
+{
+char a;
+char b;
+char c;
+if (strlen(str) > 3)
+    {
+    errorStr = string("Error parsing mode \'") + str + string("\'");
+    printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+for (int i = 0; i < 3; i++)
+    if (str[i] > '7' || str[i] < '0')
+        {
+        errorStr = string("Error parsing mode \'") + str + string("\'");
+        printfd(__FILE__, "%s\n", errorStr.c_str());
+        return -1;
+        }
+
+a = str[0] - '0';
+b = str[1] - '0';
+c = str[2] - '0';
+
+*mode = ((mode_t)c) + ((mode_t)b << 3) + ((mode_t)a << 6);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+string FILES_STORE_SETTINGS::GetWorkDir() const
+{
+return workDir;
+}
+//-----------------------------------------------------------------------------
+string FILES_STORE_SETTINGS::GetUsersDir() const
+{
+return usersDir;
+}
+//-----------------------------------------------------------------------------
+string FILES_STORE_SETTINGS::GetAdminsDir() const
+{
+return adminsDir;
+}
+//-----------------------------------------------------------------------------
+string FILES_STORE_SETTINGS::GetTariffsDir() const
+{
+return tariffsDir;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetStatMode() const
+{
+return statMode;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetStatModeDir() const
+{
+mode_t mode = statMode;
+if (statMode & S_IRUSR) mode |= S_IXUSR;
+if (statMode & S_IRGRP) mode |= S_IXGRP;
+if (statMode & S_IROTH) mode |= S_IXOTH;
+return mode;
+}
+//-----------------------------------------------------------------------------
+uid_t  FILES_STORE_SETTINGS::GetStatUID() const
+{
+return statUID;
+}
+//-----------------------------------------------------------------------------
+gid_t  FILES_STORE_SETTINGS::GetStatGID() const
+{
+return statGID;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetConfMode() const
+{
+return confMode;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetConfModeDir() const
+{
+mode_t mode = confMode;
+if (statMode & S_IRUSR) mode |= S_IXUSR;
+if (statMode & S_IRGRP) mode |= S_IXGRP;
+if (statMode & S_IROTH) mode |= S_IXOTH;
+return mode;
+}
+//-----------------------------------------------------------------------------
+uid_t  FILES_STORE_SETTINGS::GetConfUID() const
+{
+return confUID;
+}
+//-----------------------------------------------------------------------------
+gid_t  FILES_STORE_SETTINGS::GetConfGID() const
+{
+return confGID;
+}
+//-----------------------------------------------------------------------------
+mode_t FILES_STORE_SETTINGS::GetLogMode() const
+{
+return userLogMode;
+}
+//-----------------------------------------------------------------------------
+uid_t  FILES_STORE_SETTINGS::GetLogUID() const
+{
+return userLogUID;
+}
+//-----------------------------------------------------------------------------
+gid_t FILES_STORE_SETTINGS::GetLogGID() const
+{
+return userLogGID;
+}
+//-----------------------------------------------------------------------------
+bool FILES_STORE_SETTINGS::GetRemoveBak() const
+{
+return removeBak;
+}
+//-----------------------------------------------------------------------------
+bool FILES_STORE_SETTINGS::GetReadBak() const
+{
+return readBak;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+/*BASE_SETTINGS * FILES_STORE::GetStoreSettings()
+{
+return &storeSettings;
+}*/
+//-----------------------------------------------------------------------------
+FILES_STORE::FILES_STORE()
+{
+version = "file_store v.1.04";
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+};
+//-----------------------------------------------------------------------------
+FILES_STORE::~FILES_STORE()
+{
+
+};
+//-----------------------------------------------------------------------------
+void FILES_STORE::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::ParseSettings()
+{
+int ret = storeSettings.ParseSettings(settings);
+if (ret)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = storeSettings.GetStrError();
+    }
+return ret;
+}
+//-----------------------------------------------------------------------------
+const string & FILES_STORE::GetStrError() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+const string & FILES_STORE::GetVersion() const
+{
+return version;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetFilesList(vector<string> * filesList, const string & directory, mode_t mode, const string & ext) const
+{
+// æÕÎËÃÉÑ ÐÒÏÓÍÁÔÒÉ×ÁÅÔ ÓÏÄÅÒÖÉÍÏÅ ÄÉÒÅËÔÏÒÉÉ
+DIR * d;
+string str;
+struct stat st;
+dirent * dir;
+
+filesList->clear();
+
+d = opendir(directory.c_str());
+
+if (!d)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Directory \'" + directory + "\' cannot be opened.";
+    //printfd(__FILE__, "%s\n", errorStr.c_str());
+    return -1;
+    }
+
+int d_nameLen;
+int extLen = ext.size() ;
+while ((dir = readdir(d)))
+    {
+    if (strcmp(dir->d_name, ".") && strcmp(dir->d_name, ".."))
+        {
+        str = directory + "/" + string(dir->d_name);
+        if (!stat(str.c_str(), &st))
+            {
+            if (st.st_mode & mode) // ïÔÓÅ× ÆÁÊÌÏ× or directories
+                {
+                d_nameLen = strlen(dir->d_name);
+                if (d_nameLen > extLen)
+                    {
+                    if (strcmp(dir->d_name + (d_nameLen - extLen), ext.c_str()) == 0)
+                        {
+                        dir->d_name[d_nameLen - extLen] = 0;
+                        filesList->push_back(dir->d_name);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+closedir(d);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetUsersList(vector<string> * usersList) const
+{
+return GetFilesList(usersList, storeSettings.GetUsersDir(), S_IFDIR, "");
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetAdminsList(vector<string> * adminsList) const
+{
+return GetFilesList(adminsList, storeSettings.GetAdminsDir(), S_IFREG, ".adm");
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetTariffsList(vector<string> * tariffsList) const
+{
+return GetFilesList(tariffsList, storeSettings.GetTariffsDir(), S_IFREG, ".tf");
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RemoveDir(const char * path) const
+{
+vector<string> filesList;
+
+GetFilesList(&filesList, path, S_IFREG, "");
+
+for (unsigned i = 0; i < filesList.size(); i++)
+    {
+    string file = path + string("/") + filesList[i];
+    if (unlink(file.c_str()))
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "unlink failed. Message: '";
+        errorStr += strerror(errno);
+        errorStr += "'";
+        printfd(__FILE__, "FILES_STORE::RemoveDir - unlink failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+
+GetFilesList(&filesList, path, S_IFDIR, "");
+
+for (unsigned i = 0; i < filesList.size(); i++)
+    {
+    string dir = string(path) + "/" + filesList[i];
+    RemoveDir(dir.c_str());
+    }
+
+if (rmdir(path))
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "rmdir failed. Message: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    printfd(__FILE__, "FILES_STORE::RemoveDir - rmdir failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::AddUser(const string & login) const
+{
+FILE * f;
+string fileName;
+
+strprintf(&fileName, "%s%s", storeSettings.GetUsersDir().c_str(), login.c_str());
+
+if (mkdir(fileName.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = string("mkdir failed. Message: '") + strerror(errno) + "'";
+    printfd(__FILE__, "FILES_STORE::AddUser - mkdir failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+strprintf(&fileName, "%s%s/conf", storeSettings.GetUsersDir().c_str(), login.c_str());
+f = fopen(fileName.c_str(), "wt");
+if (f)
+    {
+    if (fprintf(f, "\n") < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "fprintf failed. Message: '";
+        errorStr += strerror(errno);
+        errorStr += "'";
+        printfd(__FILE__, "FILES_STORE::AddUser - fprintf failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    fclose(f);
+    }
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot create file \"" + fileName + "\'";
+    printfd(__FILE__, "FILES_STORE::AddUser - fopen failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+strprintf(&fileName, "%s%s/stat", storeSettings.GetUsersDir().c_str(), login.c_str());
+f = fopen(fileName.c_str(), "wt");
+if (f)
+    {
+    if (fprintf(f, "\n") < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "fprintf failed. Message: '";
+        errorStr += strerror(errno);
+        errorStr += "'";
+        printfd(__FILE__, "FILES_STORE::AddUser - fprintf failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    fclose(f);
+    }
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot create file \"" + fileName + "\'";
+    printfd(__FILE__, "FILES_STORE::AddUser - fopen failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::DelUser(const string & login) const
+{
+string dirName;
+string dirName1;
+
+strprintf(&dirName, "%s/"DELETED_USERS_DIR, storeSettings.GetWorkDir().c_str());
+if (access(dirName.c_str(), F_OK) != 0)
+    {
+    if (mkdir(dirName.c_str(), 0700) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Directory '" + dirName + "' cannot be created.";
+        printfd(__FILE__, "FILES_STORE::DelUser - mkdir failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+
+if (access(dirName.c_str(), F_OK) == 0)
+    {
+    strprintf(&dirName, "%s/"DELETED_USERS_DIR"/%s.%lu", storeSettings.GetWorkDir().c_str(), login.c_str(), time(NULL));
+    strprintf(&dirName1, "%s/%s", storeSettings.GetUsersDir().c_str(), login.c_str());
+    if (rename(dirName1.c_str(), dirName.c_str()))
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Error moving dir from " + dirName1 + " to " + dirName;
+        printfd(__FILE__, "FILES_STORE::DelUser - rename failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+else
+    {
+    strprintf(&dirName, "%s/%s", storeSettings.GetUsersDir().c_str(), login.c_str());
+    if (RemoveDir(dirName.c_str()))
+        {
+        return -1;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserConf(USER_CONF * conf, const string & login) const
+{
+string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/conf";
+if (RestoreUserConf(conf, login, fileName))
+    {
+    if (!storeSettings.GetReadBak())
+        {
+        return -1;
+        }
+    return RestoreUserConf(conf, login, fileName + ".bak");
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserConf(USER_CONF * conf, const string & login, const string & fileName) const
+{
+CONFIGFILE cf(fileName);
+int e = cf.Error();
+string str;
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - conf read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadString("Password", &conf->password, "") < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter Password.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - password read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+if (conf->password.empty())
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' password is blank.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - password is blank for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadString("tariff", &conf->tariffName, "") < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter Tariff.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - tariff read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+if (conf->tariffName.empty())
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' tariff is blank.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - tariff is blank for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+string ipStr;
+cf.ReadString("IP", &ipStr, "?");
+USER_IPS i;
+try
+    {
+    i = StrToIPS(ipStr);
+    }
+catch (string s)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - ip read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+conf->ips = i;
+
+if (cf.ReadInt("alwaysOnline", &conf->alwaysOnline, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - alwaysonline read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("down", &conf->disabled, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter Down.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - down read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("passive", &conf->passive, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - passive read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+cf.ReadInt("DisabledDetailStat", &conf->disabledDetailStat, 0);
+cf.ReadTime("CreditExpire", &conf->creditExpire, 0);
+cf.ReadString("TariffChange", &conf->nextTariff, "");
+cf.ReadString("Group", &conf->group, "");
+cf.ReadString("RealName", &conf->realName, "");
+cf.ReadString("Address", &conf->address, "");
+cf.ReadString("Phone", &conf->phone, "");
+cf.ReadString("Note", &conf->note, "");
+cf.ReadString("email", &conf->email, "");
+
+char userdataName[12];
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    snprintf(userdataName, 12, "Userdata%d", i);
+    cf.ReadString(userdataName, &conf->userdata[i], "");
+    }
+
+if (cf.ReadDouble("Credit", &conf->credit, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
+    printfd(__FILE__, "FILES_STORE::RestoreUserConf - credit read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserStat(USER_STAT * stat, const string & login) const
+{
+string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/stat";
+
+if (RestoreUserStat(stat, login, fileName))
+    {
+    if (!storeSettings.GetReadBak())
+        {
+        return -1;
+        }
+    return RestoreUserStat(stat, login, fileName + ".bak");
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreUserStat(USER_STAT * stat, const string & login, const string & fileName) const
+{
+CONFIGFILE cf(fileName);
+
+int e = cf.Error();
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "User \'" + login + "\' stat not read. Cannot open file " + fileName + ".";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - stat read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+char s[22];
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    uint64_t traff;
+    snprintf(s, 22, "D%d", i);
+    if (cf.ReadULongLongInt(s, &traff, 0) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "User \'" + login + "\' stat not read. Parameter " + string(s);
+        printfd(__FILE__, "FILES_STORE::RestoreUserStat - download stat read failed for user '%s'\n", login.c_str());
+        return -1;
+        }
+    stat->down[i] = traff;
+
+    snprintf(s, 22, "U%d", i);
+    if (cf.ReadULongLongInt(s, &traff, 0) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr =   "User \'" + login + "\' stat not read. Parameter " + string(s);
+        printfd(__FILE__, "FILES_STORE::RestoreUserStat - upload stat read failed for user '%s'\n", login.c_str());
+        return -1;
+        }
+    stat->up[i] = traff;
+    }
+
+if (cf.ReadDouble("Cash", &stat->cash, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter Cash";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - cash read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadDouble("FreeMb", &stat->freeMb, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter FreeMb";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - freemb read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadTime("LastCashAddTime", &stat->lastCashAddTime, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastcashaddtime read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadTime("PassiveTime", &stat->passiveTime, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter PassiveTime";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - passivetime read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadDouble("LastCashAdd", &stat->lastCashAdd, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAdd";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastcashadd read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+if (cf.ReadTime("LastActivityTime", &stat->lastActivityTime, 0) != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastActivityTime";
+    printfd(__FILE__, "FILES_STORE::RestoreUserStat - lastactivitytime read failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveUserConf(const USER_CONF & conf, const string & login) const
+{
+string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/conf";
+
+BAK_FILE bakFile(fileName, storeSettings.GetRemoveBak());
+
+if (access(fileName.c_str(), W_OK) != 0)
+    {
+    FILE * f;
+    f = fopen(fileName.c_str(), "wb");
+    if (f)
+        fclose(f);
+    }
+
+CONFIGFILE cfstat(fileName);
+
+int e = cfstat.Error();
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = string("User \'") + login + "\' conf not written\n";
+    printfd(__FILE__, "FILES_STORE::SaveUserConf - conf write failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+e = chmod(fileName.c_str(), storeSettings.GetConfMode());
+e += chown(fileName.c_str(), storeSettings.GetConfUID(), storeSettings.GetConfGID());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::SaveUserConf - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+cfstat.WriteString("Password",     conf.password);
+cfstat.WriteInt   ("Passive",      conf.passive);
+cfstat.WriteInt   ("Down",         conf.disabled);
+cfstat.WriteInt("DisabledDetailStat", conf.disabledDetailStat);
+cfstat.WriteInt   ("AlwaysOnline", conf.alwaysOnline);
+cfstat.WriteString("Tariff",       conf.tariffName);
+cfstat.WriteString("Address",      conf.address);
+cfstat.WriteString("Phone",        conf.phone);
+cfstat.WriteString("Email",        conf.email);
+cfstat.WriteString("Note",         conf.note);
+cfstat.WriteString("RealName",     conf.realName);
+cfstat.WriteString("Group",        conf.group);
+cfstat.WriteDouble("Credit",       conf.credit);
+cfstat.WriteString("TariffChange", conf.nextTariff);
+
+char userdataName[12];
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    snprintf(userdataName, 12, "Userdata%d", i);
+    cfstat.WriteString(userdataName, conf.userdata[i]);
+    }
+cfstat.WriteInt("CreditExpire",    conf.creditExpire);
+
+stringstream ipStr;
+ipStr << conf.ips;
+cfstat.WriteString("IP", ipStr.str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveUserStat(const USER_STAT & stat, const string & login) const
+{
+char s[22];
+string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/stat";
+
+BAK_FILE bakFile(fileName, storeSettings.GetRemoveBak());
+
+if (access(fileName.c_str(), W_OK) != 0)
+    {
+    FILE * f;
+    f = fopen(fileName.c_str(), "wb");
+    if (f)
+        fclose(f);
+    }
+
+CONFIGFILE cfstat(fileName);
+int e = cfstat.Error();
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = string("User \'") + login + "\' stat not written\n";
+    printfd(__FILE__, "FILES_STORE::SaveUserStat - stat write failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    snprintf(s, 22, "D%d", i);
+    cfstat.WriteInt(s, stat.down[i]);
+    snprintf(s, 22, "U%d", i);
+    cfstat.WriteInt(s, stat.up[i]);
+    }
+
+cfstat.WriteDouble("Cash", stat.cash);
+cfstat.WriteDouble("FreeMb", stat.freeMb);
+cfstat.WriteDouble("LastCashAdd", stat.lastCashAdd);
+cfstat.WriteInt("LastCashAddTime", stat.lastCashAddTime);
+cfstat.WriteInt("PassiveTime", stat.passiveTime);
+cfstat.WriteInt("LastActivityTime", stat.lastActivityTime);
+
+e = chmod(fileName.c_str(), storeSettings.GetStatMode());
+e += chown(fileName.c_str(), storeSettings.GetStatUID(), storeSettings.GetStatGID());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::SaveUserStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteLogString(const string & str, const string & login) const
+{
+FILE * f;
+time_t tm = time(NULL);
+string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/log";
+f = fopen(fileName.c_str(), "at");
+
+if (f)
+    {
+    fprintf(f, "%s", LogDate(tm));
+    fprintf(f, " -- ");
+    fprintf(f, "%s", str.c_str());
+    fprintf(f, "\n");
+    fclose(f);
+    }
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot open \'" + fileName + "\'";
+    printfd(__FILE__, "FILES_STORE::WriteLogString - log write failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+int e = chmod(fileName.c_str(), storeSettings.GetLogMode());
+e += chown(fileName.c_str(), storeSettings.GetLogUID(), storeSettings.GetLogGID());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::WriteLogString - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteLog2String(const string & str, const string & login) const
+{
+FILE * f;
+time_t tm = time(NULL);
+string fileName;
+fileName = storeSettings.GetUsersDir() + "/" + login + "/log2";
+f = fopen(fileName.c_str(), "at");
+
+if (f)
+    {
+    fprintf(f, "%s", LogDate(tm));
+    fprintf(f, " -- ");
+    fprintf(f, "%s", str.c_str());
+    fprintf(f, "\n");
+    fclose(f);
+    }
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot open \'" + fileName + "\'";
+    printfd(__FILE__, "FILES_STORE::WriteLogString - log write failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+int e = chmod(fileName.c_str(), storeSettings.GetLogMode());
+e += chown(fileName.c_str(), storeSettings.GetLogUID(), storeSettings.GetLogGID());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::WriteLogString - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteUserChgLog(const string & login,
+                                 const string & admLogin,
+                                 uint32_t       admIP,
+                                 const string & paramName,
+                                 const string & oldValue,
+                                 const string & newValue,
+                                 const string & message) const
+{
+string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
+    + paramName + "\' parameter changed from \'" + oldValue +
+    "\' to \'" + newValue + "\'. " + message;
+
+return WriteLogString(userLogMsg, login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteUserConnect(const string & login, uint32_t ip) const
+{
+string logStr = "Connect, " + inet_ntostring(ip);
+if (WriteLogString(logStr, login))
+    return -1;
+return WriteLog2String(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteUserDisconnect(const string & login,
+                                     const DIR_TRAFF & up,
+                                     const DIR_TRAFF & down,
+                                     const DIR_TRAFF & sessionUp,
+                                     const DIR_TRAFF & sessionDown,
+                                     double cash,
+                                     double freeMb,
+                                     const std::string & reason) const
+{
+stringstream logStr;
+logStr << "Disconnect, ";
+/*stringstream sssu;
+stringstream sssd;
+stringstream ssmu;
+stringstream ssmd;
+stringstream sscash;
+
+ssmu << up;
+ssmd << down;
+
+sssu << sessionUp;
+sssd << sessionDown;
+
+sscash << cash;*/
+
+logStr << " session upload: \'"
+       << sessionUp
+       << "\' session download: \'"
+       << sessionDown
+       << "\' month upload: \'"
+       << up
+       << "\' month download: \'"
+       << down
+       << "\' cash: \'"
+       << cash
+       << "\'";
+
+if (WriteLogString(logStr.str(), login))
+    return -1;
+
+logStr << " freeMb: \'"
+       << freeMb
+       << "\'"
+       << " reason: \'"
+       << reason
+       << "\'";
+
+return WriteLog2String(logStr.str(), login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const
+{
+string str;
+CONFIGFILE * s;
+int e;
+FILE *f;
+
+strprintf(&str,"%s/%s/stat.%d.%02d",
+        storeSettings.GetUsersDir().c_str(), login.c_str(), year + 1900, month + 1);
+
+if ((f = fopen(str.c_str(), "w")))
+    {
+    fprintf(f, "\n");
+    fclose(f);
+    }
+
+s = new CONFIGFILE(str);
+e = s->Error();
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot create file " + str;
+    printfd(__FILE__, "FILES_STORE::SaveMonthStat - month stat write failed for user '%s'\n", login.c_str());
+    return -1;
+    }
+
+char dirName[3];
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    snprintf(dirName, 3, "U%d", i);
+    s->WriteInt(dirName, stat.up[i]);
+    snprintf(dirName, 3, "D%d", i);
+    s->WriteInt(dirName, stat.down[i]);
+    }
+
+s->WriteDouble("cash", stat.cash);
+
+delete s;
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::AddAdmin(const string & login) const
+{
+string fileName;
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
+FILE * f;
+f = fopen(fileName.c_str(), "wt");
+if (f)
+    {
+    fprintf(f, "\n");
+    fclose(f);
+    return 0;
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+errorStr = "Cannot create file " + fileName;
+printfd(__FILE__, "FILES_STORE::AddAdmin - failed to add admin '%s'\n", login.c_str());
+return -1;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::DelAdmin(const string & login) const
+{
+string fileName;
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
+if (unlink(fileName.c_str()))
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "unlink failed. Message: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int FILES_STORE::SaveAdmin(const ADMIN_CONF & ac) const
+{
+char passwordE[2 * ADM_PASSWD_LEN + 2];
+char pass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+
+string fileName;
+
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), ac.login.c_str());
+
+CONFIGFILE cf(fileName);
+
+int e = cf.Error();
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot write admin " + ac.login + ". " + fileName;
+    printfd(__FILE__, "FILES_STORE::SaveAdmin - failed to save admin '%s'\n", ac.login.c_str());
+    return -1;
+    }
+
+memset(pass, 0, sizeof(pass));
+memset(adminPass, 0, sizeof(adminPass));
+
+BLOWFISH_CTX ctx;
+EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+adminPass[ADM_PASSWD_LEN - 1] = 0;
+
+for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+    {
+    EncodeString(pass + 8*i, adminPass + 8*i, &ctx);
+    }
+
+pass[ADM_PASSWD_LEN - 1] = 0;
+Encode12(passwordE, pass, ADM_PASSWD_LEN);
+//printfd(__FILE__, "passwordE %s\n", passwordE);
+
+cf.WriteString("password", passwordE);
+cf.WriteInt("ChgConf",     ac.priv.userConf);
+cf.WriteInt("ChgPassword", ac.priv.userPasswd);
+cf.WriteInt("ChgStat",     ac.priv.userStat);
+cf.WriteInt("ChgCash",     ac.priv.userCash);
+cf.WriteInt("UsrAddDel",   ac.priv.userAddDel);
+cf.WriteInt("ChgTariff",   ac.priv.tariffChg);
+cf.WriteInt("ChgAdmin",    ac.priv.adminChg);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreAdmin(ADMIN_CONF * ac, const string & login) const
+{
+string fileName;
+strprintf(&fileName, "%s/%s.adm", storeSettings.GetAdminsDir().c_str(), login.c_str());
+CONFIGFILE cf(fileName);
+char pass[ADM_PASSWD_LEN + 1];
+char password[ADM_PASSWD_LEN + 1];
+char passwordE[2*ADM_PASSWD_LEN + 2];
+BLOWFISH_CTX ctx;
+
+string p;
+
+if (cf.Error())
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot open " + fileName;
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - failed to restore admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+int a;
+
+if (cf.ReadString("password", &p, "*"))
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter password";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - password read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+memset(passwordE, 0, sizeof(passwordE));
+strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
+
+//printfd(__FILE__, "passwordE %s\n", passwordE);
+
+memset(pass, 0, sizeof(pass));
+
+if (passwordE[0] != 0)
+    {
+    Decode21(pass, passwordE);
+    EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+    for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+        {
+        DecodeString(password + 8*i, pass + 8*i, &ctx);
+        }
+    }
+else
+    {
+    password[0] = 0;
+    }
+
+ac->password = password;
+
+if (cf.ReadInt("ChgConf", &a, 0) == 0)
+    ac->priv.userConf = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter ChgConf";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgconf read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("ChgPassword", &a, 0) == 0)
+    ac->priv.userPasswd = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter ChgPassword";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgpassword read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("ChgStat", &a, 0) == 0)
+    ac->priv.userStat = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter ChgStat";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgstat read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("ChgCash", &a, 0) == 0)
+    ac->priv.userCash = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter ChgCash";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgcash read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("UsrAddDel", &a, 0) == 0)
+    ac->priv.userAddDel = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter UsrAddDel";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - usradddel read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("ChgAdmin", &a, 0) == 0)
+    ac->priv.adminChg = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter ChgAdmin";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgadmin read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+if (cf.ReadInt("ChgTariff", &a, 0) == 0)
+    ac->priv.tariffChg = a;
+else
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error in parameter ChgTariff";
+    printfd(__FILE__, "FILES_STORE::RestoreAdmin - chgtariff read failed for admin '%s'\n", ac->login.c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::AddTariff(const string & name) const
+{
+string fileName;
+strprintf(&fileName, "%s/%s.tf", storeSettings.GetTariffsDir().c_str(), name.c_str());
+FILE * f;
+f = fopen(fileName.c_str(), "wt");
+if (f)
+    {
+    fprintf(f, "\n");
+    fclose(f);
+    return 0;
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+errorStr = "Cannot create file " + fileName;
+printfd(__FILE__, "FILES_STORE::AddTariff - failed to add tariff '%s'\n", name.c_str());
+return -1;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::DelTariff(const string & name) const
+{
+string fileName;
+strprintf(&fileName, "%s/%s.tf", storeSettings.GetTariffsDir().c_str(), name.c_str());
+if (unlink(fileName.c_str()))
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "unlink failed. Message: '";
+    errorStr += strerror(errno);
+    errorStr += "'";
+    printfd(__FILE__, "FILES_STORE::DelTariff - unlink failed. Message: '%s'\n", strerror(errno));
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::RestoreTariff(TARIFF_DATA * td, const string & tariffName) const
+{
+string tariffFileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
+CONFIGFILE conf(tariffFileName);
+string str;
+td->tariffConf.name = tariffName;
+
+if (conf.Error() != 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot read file " + tariffFileName;
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - failed to read tariff '%s'\n", tariffName.c_str());
+    return -1;
+    }
+
+string param;
+for (int i = 0; i<DIR_NUM; i++)
+    {
+    strprintf(&param, "Time%d", i);
+    if (conf.ReadString(param, &str, "00:00-00:00") < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - time%d read failed for tariff '%s'\n", i, tariffName.c_str());
+        return -1;
+        }
+
+    ParseTariffTimeStr(str.c_str(),
+                       td->dirPrice[i].hDay,
+                       td->dirPrice[i].mDay,
+                       td->dirPrice[i].hNight,
+                       td->dirPrice[i].mNight);
+
+    strprintf(&param, "PriceDayA%d", i);
+    if (conf.ReadDouble(param, &td->dirPrice[i].priceDayA, 0.0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - pricedaya read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+    td->dirPrice[i].priceDayA /= (1024*1024);
+
+    strprintf(&param, "PriceDayB%d", i);
+    if (conf.ReadDouble(param, &td->dirPrice[i].priceDayB, 0.0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - pricedayb read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+    td->dirPrice[i].priceDayB /= (1024*1024);
+
+    strprintf(&param, "PriceNightA%d", i);
+    if (conf.ReadDouble(param, &td->dirPrice[i].priceNightA, 0.0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - pricenighta read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+    td->dirPrice[i].priceNightA /= (1024*1024);
+
+    strprintf(&param, "PriceNightB%d", i);
+    if (conf.ReadDouble(param, &td->dirPrice[i].priceNightB, 0.0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - pricenightb read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+    td->dirPrice[i].priceNightB /= (1024*1024);
+
+    strprintf(&param, "Threshold%d", i);
+    if (conf.ReadInt(param, &td->dirPrice[i].threshold, 0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - threshold read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+
+    strprintf(&param, "SinglePrice%d", i);
+    if (conf.ReadInt(param, &td->dirPrice[i].singlePrice, 0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - singleprice read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+
+    strprintf(&param, "NoDiscount%d", i);
+    if (conf.ReadInt(param, &td->dirPrice[i].noDiscount, 0) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        printfd(__FILE__, "FILES_STORE::RestoreTariff - nodiscount read failed for tariff '%s'\n", tariffName.c_str());
+        return -1;
+        }
+    }
+
+if (conf.ReadDouble("Fee", &td->tariffConf.fee, 0) < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - fee read failed for tariff '%s'\n", tariffName.c_str());
+    return -1;
+    }
+
+if (conf.ReadDouble("Free", &td->tariffConf.free, 0) < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - free read failed for tariff '%s'\n", tariffName.c_str());
+    return -1;
+    }
+
+if (conf.ReadDouble("PassiveCost", &td->tariffConf.passiveCost, 0) < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - passivecost read failed for tariff '%s'\n", tariffName.c_str());
+    return -1;
+    }
+
+if (conf.ReadString("TraffType", &str, "") < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType";
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - trafftype read failed for tariff '%s'\n", tariffName.c_str());
+    return -1;
+    }
+
+if (!strcasecmp(str.c_str(), "up"))
+    td->tariffConf.traffType = TRAFF_UP;
+else
+    if (!strcasecmp(str.c_str(), "down"))
+        td->tariffConf.traffType = TRAFF_DOWN;
+    else
+        if (!strcasecmp(str.c_str(), "up+down"))
+            td->tariffConf.traffType = TRAFF_UP_DOWN;
+        else
+            if (!strcasecmp(str.c_str(), "max"))
+                td->tariffConf.traffType = TRAFF_MAX;
+            else
+                {
+                STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+                errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType incorrect";
+                printfd(__FILE__, "FILES_STORE::RestoreTariff - invalid trafftype for tariff '%s'\n", tariffName.c_str());
+                return -1;
+                }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::SaveTariff(const TARIFF_DATA & td, const string & tariffName) const
+{
+string tariffFileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf";
+if (access(tariffFileName.c_str(), W_OK) != 0)
+    {
+    int fd = open(tariffFileName.c_str(), O_CREAT, 0600);
+    if (fd)
+        close(fd);
+    }
+
+CONFIGFILE cf(tariffFileName);
+
+int e = cf.Error();
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Error writing tariff " + tariffName;
+    printfd(__FILE__, "FILES_STORE::RestoreTariff - failed to save tariff '%s'\n", tariffName.c_str());
+    return e;
+    }
+
+string param;
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, "PriceDayA%d", i);
+    cf.WriteDouble(param, td.dirPrice[i].priceDayA * pt_mega);
+
+    strprintf(&param, "PriceDayB%d", i);
+    cf.WriteDouble(param, td.dirPrice[i].priceDayB * pt_mega);
+
+    strprintf(&param, "PriceNightA%d", i);
+    cf.WriteDouble(param, td.dirPrice[i].priceNightA * pt_mega);
+
+    strprintf(&param, "PriceNightB%d", i);
+    cf.WriteDouble(param, td.dirPrice[i].priceNightB * pt_mega);
+
+    strprintf(&param, "Threshold%d", i);
+    cf.WriteInt(param, td.dirPrice[i].threshold);
+
+    string s;
+    strprintf(&param, "Time%d", i);
+
+    strprintf(&s, "%0d:%0d-%0d:%0d",
+            td.dirPrice[i].hDay,
+            td.dirPrice[i].mDay,
+            td.dirPrice[i].hNight,
+            td.dirPrice[i].mNight);
+
+    cf.WriteString(param, s);
+
+    strprintf(&param, "NoDiscount%d", i);
+    cf.WriteInt(param, td.dirPrice[i].noDiscount);
+
+    strprintf(&param, "SinglePrice%d", i);
+    cf.WriteInt(param, td.dirPrice[i].singlePrice);
+    }
+
+cf.WriteDouble("PassiveCost", td.tariffConf.passiveCost);
+cf.WriteDouble("Fee", td.tariffConf.fee);
+cf.WriteDouble("Free", td.tariffConf.free);
+
+switch (td.tariffConf.traffType)
+    {
+    case TRAFF_UP:
+        cf.WriteString("TraffType", "up");
+        break;
+    case TRAFF_DOWN:
+        cf.WriteString("TraffType", "down");
+        break;
+    case TRAFF_UP_DOWN:
+        cf.WriteString("TraffType", "up+down");
+        break;
+    case TRAFF_MAX:
+        cf.WriteString("TraffType", "max");
+        break;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                   time_t lastStat,
+                                   const string & login) const
+{
+char fn[FN_STR_LEN];
+char dn[FN_STR_LEN];
+FILE * statFile;
+//char timestr[30];
+time_t t;//, lastTimeReal;
+tm * lt;
+
+t = time(NULL);
+
+snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat", storeSettings.GetUsersDir().c_str(), login.c_str());
+if (access(dn, F_OK) != 0)
+    {
+    if (mkdir(dn, 0700) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Directory \'" + string(dn) + "\' cannot be created.";
+        printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+
+int e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(dn, storeSettings.GetStatModeDir());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+lt = localtime(&t);
+
+if (lt->tm_hour == 0 && lt->tm_min <= 5)
+    {
+    t -= 3600 * 24;
+    lt = localtime(&t);
+    }
+
+snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat/%d",
+         storeSettings.GetUsersDir().c_str(),
+         login.c_str(),
+         lt->tm_year+1900);
+
+if (access(dn, F_OK) != 0)
+    {
+    if (mkdir(dn, 0700) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Directory \'" + string(dn) + "\' cannot be created.";
+        printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+
+e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(dn, storeSettings.GetStatModeDir());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+snprintf(dn, FN_STR_LEN, "%s/%s/detail_stat/%d/%s%d", 
+         storeSettings.GetUsersDir().c_str(),
+         login.c_str(),
+         lt->tm_year+1900,
+         lt->tm_mon+1 < 10 ? "0" : "",
+         lt->tm_mon+1);
+if (access(dn, F_OK) != 0)
+    {
+    if (mkdir(dn, 0700) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Directory \'" + string(dn) + "\' cannot be created.";
+        printfd(__FILE__, "FILES_STORE::WriteDetailStat - mkdir failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+
+e = chown(dn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(dn, storeSettings.GetStatModeDir());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+snprintf(fn, FN_STR_LEN, "%s/%s%d", dn, lt->tm_mday < 10 ? "0" : "", lt->tm_mday);
+
+statFile = fopen (fn, "at");
+
+if (!statFile)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "File \'" + string(fn) + "\' cannot be written.";
+    printfd(__FILE__, "FILES_STORE::WriteDetailStat - fopen failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+struct tm * lt1;
+struct tm * lt2;
+
+lt1 = localtime(&lastStat);
+
+int h1, m1, s1;
+int h2, m2, s2;
+
+h1 = lt1->tm_hour;
+m1 = lt1->tm_min;
+s1 = lt1->tm_sec;
+
+lt2 = localtime(&t);
+
+h2 = lt2->tm_hour;
+m2 = lt2->tm_min;
+s2 = lt2->tm_sec;
+
+if (fprintf(statFile, "-> %02d.%02d.%02d - %02d.%02d.%02d\n",
+            h1, m1, s1, h2, m2, s2) < 0)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = string("fprint failed. Message: '") + strerror(errno) + "'";
+    printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+map<IP_DIR_PAIR, STAT_NODE>::const_iterator stIter;
+stIter = statTree->begin();
+
+while (stIter != statTree->end())
+    {
+    string u, d;
+    x2str(stIter->second.up, u);
+    x2str(stIter->second.down, d);
+    #ifdef TRAFF_STAT_WITH_PORTS
+    if (fprintf(statFile, "%17s:%hu\t%15d\t%15s\t%15s\t%f\n",
+                inet_ntostring(stIter->first.ip).c_str(),
+                stIter->first.port,
+                stIter->first.dir,
+                d.c_str(),
+                u.c_str(),
+                stIter->second.cash) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "fprint failed. Message: '";
+        errorStr += strerror(errno);
+        errorStr += "'";
+        printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    #else
+    if (fprintf(statFile, "%17s\t%15d\t%15s\t%15s\t%f\n",
+                inet_ntostring(stIter->first.ip).c_str(),
+                stIter->first.dir,
+                d.c_str(),
+                u.c_str(),
+                stIter->second.cash) < 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = string("fprint failed. Message: '");
+        errorStr += strerror(errno);
+        errorStr += "'";
+        printfd(__FILE__, "FILES_STORE::WriteDetailStat - fprintf failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    #endif
+
+    ++stIter;
+    }
+
+fclose(statFile);
+
+e = chown(fn, storeSettings.GetStatUID(), storeSettings.GetStatGID());
+e += chmod(fn, storeSettings.GetStatMode());
+
+if (e)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    printfd(__FILE__, "FILES_STORE::WriteDetailStat - chmod/chown failed for user '%s'. Error: '%s'\n", login.c_str(), strerror(errno));
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::AddMessage(STG_MSG * msg, const string & login) const
+{
+//ðÒÏ×ÅÒÉÔØ ÅÓÌÔØ ÌÉ ÄÉÒÅËÔÏÒÉÑ ÄÌÑ ÓÏÏÂÝÅÎÉÊ. åÓÌÉ ÎÅÔ - ÓÏÚÄÁÔØ.
+//úÁÔÅÍ ÐÏÌÏÖÉÔØ ÓÏÏÂÝÅÎÉÅ Ó ÉÍÅÎÅÍ ÆÁÊÌÁ - ×ÒÅÍÅÎÎOÊ ÍÅÔËÏÊ. úÁÐÉÓÁÔØ ÔÕÄÁ
+//ÔÅËÓÔ É ÐÒÉÏÒÉÔÅÔ.
+
+string fn;
+string dn;
+struct timeval tv;
+FILE * msgFile;
+
+strprintf(&dn, "%s/%s/messages", storeSettings.GetUsersDir().c_str(), login.c_str());
+if (access(dn.c_str(), F_OK) != 0)
+    {
+    if (mkdir(dn.c_str(), 0700) != 0)
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Directory \'";
+        errorStr += dn;
+        errorStr += "\' cannot be created.";
+        printfd(__FILE__, "FILES_STORE::AddMessage - mkdir failed. Message: '%s'\n", strerror(errno));
+        return -1;
+        }
+    }
+
+chmod(dn.c_str(), storeSettings.GetConfMode() | S_IXUSR);
+
+gettimeofday(&tv, NULL);
+
+msg->header.id = ((long long)tv.tv_sec) * 1000000 + ((long long)tv.tv_usec);
+strprintf(&fn, "%s/%lld", dn.c_str(), msg->header.id);
+
+msgFile = fopen (fn.c_str(), "wt");
+
+if (!msgFile)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "File \'";
+    errorStr += fn;
+    errorStr += "\' cannot be writen.";
+    printfd(__FILE__, "FILES_STORE::AddMessage - fopen failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+fclose(msgFile);
+return EditMessage(*msg, login);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::EditMessage(const STG_MSG & msg, const string & login) const
+{
+//ðÒÏ×ÅÒÉÔØ ÅÓÌÔØ ÌÉ ÄÉÒÅËÔÏÒÉÑ ÄÌÑ ÓÏÏÂÝÅÎÉÊ. åÓÌÉ ÎÅÔ - ÓÏÚÄÁÔØ.
+//úÁÔÅÍ ÐÏÌÏÖÉÔØ ÓÏÏÂÝÅÎÉÅ Ó ÉÍÅÎÅÍ ÆÁÊÌÁ - ×ÒÅÍÅÎÎOÊ ÍÅÔËÏÊ. úÁÐÉÓÁÔØ ÔÕÄÁ
+//ÔÅËÓÔ É ÐÒÉÏÒÉÔÅÔ.
+
+string fn;
+
+FILE * msgFile;
+strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), msg.header.id);
+
+if (access(fn.c_str(), F_OK) != 0)
+    {
+    string idstr;
+    x2str(msg.header.id, idstr);
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "Message for user \'";
+    errorStr += login + "\' with ID \'";
+    errorStr += idstr + "\' does not exist.";
+    printfd(__FILE__, "FILES_STORE::EditMessage - %s\n", errorStr.c_str());
+    return -1;
+    }
+
+msgFile = fopen(fn.c_str(), "wt");
+if (!msgFile)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "File \'" + fn + "\' cannot be writen.";
+    printfd(__FILE__, "FILES_STORE::EditMessage - fopen failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+bool res = true;
+res &= (fprintf(msgFile, "%d\n", msg.header.type) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.lastSendTime) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.creationTime) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.showTime) >= 0);
+res &= (fprintf(msgFile, "%d\n", msg.header.repeat) >= 0);
+res &= (fprintf(msgFile, "%u\n", msg.header.repeatPeriod) >= 0);
+res &= (fprintf(msgFile, "%s", msg.text.c_str()) >= 0);
+
+if (!res)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = string("fprintf failed. Message: '") + strerror(errno) + "'";
+    printfd(__FILE__, "FILES_STORE::EditMessage - fprintf failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+
+fclose(msgFile);
+
+chmod(fn.c_str(), storeSettings.GetConfMode());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetMessage(uint64_t id, STG_MSG * msg, const string & login) const
+{
+string fn;
+strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), id);
+msg->header.id = id;
+return ReadMessage(fn, &msg->header, &msg->text);
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::DelMessage(uint64_t id, const string & login) const
+{
+string fn;
+strprintf(&fn, "%s/%s/messages/%lld", storeSettings.GetUsersDir().c_str(), login.c_str(), id);
+
+return unlink(fn.c_str());
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const
+{
+vector<string> messages;
+string dn;
+dn = storeSettings.GetUsersDir() + "/" + login + "/messages/";
+GetFilesList(&messages, dn, S_IFREG, "");
+
+//hdrsList->resize(messages.size());
+
+for (unsigned i = 0; i < messages.size(); i++)
+    {
+    unsigned long long id = 0;
+
+    if (str2x(messages[i].c_str(), id))
+        {
+        if (unlink((dn + messages[i]).c_str()))
+            {
+            STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+            errorStr = string("unlink failed. Message: '") + strerror(errno) + "'";
+            printfd(__FILE__, "FILES_STORE::GetMessageHdrs - unlink failed. Message: '%s'\n", strerror(errno));
+            return -1;
+            }
+        continue;
+        }
+
+    STG_MSG_HDR hdr;
+    if (ReadMessage(dn + messages[i], &hdr, NULL))
+        {
+        return -1;
+        }
+
+    if (hdr.repeat < 0)
+        {
+        if (unlink((dn + messages[i]).c_str()))
+            {
+            STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+            errorStr = string("unlink failed. Message: '") + strerror(errno) + "'";
+            printfd(__FILE__, "FILES_STORE::GetMessageHdrs - unlink failed. Message: '%s'\n", strerror(errno));
+            return -1;
+            }
+        continue;
+        }
+
+    hdr.id = id;
+    hdrsList->push_back(hdr);
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FILES_STORE::ReadMessage(const string & fileName,
+                             STG_MSG_HDR * hdr,
+                             string * text) const
+{
+FILE * msgFile;
+msgFile = fopen(fileName.c_str(), "rt");
+if (!msgFile)
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    errorStr = "File \'";
+    errorStr += fileName;
+    errorStr += "\' cannot be openned.";
+    printfd(__FILE__, "FILES_STORE::ReadMessage - fopen failed. Message: '%s'\n", strerror(errno));
+    return -1;
+    }
+char p[20];
+unsigned * d[6];
+d[0] = &hdr->type;
+d[1] = &hdr->lastSendTime;
+d[2] = &hdr->creationTime;
+d[3] = &hdr->showTime;
+d[4] = (unsigned*)(&hdr->repeat);
+d[5] = &hdr->repeatPeriod;
+
+memset(p, 0, sizeof(p));
+
+for (int pos = 0; pos < 6; pos++)
+    {
+    if (fgets(p, sizeof(p) - 1, msgFile) == NULL) {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read file \'";
+        errorStr += fileName;
+        errorStr += "\'. Missing data.";
+        printfd(__FILE__, "FILES_STORE::ReadMessage - cannot read file (missing data)\n");
+        printfd(__FILE__, "FILES_STORE::ReadMessage - position: %d\n", pos);
+        fclose(msgFile);
+        return -1;
+    }
+
+    char * ep;
+    ep = strrchr(p, '\r');
+    if (ep) *ep = 0;
+    ep = strrchr(p, '\n');
+    if (ep) *ep = 0;
+
+    if (feof(msgFile))
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read file \'";
+        errorStr += fileName;
+        errorStr += "\'. Missing data.";
+        printfd(__FILE__, "FILES_STORE::ReadMessage - cannot read file (feof)\n");
+        printfd(__FILE__, "FILES_STORE::ReadMessage - position: %d\n", pos);
+        fclose(msgFile);
+        return -1;
+        }
+
+    if (str2x(p, *(d[pos])))
+        {
+        STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+        errorStr = "Cannot read file \'";
+        errorStr += fileName;
+        errorStr += "\'. Incorrect value. \'";
+        errorStr += p;
+        errorStr += "\'";
+        printfd(__FILE__, "FILES_STORE::ReadMessage - incorrect value\n");
+        fclose(msgFile);
+        return -1;
+        }
+    }
+
+char txt[2048];
+memset(txt, 0, sizeof(txt));
+if (text)
+    {
+    text->erase(text->begin(), text->end());
+    while (!feof(msgFile))
+        {
+        txt[0] = 0;
+        if (fgets(txt, sizeof(txt) - 1, msgFile) == NULL) {
+            break;
+        }
+
+        (*text) += txt;
+        }
+    }
+//fprintf(msgFile, "%s\n", msg.text.c_str());
+fclose(msgFile);
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/files/file_store.h b/projects/stargazer/plugins/store/files/file_store.h
new file mode 100644 (file)
index 0000000..4734a54
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.22 $
+ $Date: 2010/01/19 11:06:53 $
+ $Author: faust $
+ */
+
+
+#ifndef FILE_STORE_H
+#define FILE_STORE_H
+
+#include <string>
+#include <sys/types.h>
+
+#include "base_settings.h"
+#include "base_store.h"
+#include "conffiles.h"
+#include "user_traff.h"
+
+using namespace std;
+//-----------------------------------------------------------------------------
+extern "C" BASE_STORE * GetStore();
+//-----------------------------------------------------------------------------
+class FILES_STORE_SETTINGS//: public BASE_SETTINGS
+{
+public:
+    FILES_STORE_SETTINGS();
+    virtual ~FILES_STORE_SETTINGS();
+    virtual int ParseSettings(const MODULE_SETTINGS & s);
+    virtual const string & GetStrError() const;
+
+    string  GetWorkDir() const;
+    string  GetUsersDir() const;
+    string  GetAdminsDir() const;
+    string  GetTariffsDir() const;
+
+    mode_t  GetStatMode() const;
+    mode_t  GetStatModeDir() const;
+    uid_t   GetStatUID() const;
+    gid_t   GetStatGID() const;
+
+    mode_t  GetConfMode() const;
+    mode_t  GetConfModeDir() const;
+    uid_t   GetConfUID() const;
+    gid_t   GetConfGID() const;
+
+    mode_t  GetLogMode() const;
+    uid_t   GetLogUID() const;
+    gid_t   GetLogGID() const;
+
+    bool    GetRemoveBak() const;
+    bool    GetReadBak() const;
+
+private:
+    const MODULE_SETTINGS * settings;
+
+    int     User2UID(const char * user, uid_t * uid);
+    int     Group2GID(const char * gr, gid_t * gid);
+    int     Str2Mode(const char * str, mode_t * mode);
+    int     ParseOwner(const vector<PARAM_VALUE> & moduleParams, const string & owner, uid_t * uid);
+    int     ParseGroup(const vector<PARAM_VALUE> & moduleParams, const string & group, uid_t * uid);
+    int     ParseMode(const vector<PARAM_VALUE> & moduleParams, const string & modeStr, mode_t * mode);
+    int     ParseYesNo(const string & value, bool * val);
+    string  errorStr;
+
+    string  workDir;
+    string  usersDir;
+    string  adminsDir;
+    string  tariffsDir;
+
+    mode_t  statMode;
+    uid_t   statUID;
+    gid_t   statGID;
+
+    mode_t  confMode;
+    uid_t   confUID;
+    gid_t   confGID;
+
+    mode_t  userLogMode;
+    uid_t   userLogUID;
+    gid_t   userLogGID;
+
+    bool    removeBak;
+    bool    readBak;
+};
+//-----------------------------------------------------------------------------
+class FILES_STORE: public BASE_STORE
+{
+public:
+    FILES_STORE();
+    virtual ~FILES_STORE();
+    virtual const string & GetStrError() const;
+
+    //User
+    virtual int GetUsersList(vector<string> * usersList) const;
+    virtual int AddUser(const string & login) const;
+    virtual int DelUser(const string & login) const;
+    virtual int SaveUserStat(const USER_STAT & stat, const string & login) const;
+    virtual int SaveUserConf(const USER_CONF & conf, const string & login) const;
+
+    virtual int RestoreUserStat(USER_STAT * stat, const string & login) const;
+    virtual int RestoreUserConf(USER_CONF * conf, const string & login) const;
+
+    virtual int WriteUserChgLog(const string & login,
+                                const string & admLogin,
+                                uint32_t       admIP,
+                                const string & paramName,
+                                const string & oldValue,
+                                const string & newValue,
+                                const string & message = "") const;
+    virtual int WriteUserConnect(const string & login, uint32_t ip) const;
+    virtual int WriteUserDisconnect(const string & login,
+                                    const DIR_TRAFF & up,
+                                    const DIR_TRAFF & down,
+                                    const DIR_TRAFF & sessionUp,
+                                    const DIR_TRAFF & sessionDown,
+                                    double cash,
+                                    double freeMb,
+                                    const std::string & reason) const;
+
+    virtual int WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                  time_t lastStat,
+                                  const string & login) const;
+
+    virtual int AddMessage(STG_MSG * msg, const string & login) const;
+    virtual int EditMessage(const STG_MSG & msg, const string & login) const;
+    virtual int GetMessage(uint64_t id, STG_MSG * msg, const string & login) const;
+    virtual int DelMessage(uint64_t id, const string & login) const;
+    virtual int GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const;
+    virtual int ReadMessage(const string & fileName,
+                            STG_MSG_HDR * hdr,
+                            string * text) const;
+
+    virtual int SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const;
+
+    //Admin
+    virtual int GetAdminsList(vector<string> * adminsList) const;
+    virtual int AddAdmin(const string & login) const;
+    virtual int DelAdmin(const string & login) const;
+    virtual int RestoreAdmin(ADMIN_CONF * ac, const string & login) const;
+    virtual int SaveAdmin(const ADMIN_CONF & ac) const;
+
+    //Tariff
+    virtual int GetTariffsList(vector<string> * tariffsList) const;
+    virtual int AddTariff(const string & name) const;
+    virtual int DelTariff(const string & name) const;
+    virtual int SaveTariff(const TARIFF_DATA & td, const string & tariffName) const;
+    virtual int RestoreTariff(TARIFF_DATA * td, const string & tariffName) const;
+
+    //Corparation
+    virtual int GetCorpsList(vector<string> *) const {return 0;};
+    virtual int SaveCorp(const CORP_CONF &) const {return 0;};
+    virtual int RestoreCorp(CORP_CONF *, const string &) const {return 0;};
+    virtual int AddCorp(const string &) const {return 0;};
+    virtual int DelCorp(const string &) const {return 0;};
+
+    // Services
+    virtual int GetServicesList(vector<string> *) const {return 0;};
+    virtual int SaveService(const SERVICE_CONF &) const {return 0;};
+    virtual int RestoreService(SERVICE_CONF *, const string &) const {return 0;};
+    virtual int AddService(const string &) const {return 0;};
+    virtual int DelService(const string &) const {return 0;};
+
+    //virtual BASE_SETTINGS * GetStoreSettings();
+    virtual void            SetSettings(const MODULE_SETTINGS & s);
+    virtual int             ParseSettings();
+    virtual const string &  GetVersion() const;
+
+private:
+    virtual int RestoreUserStat(USER_STAT * stat, const string & login, const string & fileName) const;
+    virtual int RestoreUserConf(USER_CONF * conf, const string & login, const string & fileName) const;
+
+    virtual int WriteLogString(const string & str, const string & login) const;
+    virtual int WriteLog2String(const string & str, const string & login) const;
+    int     RemoveDir(const char * path) const;
+    int     GetFilesList(vector<string> * filesList, const string & directory, mode_t mode, const string & ext) const;
+    mutable string          errorStr;
+    string                  version;
+    FILES_STORE_SETTINGS    storeSettings;
+    MODULE_SETTINGS         settings;
+    mutable pthread_mutex_t mutex;
+};
+//-----------------------------------------------------------------------------
+
+#endif //FILE_STORE_H
+
diff --git a/projects/stargazer/plugins/store/firebird/Makefile b/projects/stargazer/plugins/store/firebird/Makefile
new file mode 100644 (file)
index 0000000..773d778
--- /dev/null
@@ -0,0 +1,23 @@
+###############################################################################
+# $Id: Makefile,v 1.9 2008/12/04 17:15:53 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+DEFS += -DIBPP_LINUX
+
+PROG = mod_store_firebird.so
+
+SRCS = ./firebird_store.cpp \
+       ./firebird_store_admins.cpp \
+       ./firebird_store_corporations.cpp \
+       ./firebird_store_messages.cpp \
+       ./firebird_store_services.cpp \
+       ./firebird_store_tariffs.cpp \
+       ./firebird_store_users.cpp \
+       ./firebird_store_utils.cpp
+
+STGLIBS = -libpp -lstg_common
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/store/firebird/deps b/projects/stargazer/plugins/store/firebird/deps
new file mode 100644 (file)
index 0000000..5912b31
--- /dev/null
@@ -0,0 +1,180 @@
+firebird_store.o: firebird_store.cpp firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_admins.o: firebird_store_admins.cpp firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/blowfish.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_corporations.o: firebird_store_corporations.cpp \
+ firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_messages.o: firebird_store_messages.cpp firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_services.o: firebird_store_services.cpp firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_tariffs.o: firebird_store_tariffs.cpp firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_users.o: firebird_store_users.cpp \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
+firebird_store_utils.o: firebird_store_utils.cpp firebird_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX -DIBPP_LINUX
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store.cpp b/projects/stargazer/plugins/store/firebird/firebird_store.cpp
new file mode 100644 (file)
index 0000000..c9265e1
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *    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>
+ */
+
+/*
+ *  This file contains a realization of a base firebird-storage plugin class
+ *
+ *  $Revision: 1.18 $
+ *  $Date: 2010/01/08 16:00:45 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+using namespace std;
+
+#include "firebird_store.h"
+#include "ibpp.h"
+
+class FIREBIRD_STORE_CREATOR
+{
+public:
+    FIREBIRD_STORE_CREATOR()
+        : frb(new FIREBIRD_STORE())
+        {
+        };
+    ~FIREBIRD_STORE_CREATOR()
+        {
+        delete frb;
+        };
+    FIREBIRD_STORE * GetStore() { return frb; };
+private:
+    FIREBIRD_STORE * frb;
+} frsc;
+
+//-----------------------------------------------------------------------------
+BASE_STORE * GetStore()
+{
+return frsc.GetStore();
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+FIREBIRD_STORE::FIREBIRD_STORE()
+{
+db_server = "localhost";
+db_database = "/var/stg/stargazer.fdb";
+db_user = "stg";
+db_password = "123456";
+version = "firebird_store v.1.4";
+pthread_mutex_init(&mutex, NULL);
+
+// Advanced settings defaults
+
+til = IBPP::ilConcurrency;
+tlr = IBPP::lrWait;
+}
+//-----------------------------------------------------------------------------
+FIREBIRD_STORE::~FIREBIRD_STORE()
+{
+db->Disconnect();
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::ParseSettings()
+{
+vector<PARAM_VALUE>::iterator i;
+string s;
+
+for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
+    {
+    s = i->param;
+    transform(s.begin(), s.end(), s.begin(), ToLower());
+    if (s == "server")
+        {
+        db_server = *(i->value.begin());
+        }
+    if (s == "database")
+        {
+        db_database = *(i->value.begin());
+        }
+    if (s == "user")
+        {
+        db_user = *(i->value.begin());
+        }
+    if (s == "password")
+        {
+        db_password = *(i->value.begin());
+        }
+
+    // Advanced settings block
+
+    if (s == "isolationLevel")
+        {
+        if (*(i->value.begin()) == "Concurrency")
+            {
+            til = IBPP::ilConcurrency;
+            }
+        else if (*(i->value.begin()) == "DirtyRead")
+            {
+            til = IBPP::ilReadDirty;
+            }
+        else if (*(i->value.begin()) == "ReadCommitted")
+            {
+            til = IBPP::ilReadCommitted;
+            }
+        else if (*(i->value.begin()) == "Consistency")
+            {
+            til = IBPP::ilConsistency;
+            }
+        }
+    if (s == "lockResolution")
+        {
+        if (*(i->value.begin()) == "Wait")
+            {
+            tlr = IBPP::lrWait;
+            }
+        else if (*(i->value.begin()) == "NoWait")
+            {
+            tlr = IBPP::lrNoWait;
+            }
+        }
+    }
+
+try
+    {
+    db = IBPP::DatabaseFactory(db_server, db_database, db_user, db_password, "", "KOI8U", "");
+    db->Connect();
+    }
+catch (IBPP::Exception & ex)
+    {
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store.h b/projects/stargazer/plugins/store/firebird/firebird_store.h
new file mode 100644 (file)
index 0000000..2cc62cf
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Firebird storage class definition
+ *
+ *  $Revision: 1.13 $
+ *  $Date: 2010/01/19 11:07:25 $
+ *
+ */
+
+#ifndef FIREBIRD_STORE_H
+#define FIREBIRD_STORE_H
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "base_store.h"
+#include "stg_locker.h"
+#include "ibpp.h"
+//#include "firebird_database.h"
+
+struct ToLower
+{
+char operator() (char c) const  { return std::tolower(c); }
+};
+
+extern "C" BASE_STORE * GetStore();
+
+class FIREBIRD_STORE : public BASE_STORE {
+public:
+    FIREBIRD_STORE();
+    virtual ~FIREBIRD_STORE();
+
+    int GetUsersList(std::vector<std::string> * usersList) const;
+    int AddUser(const std::string & login) const;
+    int DelUser(const std::string & login) const;
+    int SaveUserStat(const USER_STAT & stat, const std::string & login) const;
+    int SaveUserConf(const USER_CONF & conf, const std::string & login) const;
+    int RestoreUserStat(USER_STAT * stat, const std::string & login) const;
+    int RestoreUserConf(USER_CONF * conf, const std::string & login) const;
+    int WriteUserChgLog(const std::string & login,
+                        const std::string & admLogin,
+                        uint32_t admIP,
+                        const std::string & paramName,
+                        const std::string & oldValue,
+                        const std::string & newValue,
+                        const std::string & message) const;
+    int WriteUserConnect(const std::string & login, uint32_t ip) const;
+    int WriteUserDisconnect(const std::string & login,
+                            const DIR_TRAFF & up,
+                            const DIR_TRAFF & down,
+                            const DIR_TRAFF & sessionUp,
+                            const DIR_TRAFF & sessionDown,
+                            double cash,
+                            double freeMb,
+                            const std::string & reason) const;
+    int WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                          time_t lastStat,
+                          const std::string & login) const;
+
+    int AddMessage(STG_MSG * msg, const std::string & login) const;
+    int EditMessage(const STG_MSG & msg, const std::string & login) const;
+    int GetMessage(uint64_t id, STG_MSG * msg, const std::string & login) const;
+    int DelMessage(uint64_t id, const std::string & login) const;
+    int GetMessageHdrs(std::vector<STG_MSG_HDR> * hdrsList, const std::string & login) const;
+
+    int SaveMonthStat(const USER_STAT & stat, int month, int year, const std::string  & login) const;
+
+    int GetAdminsList(std::vector<std::string> * adminsList) const;
+    int SaveAdmin(const ADMIN_CONF & ac) const;
+    int RestoreAdmin(ADMIN_CONF * ac, const std::string & login) const;
+    int AddAdmin(const std::string & login) const;
+    int DelAdmin(const std::string & login) const;
+
+    int GetTariffsList(std::vector<std::string> * tariffsList) const;
+    int AddTariff(const std::string & name) const;
+    int DelTariff(const string & name) const;
+    int SaveTariff(const TARIFF_DATA & td, const std::string & tariffName) const;
+    int RestoreTariff(TARIFF_DATA * td, const std::string & tariffName) const;
+
+    int GetCorpsList(std::vector<std::string> * corpsList) const;
+    int SaveCorp(const CORP_CONF & cc) const;
+    int RestoreCorp(CORP_CONF * cc, const std::string & name) const;
+    int AddCorp(const std::string & name) const;
+    int DelCorp(const std::string & name) const;
+
+    inline void SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int ParseSettings();
+
+    inline const string & GetStrError() const { return strError; };
+
+    inline const string & GetVersion() const { return version; };
+
+    int GetServicesList(std::vector<std::string> * servicesList) const;
+    int SaveService(const SERVICE_CONF & sc) const;
+    int RestoreService(SERVICE_CONF * sc, const std::string & name) const;
+    int AddService(const std::string & name) const;
+    int DelService(const std::string & name) const;
+private:
+    std::string version;
+    mutable std::string strError;
+    mutable std::string db_server, db_database, db_user, db_password;
+    MODULE_SETTINGS settings;
+    mutable IBPP::Database db;
+    mutable pthread_mutex_t mutex;
+    mutable IBPP::TIL til;
+    mutable IBPP::TLR tlr;
+
+    int SaveStat(const USER_STAT & stat, const std::string & login, int year = 0, int month = 0) const;
+
+    time_t ts2time_t(const IBPP::Timestamp & ts) const;
+    void time_t2ts(time_t t, IBPP::Timestamp * ts) const;
+    void ym2date(int year, int month, IBPP::Date * date) const;
+};
+
+#endif //FIREBIRD_STORE_H
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_admins.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_admins.cpp
new file mode 100644 (file)
index 0000000..9838348
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Administrators manipulation methods
+ *
+ *  $Revision: 1.11 $
+ *  $Date: 2008/12/04 17:10:06 $
+ *
+ */
+
+#include <string>
+#include <vector>
+
+using namespace std;
+
+#include "firebird_store.h"
+#include "ibpp.h"
+#include "blowfish.h"
+
+#define adm_enc_passwd "cjeifY8m3"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetAdminsList(vector<string> * adminsList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+string login;
+
+try
+    {
+    tr->Start();
+    st->Execute("select login from tb_admins");
+    while (st->Fetch())
+        {
+        st->Get(1, login);
+        adminsList->push_back(login);
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveAdmin(const ADMIN_CONF & ac) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+char encodedPass[2 * ADM_PASSWD_LEN + 2];
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+memset(cryptedPass, 0, ADM_PASSWD_LEN + 1);
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+EnDecodeInit(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+    EncodeString(cryptedPass + 8 * i, adminPass + 8 * i, &ctx);
+
+cryptedPass[ADM_PASSWD_LEN] = 0;
+Encode12(encodedPass, cryptedPass, ADM_PASSWD_LEN);
+
+try
+    {
+    tr->Start();
+    st->Prepare("update tb_admins set passwd=?, \
+               chg_conf=?, \
+               chg_password=?, \
+               chg_stat=?, \
+               chg_cash=?, \
+               usr_add_del=?, \
+               chg_tariff=?, \
+               chg_admin=? \
+               where login=?");
+    st->Set(1, encodedPass);
+    st->Set(2, static_cast<int16_t>(ac.priv.userConf));
+    st->Set(3, static_cast<int16_t>(ac.priv.userPasswd));
+    st->Set(4, static_cast<int16_t>(ac.priv.userStat));
+    st->Set(5, static_cast<int16_t>(ac.priv.userCash));
+    st->Set(6, static_cast<int16_t>(ac.priv.userAddDel));
+    st->Set(7, static_cast<int16_t>(ac.priv.tariffChg));
+    st->Set(8, static_cast<int16_t>(ac.priv.adminChg));
+    st->Set(9, ac.login);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreAdmin(ADMIN_CONF * ac, const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select * from tb_admins where login = ?");
+    st->Set(1, login);
+    st->Execute();
+    if (st->Fetch())
+        {
+        st->Get(2, ac->login);
+        st->Get(3, ac->password);
+        st->Get(4, (int16_t &)ac->priv.userConf);
+        st->Get(5, (int16_t &)ac->priv.userPasswd);
+        st->Get(6, (int16_t &)ac->priv.userStat);
+        st->Get(7, (int16_t &)ac->priv.userCash);
+        st->Get(8, (int16_t &)ac->priv.userAddDel);
+        st->Get(9, (int16_t &)ac->priv.tariffChg);
+        st->Get(10, (int16_t &)ac->priv.adminChg);
+        }
+    else
+        {
+        strError = "Admin \"" + login + "\" not found in database";
+    printfd(__FILE__, "Admin '%s' not found in database\n", login.c_str());
+    tr->Rollback();
+        return -1;
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+if (ac->password == "")
+    {
+    return 0;
+    }
+
+Decode21(cryptedPass, ac->password.c_str());
+EnDecodeInit(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+    {
+    DecodeString(adminPass + 8 * i, cryptedPass + 8 * i, &ctx);
+    }
+ac->password = adminPass;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddAdmin(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("insert into tb_admins(login, \
+                    passwd, \
+                    chg_conf, \
+                    chg_password, \
+                    chg_stat, \
+                    chg_cash, \
+                    usr_add_del, \
+                    chg_tariff, \
+                    chg_admin, \
+                    chg_service, \
+                    chg_corporation) \
+                 values (?, '', 0, 0, 0, 0, 0, 0, 0, 0, 0)");
+    st->Set(1, login);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelAdmin(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("delete from tb_admins where login = ?");
+    st->Set(1, login);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_corporations.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_corporations.cpp
new file mode 100644 (file)
index 0000000..71e75cb
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Corporations manipulation methods
+ *
+ *  $Revision: 1.5 $
+ *  $Date: 2007/12/23 13:39:59 $
+ *
+ */
+
+#include "firebird_store.h"
+#include "ibpp.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetCorpsList(vector<string> * corpsList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+string name;
+
+try
+    {
+    tr->Start();
+    st->Execute("select name from tb_corporations");
+    while (st->Fetch())
+        {
+        st->Get(1, name);
+        corpsList->push_back(name);
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveCorp(const CORP_CONF & cc) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Execute("update tb_corporations set cash = ? where name = ?");
+    st->Set(1, cc.cash);
+    st->Set(2, cc.name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreCorp(CORP_CONF * cc, const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("select cash from tb_corporations where name = ?");
+    st->Set(1, name);
+    st->Execute();
+    if (st->Fetch())
+        {
+        st->Get(1, cc->cash);
+        }
+    else
+        {
+        strError = "Corporation \"" + name + "\" not found in database";
+        tr->Rollback();
+    printfd(__FILE__, "Corporation '%s' not found in database\n", name.c_str());
+        return -1;
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddCorp(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("insert into tb_corporations (name, cash), values (?, 0)");
+    st->Set(1, name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelCorp(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("delete from tb_corporations where name = ?");
+    st->Set(1, name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_messages.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_messages.cpp
new file mode 100644 (file)
index 0000000..53805eb
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *    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>
+ */
+
+
+/*
+ *  Messages manipualtion methods
+ *
+ *  $Revision: 1.10 $
+ *  $Date: 2009/03/03 16:16:23 $
+ *
+ */
+
+#include <sstream>
+
+#include "firebird_store.h"
+#include "ibpp.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddMessage(STG_MSG * msg, const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_add_message(NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+    st->Set(1, login);
+    st->Set(2, (int32_t)msg->header.ver);
+    st->Set(3, (int32_t)msg->header.type);
+    st->Set(4, (int32_t)msg->header.lastSendTime);
+    st->Set(5, (int32_t)msg->header.creationTime);
+    st->Set(6, (int32_t)msg->header.showTime);
+    st->Set(7, msg->header.repeat);
+    st->Set(8, (int32_t)msg->header.repeatPeriod);
+    st->Set(9, msg->text);
+    st->Execute();
+    st->Get(1, (int64_t &)msg->header.id);
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::EditMessage(const STG_MSG & msg,
+                                const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_add_message(?, ?, ?, ?, ?, ?, ?, ?, ?)");
+    st->Set(1, (int64_t)msg.header.id);
+    st->Set(2, login);
+    st->Set(3, (int32_t)msg.header.ver);
+    st->Set(4, (int32_t)msg.header.type);
+    st->Set(5, (int32_t)msg.header.lastSendTime);
+    st->Set(6, (int32_t)msg.header.creationTime);
+    st->Set(7, (int32_t)msg.header.showTime);
+    st->Set(8, msg.header.repeat);
+    st->Set(9, (int32_t)msg.header.repeatPeriod);
+    st->Set(10, msg.text.c_str());
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetMessage(uint64_t id,
+                               STG_MSG * msg,
+                               const string &) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("select * from tb_messages where pk_message = ?");
+    st->Set(1, (int64_t)id);
+    st->Execute();
+    if (st->Fetch())
+        {
+        st->Get(1, (int64_t &)msg->header.id);
+        st->Get(3, (int32_t &)msg->header.ver);
+        st->Get(4, (int32_t &)msg->header.type);
+        st->Get(5, (int32_t &)msg->header.lastSendTime);
+        st->Get(6, (int32_t &)msg->header.creationTime);
+        st->Get(7, (int32_t &)msg->header.showTime);
+        st->Get(8, msg->header.repeat);
+        st->Get(9, (int32_t &)msg->header.repeatPeriod);
+        st->Get(10, msg->text);
+        }
+    else
+        {
+        strprintf(&strError, "Message with id = %d not found in database", id);
+    printfd(__FILE__, "Message with id - %d not found in database\n", id);
+        tr->Rollback();
+        return -1;
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelMessage(uint64_t id, const string &) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("delete from tb_messages where pk_message = ?");
+    st->Set(1, (int64_t)id);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList,
+                                   const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+STG_MSG_HDR header;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select pk_message, ver, msg_type, \
+                        last_send_time, creation_time, \
+            show_time, repeat, repeat_period \
+         from tb_messages where \
+                fk_user = (select pk_user from tb_users where name = ?)");
+    st->Set(1, login);
+    st->Execute();
+    while (st->Fetch())
+        {
+        st->Get(1, (int64_t &)header.id);
+        st->Get(2, (int32_t &)header.ver);
+        st->Get(3, (int32_t &)header.type);
+        st->Get(4, (int32_t &)header.lastSendTime);
+        st->Get(5, (int32_t &)header.creationTime);
+        st->Get(6, (int32_t &)header.showTime);
+        st->Get(7, header.repeat);
+        st->Get(8, (int32_t &)header.repeatPeriod);
+        hdrsList->push_back(header);
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_services.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_services.cpp
new file mode 100644 (file)
index 0000000..01a460e
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *    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>
+ */
+
+
+/*
+ *  Services manipulation methods
+ *
+ *  $Revision: 1.6 $
+ *  $Date: 2009/05/13 13:19:33 $
+ *
+ */
+
+#include "firebird_store.h"
+#include "ibpp.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetServicesList(vector<string> * servicesList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+string name;
+
+try
+    {
+    tr->Start();
+    st->Execute("select name from tb_services");
+    while (st->Fetch())
+        {
+        st->Get(1, name);
+        servicesList->push_back(name);
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveService(const SERVICE_CONF & sc) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("update tb_services set \
+            comments = ?, \
+            cost = ?, \
+            pay_day = ? \
+         where name = ?");
+    st->Set(1, sc.comment);
+    st->Set(2, sc.cost);
+    st->Set(3, sc.payDay);
+    st->Set(4, sc.name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreService(SERVICE_CONF * sc,
+                                   const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("select * from tb_services where name = ?");
+    st->Set(1, name);
+    st->Execute();
+    if (st->Fetch())
+        {
+        st->Get(3, sc->comment);
+        st->Get(4, sc->cost);
+        st->Get(5, sc->payDay);
+        }
+    else
+        {
+        strError = "Service \"" + name + "\" not found in database";
+    printfd(__FILE__, "Service '%s' not found in database\n", name.c_str());
+        tr->Rollback();
+        return -1;
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddService(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("insert into tb_services (name, comment, cost, pay_day) \
+            values (?, '', 0, 0)");
+    st->Set(1, name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelService(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_delete_service(?)");
+    st->Set(1, name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp
new file mode 100644 (file)
index 0000000..eaba5b5
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Tariffs manipulation methods
+ *
+ *  $Revision: 1.5 $
+ *  $Date: 2007/12/23 13:39:59 $
+ *
+ */
+
+#include "firebird_store.h"
+#include "ibpp.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetTariffsList(vector<string> * tariffsList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+string name;
+
+try
+    {
+    tr->Start();
+    st->Execute("select name from tb_tariffs");
+    while (st->Fetch())
+        {
+        st->Get(1, name);
+        tariffsList->push_back(name);
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddTariff(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_add_tariff(?, ?)");
+    st->Set(1, name);
+    st->Set(2, DIR_NUM);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelTariff(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_delete_tariff(?)");
+    st->Set(1, name);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveTariff(const TARIFF_DATA & td,
+                               const string & tariffName) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+int32_t id, i;
+double pda, pdb, pna, pnb;
+int threshold;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select pk_tariff from tb_tariffs where name = ?");
+    st->Set(1, tariffName);
+    st->Execute();
+    if (!st->Fetch())
+    {
+    tr->Rollback();
+    strprintf(&strError, "Tariff \"%s\" not found in database", tariffName.c_str());
+    printfd(__FILE__, "Tariff '%s' not found in database\n", tariffName.c_str());
+    return -1;
+    }
+    st->Get(1, id);
+    st->Close();
+    st->Prepare("update tb_tariffs set \
+            fee = ?, \
+            free = ?, \
+            passive_cost = ?, \
+            traff_type = ? \
+            where pk_tariff = ?");
+    st->Set(1, td.tariffConf.fee);
+    st->Set(2, td.tariffConf.free);
+    st->Set(3, td.tariffConf.passiveCost);
+    st->Set(4, td.tariffConf.traffType);
+    st->Set(5, id);
+    st->Execute();
+    st->Close();
+
+    IBPP::Time tb;
+    IBPP::Time te;
+
+    for(i = 0; i < DIR_NUM; i++)
+        {
+
+    tb.SetTime(td.dirPrice[i].hDay, td.dirPrice[i].mDay, 0);
+    te.SetTime(td.dirPrice[i].hNight, td.dirPrice[i].mNight, 0);
+
+        pda = td.dirPrice[i].priceDayA * 1024 * 1024;
+        pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
+
+        if (td.dirPrice[i].singlePrice)
+            {
+            pna = pda;
+            pnb = pdb;
+            }
+        else
+            {
+            pna = td.dirPrice[i].priceNightA;
+            pnb = td.dirPrice[i].priceNightB;
+            }
+
+        if (td.dirPrice[i].noDiscount)
+            {
+            threshold = 0xffFFffFF;
+            }
+        else
+            {
+            threshold = td.dirPrice[i].threshold;
+            }
+
+    st->Prepare("update tb_tariffs_params set \
+            price_day_a = ?, \
+            price_day_b = ?, \
+            price_night_a = ?, \
+            price_night_b = ?, \
+            threshold = ?, \
+            time_day_begins = ?, \
+            time_day_ends = ? \
+             where fk_tariff = ? and dir_num = ?");
+    st->Set(1, pda);
+    st->Set(2, pdb);
+    st->Set(3, pna);
+    st->Set(4, pnb);
+    st->Set(5, threshold);
+    st->Set(6, tb);
+    st->Set(7, te);
+    st->Set(8, id);
+    st->Set(9, i);
+    st->Execute();
+    st->Close();
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreTariff(TARIFF_DATA * td,
+                                  const string & tariffName) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+int32_t id;
+int16_t dir;
+int i;
+IBPP::Time tb, te;
+int h, m, s;
+
+td->tariffConf.name = tariffName;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select * from tb_tariffs where name = ?");
+    st->Set(1, tariffName);
+    st->Execute();
+    if (!st->Fetch())
+        {
+        strError = "Tariff \"" + tariffName + "\" not found in database";
+    printfd(__FILE__, "Tariff '%s' not found in database\n", tariffName.c_str());
+        tr->Rollback();
+        return -1;
+        }
+    st->Get(1, id);
+    st->Get(3, td->tariffConf.fee);
+    st->Get(4, td->tariffConf.free);
+    st->Get(5, td->tariffConf.passiveCost);
+    st->Get(6, td->tariffConf.traffType);
+    st->Close();
+    st->Prepare("select * from tb_tariffs_params where fk_tariff = ?");
+    st->Set(1, id);
+    st->Execute();
+    i = 0;
+    while (st->Fetch())
+    {
+    i++;
+    if (i > DIR_NUM)
+        {
+        strError = "Too mach params for tariff \"" + tariffName + "\"";
+        printfd(__FILE__, "Too mach params for tariff '%s'\n", tariffName.c_str());
+        tr->Rollback();
+        return -1;
+        }
+    st->Get(3, dir);
+    st->Get(4, td->dirPrice[dir].priceDayA);
+    td->dirPrice[dir].priceDayA /= 1024*1024;
+    st->Get(5, td->dirPrice[dir].priceDayB);
+    td->dirPrice[dir].priceDayB /= 1024*1024;
+    st->Get(6, td->dirPrice[dir].priceNightA);
+    td->dirPrice[dir].priceNightA /= 1024*1024;
+    st->Get(7, td->dirPrice[dir].priceNightB);
+    td->dirPrice[dir].priceNightB /= 1024*1024;
+    st->Get(8, td->dirPrice[dir].threshold);
+    if (td->dirPrice[dir].priceDayA == td->dirPrice[dir].priceNightA &&
+        td->dirPrice[dir].priceDayB == td->dirPrice[dir].priceNightB)
+        {
+        td->dirPrice[dir].singlePrice = true;
+        }
+    else
+        {
+        td->dirPrice[dir].singlePrice = false;
+        }
+    if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
+        {
+        td->dirPrice[dir].noDiscount = true;
+        }
+    else
+        {
+
+        td->dirPrice[dir].noDiscount = false;
+        }
+    st->Get(9, tb);
+    st->Get(10, te);
+    tb.GetTime(h, m, s);
+    td->dirPrice[dir].hDay = h;
+    td->dirPrice[dir].mDay = m;
+    te.GetTime(h, m, s);
+    td->dirPrice[dir].hNight = h;
+    td->dirPrice[dir].mNight = m;
+    }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_users.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_users.cpp
new file mode 100644 (file)
index 0000000..035ae13
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ *    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>
+ */
+
+/*
+ *  User manipulation methods
+ *
+ *  $Revision: 1.19 $
+ *  $Date: 2010/01/19 11:07:25 $
+ *
+ */
+
+#include "stg_const.h"
+#include "firebird_store.h"
+#include "ibpp.h"
+
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::GetUsersList(vector<string> * usersList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+string name;
+
+try
+    {
+    tr->Start();
+    st->Execute("select name from tb_users");
+    while (st->Fetch())
+        {
+        st->Get(1, name);
+        usersList->push_back(name);
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::AddUser(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_add_user(?, ?)");
+    st->Set(1, name);
+    st->Set(2, DIR_NUM);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::DelUser(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_delete_user(?)");
+    st->Set(1, login);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveUserStat(const USER_STAT & stat,
+                                 const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+return SaveStat(stat, login);
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveStat(const USER_STAT & stat,
+                                 const string & login,
+                                 int year,
+                                 int month) const
+{
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+IBPP::Timestamp actTime;
+IBPP::Timestamp addTime;
+IBPP::Date dt;
+int i;
+int32_t sid, uid;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select pk_user from tb_users where name = ?");
+    st->Set(1, login);
+    st->Execute();
+    if (!st->Fetch())
+    {
+    strError = "User \"" + login + "\" not found in database";
+    printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
+    tr->Rollback();
+    return -1;
+    }
+    st->Get(1, uid);
+    st->Close();
+    st->Prepare("select first 1 pk_stat from tb_stats where fk_user = ? order by stats_date desc");
+    st->Set(1, uid);
+    st->Execute();
+    if (!st->Fetch())
+    {
+    tr->Rollback();
+    strError = "No stat info for user \"" + login + "\"";
+    printfd(__FILE__, "No stat info for user '%s'\n", login.c_str());
+    return -1;
+    }
+    st->Get(1, sid);
+    st->Close();
+
+    time_t2ts(stat.lastActivityTime, &actTime);
+    time_t2ts(stat.lastCashAddTime, &addTime);
+    if (year != 0)
+        ym2date(year, month, &dt);
+    else
+        dt.Today();
+
+    st->Prepare("update tb_stats set \
+                    cash = ?, \
+                    free_mb = ?, \
+                    last_activity_time = ?, \
+                    last_cash_add = ?, \
+                    last_cash_add_time = ?, \
+                    passive_time = ?, \
+                    stats_date = ? \
+                 where pk_stat = ?");
+
+    st->Set(1, stat.cash);
+    st->Set(2, stat.freeMb);
+    st->Set(3, actTime);
+    st->Set(4, stat.lastCashAdd);
+    st->Set(5, addTime);
+    st->Set(6, (int32_t)stat.passiveTime);
+    st->Set(7, dt);
+    st->Set(8, sid);
+
+    st->Execute();
+    st->Close();
+
+    for(i = 0; i < DIR_NUM; i++)
+        {
+        st->Prepare("update tb_stats_traffic set \
+                        upload = ?, \
+                        download = ? \
+                     where fk_stat = ? and dir_num = ?");
+        st->Set(1, (int64_t)stat.up[i]);
+        st->Set(2, (int64_t)stat.down[i]);
+        st->Set(3, sid);
+        st->Set(4, i);
+        st->Execute();
+        st->Close();
+        }
+
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveUserConf(const USER_CONF & conf,
+                                 const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+int i;
+int32_t uid;
+IBPP::Timestamp creditExpire;
+vector<string>::const_iterator it;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select pk_user from tb_users where name = ?");
+    st->Set(1, login);
+    st->Execute();
+    if (!st->Fetch())
+        {
+        strError = "User \"" + login + "\" not found in database";
+        printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
+        tr->Rollback();
+        return -1;
+        }
+    st->Get(1, uid);
+    st->Close();
+
+    time_t2ts(conf.creditExpire, &creditExpire);
+
+    st->Prepare("update tb_users set \
+                    address = ?, \
+                    always_online = ?, \
+                    credit = ?, \
+                    credit_expire = ?, \
+                    disabled = ?, \
+                    disabled_detail_stat = ?, \
+                    email = ?, \
+                    grp = ?, \
+                    note = ?, \
+                    passive = ?, \
+                    passwd = ?, \
+                    phone = ?, \
+                    fk_tariff = (select pk_tariff from tb_tariffs \
+                                 where name = ?), \
+                    fk_tariff_change = (select pk_tariff from tb_tariffs \
+                                        where name = ?), \
+                    fk_corporation = (select pk_corporation from tb_corporations \
+                                      where name = ?), \
+                    real_name = ? \
+                 where pk_user = ?");
+
+    st->Set(1, conf.address);
+    st->Set(2, (bool)conf.alwaysOnline);
+    st->Set(3, conf.credit);
+    st->Set(4, creditExpire);
+    st->Set(5, (bool)conf.disabled);
+    st->Set(6, (bool)conf.disabledDetailStat);
+    st->Set(7, conf.email);
+    st->Set(8, conf.group);
+    st->Set(9, conf.note);
+    st->Set(10, (bool)conf.passive);
+    st->Set(11, conf.password);
+    st->Set(12, conf.phone);
+    st->Set(13, conf.tariffName);
+    st->Set(14, conf.nextTariff);
+    st->Set(15, conf.corp);
+    st->Set(16, conf.realName);
+    st->Set(17, uid);
+
+    st->Execute();
+    st->Close();
+
+    st->Prepare("delete from tb_users_services where fk_user = ?");
+    st->Set(1, uid);
+    st->Execute();
+    st->Close();
+
+    st->Prepare("insert into tb_users_services (fk_user, fk_service) \
+                    values (?, (select pk_service from tb_services \
+                                where name = ?))");
+    for(it = conf.service.begin(); it != conf.service.end(); ++it)
+        {
+        st->Set(1, uid);
+        st->Set(2, *it);
+        st->Execute();
+        }
+    st->Close();
+
+    st->Prepare("delete from tb_users_data where fk_user = ?");
+    st->Set(1, uid);
+    st->Execute();
+    st->Close();
+
+    i = 0;
+    st->Prepare("insert into tb_users_data (fk_user, data, num) values (?, ?, ?)");
+    for (it = conf.userdata.begin(); it != conf.userdata.end(); ++it)
+        {
+        st->Set(1, uid);
+        st->Set(2, *it);
+        st->Set(3, i++);
+        st->Execute();
+        }
+    st->Close();
+
+    st->Prepare("delete from tb_allowed_ip where fk_user = ?");
+    st->Set(1, uid);
+    st->Execute();
+
+    st->Prepare("insert into tb_allowed_ip (fk_user, ip, mask) values (?, ?, ?)");
+    for(i = 0; i < conf.ips.Count(); i++)
+        {
+        st->Set(1, uid);
+        st->Set(2, (int32_t)conf.ips[i].ip);
+        st->Set(3, (int32_t)conf.ips[i].mask);
+        st->Execute();
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreUserStat(USER_STAT * stat,
+                                    const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+IBPP::Timestamp actTime, addTime;
+int i, dir;
+int32_t uid, sid, passiveTime;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select pk_user from tb_users where name = ?");
+    st->Set(1, login);
+    st->Execute();
+    if (!st->Fetch())
+        {
+        strError = "User \"" + login + "\" not found in database";
+        printfd(__FILE__, "User '%s' not found in database\n", login.c_str());
+        return -1;
+        }
+    st->Get(1, uid);
+    st->Close();
+
+    st->Prepare("select first 1 pk_stat, cash, free_mb, last_activity_time, \
+                    last_cash_add, last_cash_add_time, passive_time from tb_stats \
+                 where fk_user = ? order by stats_date desc");
+    st->Set(1, uid);
+    st->Execute();
+    if (!st->Fetch())
+        {
+        strError = "No stat info for user \"" + login + "\"";
+        printfd(__FILE__, "No stat info for user '%s'\n", login.c_str());
+        tr->Rollback();
+        return -1;
+        }
+
+    st->Get(1, sid);
+    st->Get(2, stat->cash);
+    st->Get(3, stat->freeMb);
+    st->Get(4, actTime);
+    st->Get(5, stat->lastCashAdd);
+    st->Get(6, addTime);
+    st->Get(7, passiveTime);
+
+    stat->passiveTime = passiveTime;
+
+    stat->lastActivityTime = ts2time_t(actTime);
+
+    stat->lastCashAddTime = ts2time_t(addTime);
+
+    st->Close();
+    st->Prepare("select * from tb_stats_traffic where fk_stat = ?");
+    st->Set(1, sid);
+    st->Execute();
+    for(i = 0; i < DIR_NUM; i++)
+        {
+        if (st->Fetch())
+            {
+            st->Get(3, dir);
+            st->Get(5, (int64_t &)stat->up[dir]);
+            st->Get(4, (int64_t &)stat->down[dir]);
+            }
+        else
+            {
+            break;
+            }
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::RestoreUserConf(USER_CONF * conf,
+                                    const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amRead, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+int32_t uid;
+int i;
+IBPP::Timestamp timestamp;
+IP_MASK im;
+string name;
+bool test;
+
+try
+    {
+    tr->Start();
+    st->Prepare("select tb_users.pk_user, tb_users.address, tb_users.always_online, \
+                        tb_users.credit, tb_users.credit_expire, tb_users.disabled, \
+                        tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, \
+                        tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, \
+                        tb_users.real_name, tf1.name, tf2.name, tb_corporations.name \
+                 from tb_users left join tb_tariffs tf1 \
+                 on tf1.pk_tariff = tb_users.fk_tariff \
+                 left join tb_tariffs tf2 \
+                 on tf2.pk_tariff = tb_users.fk_tariff_change \
+                 left join tb_corporations \
+                 on tb_corporations.pk_corporation = tb_users.fk_corporation \
+                 where tb_users.name = ?");
+    st->Set(1, login);
+    st->Execute();
+    if (!st->Fetch())
+        {
+        strError = "User \"" + login + "\" not found in database";
+    printfd(__FILE__, "User '%s' not found in database", login.c_str());
+        tr->Rollback();
+        return -1;
+        }
+    st->Get(1, uid);
+    // Getting base config
+    st->Get(2, conf->address);
+    st->Get(3, test);
+    conf->alwaysOnline = test;
+    st->Get(4, conf->credit);
+    st->Get(5, timestamp);
+
+    conf->creditExpire = ts2time_t(timestamp);
+
+    st->Get(6, test);
+    conf->disabled = test;
+    st->Get(7, test);
+    conf->disabledDetailStat = test;
+    st->Get(8, conf->email);
+    st->Get(9, conf->group);
+    st->Get(10, conf->note);
+    st->Get(11, test);
+    conf->passive = test;
+    st->Get(12, conf->password);
+    st->Get(13, conf->phone);
+    st->Get(14, conf->realName);
+    st->Get(15, conf->tariffName);
+    st->Get(16, conf->nextTariff);
+    st->Get(17, conf->corp);
+
+    if (conf->tariffName == "")
+        conf->tariffName = NO_TARIFF_NAME;
+    if (conf->corp == "")
+        conf->corp = NO_CORP_NAME;
+
+    // Services
+    st->Close();
+    st->Prepare("select name from tb_services \
+                 where pk_service in \
+                    (select fk_service from tb_users_services \
+                     where fk_user = ?)");
+    st->Set(1, uid);
+    st->Execute();
+    while (st->Fetch())
+        {
+        st->Get(1, name);
+        conf->service.push_back(name);
+        }
+
+    // User data
+    st->Close();
+    st->Prepare("select data, num from tb_users_data where fk_user = ? order by num");
+    st->Set(1, uid);
+    st->Execute();
+    while (st->Fetch())
+        {
+        st->Get(2, i);
+        st->Get(1, conf->userdata[i]);
+        }
+
+    // User IPs
+    st->Close();
+    st->Prepare("select ip, mask from tb_allowed_ip \
+                 where fk_user = ?");
+    st->Set(1, uid);
+    st->Execute();
+    conf->ips.Erase();
+    while (st->Fetch())
+        {
+        st->Get(1, (int32_t &)im.ip);
+        st->Get(2, (int32_t &)im.mask);
+        conf->ips.Add(im);
+        }
+
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteUserChgLog(const string & login,
+                                    const string & admLogin,
+                                    uint32_t admIP,
+                                    const string & paramName,
+                                    const string & oldValue,
+                                    const string & newValue,
+                                    const string & message = "") const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+IBPP::Timestamp now;
+now.Now();
+
+string temp = ""; // Composed message for log
+
+try
+    {
+    tr->Start();
+    temp += "Admin \"" + admLogin + "\", ";
+    temp += inet_ntostring(admIP);
+    temp += ": ";
+    temp = temp + message;
+    //----------------------------------------------------------------------------------------
+    // Checking and inserting parameters in params table
+    st->Prepare("select pk_parameter from tb_parameters where name = ?");
+    st->Set(1, paramName);
+    st->Execute();
+    if (!st->Fetch())
+        {
+        st->Close();
+        st->Prepare("insert into tb_parameters (name) values (?)");
+        st->Set(1, paramName);
+        st->Execute();
+        }
+    st->Close();
+    //----------------------------------------------------------------------------------------
+    st->Prepare("insert into tb_params_log \
+                    (fk_user, fk_parameter, event_time, from_val, to_val, comment) \
+                 values ((select pk_user from tb_users \
+                          where name = ?), \
+                         (select pk_parameter from tb_parameters \
+                          where name = ?), \
+                         ?, ?, ?, ?)");
+    st->Set(1, login);
+    st->Set(2, paramName);
+    st->Set(3, now);
+    st->Set(4, oldValue);
+    st->Set(5, newValue);
+    st->Set(6, temp);
+    st->Execute();
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteUserConnect(const string & login, uint32_t ip) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+IBPP::Timestamp now;
+now.Now();
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_append_session_log(?, ?, 'c', ?)");
+    st->Set(1, login);
+    st->Set(2, now);
+    st->Set(3, (int32_t)ip);
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteUserDisconnect(const string & login,
+                    const DIR_TRAFF & up,
+                    const DIR_TRAFF & down,
+                    const DIR_TRAFF & sessionUp,
+                    const DIR_TRAFF & sessionDown,
+                    double cash,
+                    double freeMb,
+                    const std::string & reason) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+IBPP::Timestamp now;
+now.Now();
+
+int32_t id;
+int i;
+
+try
+    {
+    tr->Start();
+    st->Prepare("execute procedure sp_append_session_log(?, ?, 'd', 0)");
+    st->Set(1, login);
+    st->Set(2, now);
+    st->Execute();
+    st->Get(1, id);
+    st->Prepare("insert into tb_sessions_data \
+                    (fk_session_log, dir_num, session_upload, \
+                     session_download, month_upload, month_download) \
+                 values (?, ?, ?, ?, ?, ?)");
+    for(i = 0; i < DIR_NUM; i++)
+        {
+        st->Set(1, id);
+        st->Set(2, i);
+        st->Set(3, (int64_t)sessionUp[i]);
+        st->Set(4, (int64_t)sessionDown[i]);
+        st->Set(5, (int64_t)up[i]);
+        st->Set(6, (int64_t)down[i]);
+        st->Execute();
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                      time_t lastStat,
+                                      const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+IBPP::Timestamp statTime, now;
+now.Now();
+
+time_t2ts(lastStat, &statTime);
+
+try
+    {
+    tr->Start();
+    map<IP_DIR_PAIR, STAT_NODE>::const_iterator it;
+    it = statTree->begin();
+    st->Prepare("insert into tb_detail_stats \
+                    (till_time, from_time, fk_user, dir_num, \
+                     ip, download, upload, cost) \
+                 values (?, ?, (select pk_user from tb_users \
+                                where name = ?), \
+                     ?, ?, ?, ?, ?)");
+    while (it != statTree->end())
+        {
+        st->Set(1, now);
+        st->Set(2, statTime);
+        st->Set(3, login);
+        st->Set(4, it->first.dir);
+        st->Set(5, (int32_t)it->first.ip);
+        st->Set(6, (int64_t)it->second.down);
+        st->Set(7, (int64_t)it->second.up);
+        st->Set(8, it->second.cash);
+        st->Execute();
+        ++it;
+        }
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int FIREBIRD_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+IBPP::Transaction tr = IBPP::TransactionFactory(db, IBPP::amWrite, til, tlr);
+IBPP::Statement st = IBPP::StatementFactory(db, tr);
+
+IBPP::Timestamp now;
+IBPP::Date nowDate;
+nowDate.Today();
+now.Now();
+int32_t id;
+int i;
+
+if (SaveStat(stat, login, year, month))
+    {
+    return -1;
+    }
+
+try
+    {
+    tr->Start();
+
+    st->Prepare("execute procedure sp_add_stat(?, 0, 0, ?, 0, ?, 0, ?)");
+    st->Set(1, login);
+    st->Set(2, now);
+    st->Set(3, now);
+    st->Set(4, nowDate);
+
+    st->Execute();
+    st->Get(1, id);
+    st->Close();
+
+    st->Prepare("insert into tb_stats_traffic \
+                    (fk_stat, dir_num, upload, download) \
+                 values (?, ?, 0, 0)");
+
+    for(i = 0; i < DIR_NUM; i++)
+        {
+        st->Set(1, id);
+        st->Set(2, i);
+        st->Execute();
+        }
+
+    tr->Commit();
+    }
+
+catch (IBPP::Exception & ex)
+    {
+    tr->Rollback();
+    strError = "IBPP exception";
+    printfd(__FILE__, ex.what());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_utils.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_utils.cpp
new file mode 100644 (file)
index 0000000..9f7fe6b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+/*
+ *  Vairous utility methods
+ *
+ *  $Revision: 1.8 $
+ *  $Date: 2010/03/04 12:20:32 $
+ *
+ */
+
+#include <cstdio>
+
+#include "firebird_store.h"
+#include "ibpp.h"
+
+//-----------------------------------------------------------------------------
+time_t FIREBIRD_STORE::ts2time_t(const IBPP::Timestamp & ts) const
+{
+    char buf[32];
+    int year, month, day, hour, min, sec;
+    struct tm time_tm;
+
+    memset(&time_tm, 0, sizeof(time_tm));
+    ts.GetDate(year, month, day);
+    ts.GetTime(hour, min, sec);
+    sprintf(buf, "%d-%d-%d %d:%d:%d", year, month, day, hour, min, sec);
+    stg_strptime(buf, "%Y-%m-%d %H:%M:%S", &time_tm);
+
+    return mktime(&time_tm);
+}
+//-----------------------------------------------------------------------------
+void FIREBIRD_STORE::time_t2ts(time_t t, IBPP::Timestamp * ts) const
+{
+    struct tm res;
+
+    localtime_r(&t, &res); // Reenterable
+
+    *ts = IBPP::Timestamp(res.tm_year + 1900, res.tm_mon + 1, res.tm_mday, res.tm_hour, res.tm_min, res.tm_sec);
+}
+//-----------------------------------------------------------------------------
+void FIREBIRD_STORE::ym2date(int year, int month, IBPP::Date * date) const
+{
+    date->SetDate(year + 1900, month + 1, 1);
+    date->EndOfMonth();
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/firebird/mod_store_firebird.so b/projects/stargazer/plugins/store/firebird/mod_store_firebird.so
new file mode 100755 (executable)
index 0000000..588ec84
Binary files /dev/null and b/projects/stargazer/plugins/store/firebird/mod_store_firebird.so differ
diff --git a/projects/stargazer/plugins/store/mysql/.#mysql_store.cpp.1.3 b/projects/stargazer/plugins/store/mysql/.#mysql_store.cpp.1.3
new file mode 100644 (file)
index 0000000..03b3efb
--- /dev/null
@@ -0,0 +1,2065 @@
+#include <sys/time.h>
+#include <errno.h>
+#include <string>
+
+#include <mysql/mysql.h>
+#include <mysql/errmsg.h>
+
+#include "user_ips.h"
+#include "user_conf.h"
+#include "user_stat.h"
+#include "mysql_store.h"
+#include "blowfish.h"
+
+#define adm_enc_passwd "cjeifY8m3"
+char qbuf[4096];
+
+using namespace std;
+
+const int pt_mega = 1024 * 1024;
+const string badSyms = "'`";
+const char repSym = '\"';
+const int RepitTimes = 3;
+
+int GetInt(const string & str, int * val, int defaultVal)
+{
+    char *res;
+    
+    *val = strtol(str.c_str(), &res, 10);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+int GetDouble(const string & str, double * val, double defaultVal)
+{
+    char *res;
+    
+    *val = strtod(str.c_str(), &res);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+int GetTime(const string & str, time_t * val, time_t defaultVal)
+{
+    char *res;
+    
+    *val = strtol(str.c_str(), &res, 10);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+//-----------------------------------------------------------------------------
+string ReplaceStr(string source, const string symlist, const char chgsym)
+{
+    string::size_type pos=0;
+
+    while( (pos = source.find_first_of(symlist,pos)) != string::npos)
+        source.replace(pos, 1,1, chgsym);
+
+    return source;
+}
+
+int GetULongLongInt(const string & str, uint64_t * val, uint64_t defaultVal)
+{
+    char *res;
+    
+    *val = strtoull(str.c_str(), &res, 10);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+} 
+
+class STORE_CREATOR
+{
+private:
+    BASE_STORE * bs;
+
+public:
+    STORE_CREATOR()
+        {
+        bs = new MYSQL_STORE();
+        };
+    ~STORE_CREATOR()
+        {
+        if (bs)
+            delete bs;
+        };
+
+    BASE_STORE * GetStore()
+    {
+        return bs;
+    };
+};
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//STORE_CREATOR sc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_STORE * GetStore()
+{
+//return sc.GetStore();
+return new MYSQL_STORE();
+}
+//-----------------------------------------------------------------------------
+MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
+{
+}
+//-----------------------------------------------------------------------------
+MYSQL_STORE_SETTINGS::~MYSQL_STORE_SETTINGS()
+{
+
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE_SETTINGS::ParseParam(const vector<PARAM_VALUE> & moduleParams, 
+                        const string & name, string & result)
+{
+PARAM_VALUE pv;
+pv.param = name;
+vector<PARAM_VALUE>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end())
+    {
+    errorStr = "Parameter \'" + name + "\' not found.";
+    return -1;
+    }
+    
+result = pvi->value[0];
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+if (ParseParam(s.moduleParams, "dbuser", dbUser) < 0)
+    return -1;
+if (ParseParam(s.moduleParams, "rootdbpass", dbPass) < 0)
+    return -1;
+if (ParseParam(s.moduleParams, "dbname", dbName) < 0)
+    return -1;
+if (ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & MYSQL_STORE_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBUser() const
+{
+return dbUser;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBPassword() const
+{
+return dbPass;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBHost() const
+{
+return dbHost;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBName() const
+{
+return dbName;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+MYSQL_STORE::MYSQL_STORE()
+{
+version = "mysql_store v.0.67";
+};
+//-----------------------------------------------------------------------------
+MYSQL_STORE::~MYSQL_STORE()
+{    
+};
+//-----------------------------------------------------------------------------
+void MYSQL_STORE::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int    MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
+{
+    int ret,i;
+
+    if( (ret = mysql_query(sock,sQuery)) )
+    {
+        for(i=0; i<RepitTimes; i++)
+        {
+            if( (ret = mysql_query(sock,sQuery)) )
+                ;//need to send error result
+            else
+                return 0;
+        }
+    }
+    
+    return ret;
+}
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::ParseSettings()
+{
+int ret = storeSettings.ParseSettings(settings);
+MYSQL mysql;
+MYSQL * sock;
+mysql_init(&mysql);
+if (ret)
+    errorStr = storeSettings.GetStrError();
+else
+{
+    if(storeSettings.GetDBPassword().length() == 0)
+    {
+        errorStr = "Database password must be not empty. Please read Manual.";
+        return -1;
+    }
+    
+    if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
+            storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
+            0,0,NULL,0)))
+        {
+            errorStr = "Couldn't connect to mysql engine! With error:\n";
+            errorStr += mysql_error(&mysql);
+            mysql_close(sock);
+            ret = -1;
+        }
+    else
+    {
+         if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
+         {
+             string res = "CREATE DATABASE " + storeSettings.GetDBName();
+            
+            if(MysqlQuery(res.c_str(),sock))
+            {
+                errorStr = "Couldn't create database! With error:\n";
+                errorStr += mysql_error(sock);
+                mysql_close(sock);
+                ret = -1;
+            }
+            else
+            {
+                 if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
+                 {
+                    errorStr = "Couldn't select database! With error:\n";
+                    errorStr += mysql_error(sock);
+                    mysql_close(sock);
+                    ret = -1;
+                 }
+                 ret = CheckAllTables(sock);
+            }
+         }
+         else
+             ret = CheckAllTables(sock);
+         mysql_close(sock);
+    }
+    
+}
+return ret;
+}
+//-----------------------------------------------------------------------------
+const string & MYSQL_STORE::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+const string & MYSQL_STORE::GetVersion() const
+{
+return version;
+}
+//-----------------------------------------------------------------------------
+bool MYSQL_STORE::IsTablePresent(const string & str,MYSQL * sock)
+{
+MYSQL_RES* result;
+
+if (!(result=mysql_list_tables(sock,str.c_str() )))
+{
+    errorStr = "Couldn't get tables list With error:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int num_rows =  mysql_num_rows(result);
+
+if(result)
+    mysql_free_result(result);
+
+return (num_rows == 1);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::CheckAllTables(MYSQL * sock)
+{
+//admins-----------------------------------------------------------------------
+if(!IsTablePresent("admins",sock))
+{
+    sprintf(qbuf,"CREATE TABLE admins (login VARCHAR(40) DEFAULT '' PRIMARY KEY,"\
+        "password VARCHAR(150) DEFAULT '*',ChgConf TINYINT DEFAULT 0,"\
+        "ChgPassword TINYINT DEFAULT 0,ChgStat TINYINT DEFAULT 0,"\
+        "ChgCash TINYINT DEFAULT 0,UsrAddDel TINYINT DEFAULT 0,"\
+        "ChgTariff TINYINT DEFAULT 0,ChgAdmin TINYINT DEFAULT 0)");
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create admin table list With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+
+    sprintf(qbuf,"INSERT INTO admins SET login='admin',"\
+        "password='geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa',"\
+        "ChgConf=1,ChgPassword=1,ChgStat=1,ChgCash=1,UsrAddDel=1,ChgTariff=1,ChgAdmin=1");
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create default admin. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+//tariffs-----------------------------------------------------------------------
+string param, res;
+if(!IsTablePresent("tariffs",sock))
+{
+    res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
+        
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " PriceDayA%d DOUBLE DEFAULT 0.0,", i); 
+        res += param;
+    
+        strprintf(&param, " PriceDayB%d DOUBLE DEFAULT 0.0,", i);
+        res += param;
+            
+        strprintf(&param, " PriceNightA%d DOUBLE DEFAULT 0.0,", i);
+        res += param;
+    
+        strprintf(&param, " PriceNightB%d DOUBLE DEFAULT 0.0,", i);
+        res += param;
+            
+        strprintf(&param, " Threshold%d INT DEFAULT 0,", i);
+        res += param;
+    
+        string s;
+        strprintf(&param, " Time%d VARCHAR(15) DEFAULT '0:0-0:0',", i);
+        res += param;
+    
+        strprintf(&param, " NoDiscount%d INT DEFAULT 0,", i);
+        res += param;
+    
+        strprintf(&param, " SinglePrice%d INT DEFAULT 0,", i);
+        res += param;
+        }
+    
+    res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"\
+        "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '')";
+    
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create tariffs table list With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+
+    res = "INSERT INTO tariffs SET name='tariff',";
+        
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " NoDiscount%d=1,", i);
+        res += param;
+    
+        strprintf(&param, " Threshold%d=0,", i);
+        res += param;
+    
+        strprintf(&param, " Time%d='0:0-0:0',", i);
+        res += param;
+    
+        if(i != 0 && i != 1)
+        {
+            strprintf(&param, " SinglePrice%d=0,", i);
+            res += param;        
+        }
+    
+        if(i != 1)
+        {
+            strprintf(&param, " PriceDayA%d=0.0,", i); 
+            res += param;        
+        }
+        if(i != 1)
+        {
+            strprintf(&param, " PriceDayB%d=0.0,", i);        
+            res += param;    
+        }
+    
+        if(i != 0)
+        {
+            strprintf(&param, " PriceNightA%d=0.0,", i); 
+            res += param;        
+        }
+        if(i != 0)
+        {
+            strprintf(&param, " PriceNightB%d=0.0,", i);        
+            res += param;    
+        }
+        }
+    
+    res += "PassiveCost=0.0, Fee=10.0, Free=0,"\
+        "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\
+        "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down'";
+    
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create default tariff. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+//users-----------------------------------------------------------------------
+if(!IsTablePresent("users",sock))
+{
+    res = "CREATE TABLE users (login VARCHAR(50) NOT NULL DEFAULT '' PRIMARY KEY, Password VARCHAR(150) NOT NULL DEFAULT '*',"\
+        "Passive INT(3) DEFAULT 0,Down INT(3) DEFAULT 0,DisabledDetailStat INT(3) DEFAULT 0,AlwaysOnline INT(3) DEFAULT 0,Tariff VARCHAR(40) NOT NULL DEFAULT '',"\
+        "Address VARCHAR(254) NOT NULL DEFAULT '',Phone VARCHAR(128) NOT NULL DEFAULT '',Email VARCHAR(50) NOT NULL DEFAULT '',"\
+        "Note TEXT NOT NULL,RealName VARCHAR(254) NOT NULL DEFAULT '',StgGroup VARCHAR(40) NOT NULL DEFAULT '',"\
+        "Credit DOUBLE DEFAULT 0, TariffChange VARCHAR(40) NOT NULL DEFAULT '',";
+    
+    for (int i = 0; i < USERDATA_NUM; i++)
+        {
+        strprintf(&param, " Userdata%d VARCHAR(254) NOT NULL,", i);
+        res += param;
+        }
+    
+    param = " CreditExpire INT(11) DEFAULT 0,";
+    res += param;
+    
+    strprintf(&param, " IP VARCHAR(254) DEFAULT '*',");
+    res += param;
+    
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " D%d BIGINT(30) DEFAULT 0,", i);
+        res += param;
+    
+        strprintf(&param, " U%d BIGINT(30) DEFAULT 0,", i);
+        res += param;
+        }
+    
+    strprintf(&param, "Cash DOUBLE DEFAULT 0,FreeMb DOUBLE DEFAULT 0,LastCashAdd DOUBLE DEFAULT 0,"\
+        "LastCashAddTime INT(11) DEFAULT 0,PassiveTime INT(11) DEFAULT 0,LastActivityTime INT(11) DEFAULT 0,"\
+        "NAS VARCHAR(17) NOT NULL, INDEX (AlwaysOnline), INDEX (IP), INDEX (Address),"\
+        " INDEX (Tariff),INDEX (Phone),INDEX (Email),INDEX (RealName))");
+    res += param;
+        
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create users table list With error:\n";
+        errorStr += mysql_error(sock);
+        errorStr += "\n\n" + res;
+        mysql_close(sock);
+        return -1;
+    }
+
+    res = "INSERT INTO users SET login='test',Address='',AlwaysOnline=0,"\
+        "Credit=0.0,CreditExpire=0,Down=0,Email='',DisabledDetailStat=0,"\
+        "StgGroup='',IP='192.168.1.1',Note='',Passive=0,Password='123456',"\
+        "Phone='', RealName='',Tariff='tariff',TariffChange='',Userdata0='',"\
+        "Userdata1='',";
+    
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " D%d=0,", i);
+        res += param;
+    
+        strprintf(&param, " U%d=0,", i);
+        res += param;
+        }
+    
+    res += "Cash=10.0,FreeMb=0.0,LastActivityTime=0,LastCashAdd=0,"\
+        "LastCashAddTime=0, PassiveTime=0";
+        
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create default user. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+/*
+//logs-----------------------------------------------------------------------
+if(!IsTablePresent("logs"))
+{
+    sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
+    
+    if(MysqlQuery(qbuf))
+    {
+        errorStr = "Couldn't create admin table list With error:\n";
+        errorStr += mysql_error(sock);
+        return -1;
+    }
+}
+*/
+//messages---------------------------------------------------------------------
+if(!IsTablePresent("messages",sock))
+{
+    sprintf(qbuf,"CREATE TABLE messages (login VARCHAR(40) DEFAULT '', id BIGINT, "\
+            "type INT, lastSendTime INT, creationTime INT, showTime INT,"\
+            "stgRepeat INT, repeatPeriod INT, text TEXT)");
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create messages table. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+//month_stat-------------------------------------------------------------------
+if(!IsTablePresent("stat",sock))
+{
+    res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
+    
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " U%d BIGINT,", i); 
+        res += param;
+            
+        strprintf(&param, " D%d BIGINT,", i); 
+        res += param;
+        }
+        
+    res += " cash DOUBLE, INDEX (login))";
+    
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create stat table. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+int MYSQL_STORE::GetAllParams(vector<string> * ParamList, 
+                            const string & table, const string & name) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock=NULL;
+unsigned int num,i;
+    
+ParamList->clear();
+    
+sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't GetAllParams Query for: ";
+    errorStr += name + " - " + table + "\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't GetAllParams Results for: ";
+    errorStr += name + " - " + table + "\n";
+    errorStr += mysql_error(sock);
+    return -1;
+}
+
+num = mysql_num_rows(res);
+
+for(i=0;i<num;i++)
+{
+    row = mysql_fetch_row(res);    
+    ParamList->push_back(row[0]);
+}
+
+mysql_free_result(res);
+mysql_close(sock);
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetUsersList(vector<string> * usersList) const
+{
+if(GetAllParams(usersList, "users", "login"))
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetAdminsList(vector<string> * adminsList) const
+{
+if(GetAllParams(adminsList, "admins", "login"))
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetTariffsList(vector<string> * tariffsList) const
+{
+if(GetAllParams(tariffsList, "tariffs", "name"))
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddUser(const string & login) const
+{
+sprintf(qbuf,"INSERT INTO users SET login='%s'", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add user:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelUser(const string & login) const
+{
+sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete user:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreUserConf(USER_CONF * conf, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+string query;
+
+query = "SELECT login, Password, Passive, Down, DisabledDetailStat, \
+         AlwaysOnline, Tariff, Address, Phone, Email, Note, \
+         RealName, StgGroup, Credit, TariffChange, ";
+
+for (int i = 0; i < USERDATA_NUM; i++)
+{
+    sprintf(qbuf, "Userdata%d, ", i);
+    query += qbuf;
+}
+
+query += "CreditExpire, IP FROM users WHERE login='";
+query += login + "' LIMIT 1";
+
+//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlGetQuery(query.c_str(),sock))
+{
+    errorStr = "Couldn't restore Tariff(on query):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore Tariff(on getting result):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+row = mysql_fetch_row(res);
+
+string param;
+
+conf->password = row[1];
+
+if (conf->password.empty())
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' password is blank.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[2],&conf->passive, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[3], &conf->disabled, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter Down.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[4], &conf->disabledDetailStat, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter DisabledDetailStat.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[5], &conf->alwaysOnline, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
+    mysql_close(sock);
+    return -1;
+    }
+
+conf->tariffName = row[6];
+
+if (conf->tariffName.empty()) 
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' tariff is blank.";
+    mysql_close(sock);
+    return -1;
+    }
+
+conf->address = row[7];
+conf->phone = row[8];
+conf->email = row[9];
+conf->note = row[10];
+conf->realName = row[11];
+conf->group = row[12];
+
+if (GetDouble(row[13], &conf->credit, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
+    mysql_close(sock);
+    return -1;
+    }
+
+conf->nextTariff = row[14];
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    conf->userdata[i] = row[15+i];
+    }
+
+GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
+    
+string ipStr = row[16+USERDATA_NUM];
+USER_IPS i;
+try
+    {
+    i = StrToIPS(ipStr);
+    }
+catch (string s)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
+    mysql_close(sock);
+    return -1;
+    }
+conf->ips = i;
+
+mysql_free_result(res);
+mysql_close(sock);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreUserStat(USER_STAT * stat, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+
+string query;
+
+query = "SELECT ";
+
+for (int i = 0; i < DIR_NUM; i++)
+{
+    sprintf(qbuf, "D%d, U%d, ", i, i);
+    query += qbuf;
+}
+
+query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityTime \
+          FROM users WHERE login = '";
+query += login + "'";
+
+//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlGetQuery(query.c_str() ,sock))
+{
+    errorStr = "Couldn't restore UserStat(on query):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore UserStat(on getting result):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+row = mysql_fetch_row(res);
+
+unsigned int startPos=0;
+
+char s[22];
+uint64_t traffU[DIR_NUM];
+uint64_t traffD[DIR_NUM];
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    sprintf(s, "D%d", i);
+    if (GetULongLongInt(row[startPos+i*2],&traffD[i], 0) != 0)
+        {
+        mysql_free_result(res);
+        errorStr = "User \'" + login + "\' stat not read. Parameter " + string(s);
+        mysql_close(sock);
+        return -1;
+        }
+    stat->down = traffD;
+
+    sprintf(s, "U%d", i);
+    if (GetULongLongInt(row[startPos+i*2+1], &traffU[i], 0) != 0)
+        {
+        mysql_free_result(res);
+        errorStr =   "User \'" + login + "\' stat not read. Parameter " + string(s);
+        mysql_close(sock);
+        return -1;
+        }
+    stat->up = traffU;
+    }//for
+
+startPos += (2*DIR_NUM);
+
+if (GetDouble(row[startPos], &stat->cash, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter Cash";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[startPos+1],&stat->freeMb, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter FreeMb";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[startPos+2], &stat->lastCashAdd, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAdd";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetTime(row[startPos+3], &stat->lastCashAddTime, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetTime(row[startPos+4], &stat->passiveTime, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter PassiveTime";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetTime(row[startPos+5], &stat->lastActivityTime, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastActivityTime";
+    mysql_close(sock);
+    return -1;
+    }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveUserConf(const USER_CONF & conf, const string & login) const
+{
+string param;
+string res;
+
+strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDetailStat = %d, "\
+    "AlwaysOnline=%d, Tariff='%s', Address='%s', Phone='%s', Email='%s', "\
+    "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ", 
+    conf.password.c_str(),
+    conf.passive,
+    conf.disabled,
+    conf.disabledDetailStat,
+    conf.alwaysOnline,
+    conf.tariffName.c_str(),
+    (ReplaceStr(conf.address,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.phone,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.email,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.note,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.realName,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.group,badSyms,repSym)).c_str(),
+    conf.credit,
+    conf.nextTariff.c_str()
+    );
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    strprintf(&param, " Userdata%d='%s',", i, 
+        (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
+    res += param;
+    }
+    
+strprintf(&param, " CreditExpire=%d,", conf.creditExpire);
+res += param;
+
+stringstream ipStr;
+ipStr << conf.ips;
+
+strprintf(&param, " IP='%s'", ipStr.str().c_str());
+res += param;
+
+strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't save user conf:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveUserStat(const USER_STAT & stat, const string & login) const
+{
+string param;
+string res;
+
+res = "UPDATE users SET";
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, " D%d=%lld,", i, stat.down[i]);
+    res += param;
+
+    strprintf(&param, " U%d=%lld,", i, stat.up[i]);
+    res += param;
+    }
+
+strprintf(&param, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
+    " PassiveTime=%d, LastActivityTime=%d", 
+    stat.cash,
+    stat.freeMb,
+    stat.lastCashAdd,
+    stat.lastCashAddTime,
+    stat.passiveTime,
+    stat.lastActivityTime
+    );
+res += param;
+
+strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't save user stat:\n";
+//    errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteLogString(const string & str, const string & login) const
+{
+string res, tempStr;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+lt = localtime(&t);
+
+MYSQL_RES* result;
+MYSQL * sock;
+strprintf(&tempStr, "logs_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
+if (!(sock=MysqlConnect())){
+    errorStr = "Couldn't connect to Server";
+    return -1;
+}
+if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
+{
+    errorStr = "Couldn't get table " + tempStr + ":\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int num_rows =  mysql_num_rows(result);
+
+mysql_free_result(result);
+
+if (num_rows < 1)
+{
+    sprintf(qbuf,"CREATE TABLE logs_%02d_%4d (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)",
+    lt->tm_mon+1, lt->tm_year+1900);
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create WriteDetailedStat table:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+strprintf(&res, "%s -- %s",LogDate(t), str.c_str());
+
+string send;
+
+strprintf(&send,"INSERT INTO logs_%02d_%4d SET login='%s', text='%s'",
+        lt->tm_mon+1, lt->tm_year+1900,
+    login.c_str(), (ReplaceStr(res,badSyms,repSym)).c_str());
+
+if(MysqlQuery(send.c_str(),sock))
+{
+    errorStr = "Couldn't write log string:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+mysql_close(sock);
+return 0;
+
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserChgLog(const string & login,
+                                 const string & admLogin,
+                                 uint32_t       admIP,
+                                 const string & paramName,
+                                 const string & oldValue,
+                                 const string & newValue,
+                                 const string & message) const
+{
+string userLogMsg = "Admin \'" + admLogin + "\', " + string(inet_ntostr(admIP)) + ": \'"
+    + paramName + "\' parameter changed from \'" + oldValue +
+    "\' to \'" + newValue + "\'. " + message;
+
+return WriteLogString(userLogMsg, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserConnect(const string & login, uint32_t ip) const
+{
+string logStr = "Connect, " + string(inet_ntostr(ip));
+return WriteLogString(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserDisconnect(const string & login,
+                                     const DIR_TRAFF & up,
+                                     const DIR_TRAFF & down,
+                                     const DIR_TRAFF & sessionUp,
+                                     const DIR_TRAFF & sessionDown,
+                                     double cash,
+                                    double freeMb) const
+{
+string logStr = "Disconnect, ";
+stringstream sssu;
+stringstream sssd;
+stringstream ssmu;
+stringstream ssmd;
+stringstream sscash;
+
+ssmu << up;
+ssmd << down;
+
+sssu << sessionUp;
+sssd << sessionDown;
+
+sscash << cash;
+
+logStr += " session upload: \'";
+logStr += sssu.str();
+logStr += "\' session download: \'";
+logStr += sssd.str();
+logStr += "\' month upload: \'";
+logStr += ssmu.str();
+logStr += "\' month download: \'";
+logStr += ssmd.str();
+logStr += "\' cash: \'";
+logStr += sscash.str();
+logStr += "\'";
+
+return WriteLogString(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, 
+                                const string & login) const
+{
+string param, res;
+
+strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,", 
+    login.c_str(), month+1, year+1900);
+    
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, " U%d=%lld,", i, stat.up[i]); 
+    res += param;
+
+    strprintf(&param, " D%d=%lld,", i, stat.down[i]);        
+    res += param;
+    }
+    
+strprintf(&param, " cash=%f", stat.cash);        
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't SaveMonthStat:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::AddAdmin(const string & login) const
+{
+sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::DelAdmin(const string & login) const
+{
+sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::SaveAdmin(const ADMIN_CONF & ac) const
+{
+char passwordE[2 * ADM_PASSWD_LEN + 2];
+char pass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+
+memset(pass, 0, sizeof(pass));
+memset(adminPass, 0, sizeof(adminPass));
+
+BLOWFISH_CTX ctx;
+EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+adminPass[ADM_PASSWD_LEN - 1] = 0;
+
+for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+    {
+    EncodeString(pass + 8*i, adminPass + 8*i, &ctx);
+    }
+
+pass[ADM_PASSWD_LEN - 1] = 0;
+Encode12(passwordE, pass, ADM_PASSWD_LEN);
+
+sprintf(qbuf,"UPDATE admins SET password='%s', ChgConf=%d, ChgPassword=%d, "\
+    "ChgStat=%d, ChgCash=%d, UsrAddDel=%d, ChgTariff=%d, ChgAdmin=%d "\
+    "WHERE login='%s' LIMIT 1", 
+    passwordE,
+    ac.priv.userConf,
+    ac.priv.userPasswd,
+    ac.priv.userStat,
+    ac.priv.userCash,
+    ac.priv.userAddDel,
+    ac.priv.tariffChg,
+    ac.priv.adminChg,
+    ac.login.c_str()
+    );
+
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't save admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreAdmin(ADMIN_CONF * ac, const string & login) const
+{
+char pass[ADM_PASSWD_LEN + 1];
+char password[ADM_PASSWD_LEN + 1];
+char passwordE[2*ADM_PASSWD_LEN + 2];
+BLOWFISH_CTX ctx;
+
+string p;
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't restore admin:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore admin:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if ( mysql_num_rows(res) == 0)
+{
+    mysql_free_result(res);
+    errorStr = "Couldn't restore admin as couldn't found him in table.\n";
+    mysql_close(sock);
+    return -1;
+}
+  
+row = mysql_fetch_row(res);
+
+p = row[1];
+int a;
+
+if(p.length() == 0)
+{
+    mysql_free_result(res);
+    errorStr = "Error in parameter password";
+    mysql_close(sock);
+    return -1;
+}
+
+memset(passwordE, 0, sizeof(passwordE));
+strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
+
+memset(pass, 0, sizeof(pass));
+
+if (passwordE[0] != 0)
+    {
+    Decode21(pass, passwordE);
+    EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+    for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+        {
+        DecodeString(password + 8*i, pass + 8*i, &ctx);
+        }
+    }
+else
+    {
+    password[0] = 0;
+    }
+
+ac->password = password;
+
+if (GetInt(row[2], &a, 0) == 0) 
+    ac->priv.userConf = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgConf";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[3], &a, 0) == 0) 
+    ac->priv.userPasswd = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgPassword";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[4], &a, 0) == 0) 
+    ac->priv.userStat = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgStat";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[5], &a, 0) == 0) 
+    ac->priv.userCash = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgCash";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[6], &a, 0) == 0) 
+    ac->priv.userAddDel = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter UsrAddDel";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[7], &a, 0) == 0) 
+    ac->priv.tariffChg = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgTariff";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[8], &a, 0) == 0) 
+    ac->priv.adminChg = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgAdmin";
+    mysql_close(sock);
+    return -1;
+    }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddTariff(const string & name) const
+{
+sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add tariff:\n";
+//    errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelTariff(const string & name) const
+{
+sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete tariff: ";
+//    errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreTariff(TARIFF_DATA * td, const string & tariffName) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't restore Tariff:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore Tariff:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+string str;
+td->tariffConf.name = tariffName;
+
+row = mysql_fetch_row(res);
+
+string param;
+for (int i = 0; i<DIR_NUM; i++)
+    {
+    strprintf(&param, "Time%d", i);
+    str = row[6+i*8];
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    ParseTariffTimeStr(str.c_str(), 
+                       td->dirPrice[i].hDay, 
+                       td->dirPrice[i].mDay, 
+                       td->dirPrice[i].hNight, 
+                       td->dirPrice[i].mNight);
+
+    strprintf(&param, "PriceDayA%d", i);
+    if (GetDouble(row[1+i*8], &td->dirPrice[i].priceDayA, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceDayA /= (1024*1024);
+
+    strprintf(&param, "PriceDayB%d", i);
+    if (GetDouble(row[2+i*8], &td->dirPrice[i].priceDayB, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceDayB /= (1024*1024);
+
+    strprintf(&param, "PriceNightA%d", i);
+    if (GetDouble(row[3+i*8], &td->dirPrice[i].priceNightA, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceNightA /= (1024*1024);
+
+    strprintf(&param, "PriceNightB%d", i);
+    if (GetDouble(row[4+i*8], &td->dirPrice[i].priceNightB, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceNightB /= (1024*1024);
+
+    strprintf(&param, "Threshold%d", i);
+    if (GetInt(row[5+i*8], &td->dirPrice[i].threshold, 0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    strprintf(&param, "SinglePrice%d", i);
+    if (GetInt(row[8+i*8], &td->dirPrice[i].singlePrice, 0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    strprintf(&param, "NoDiscount%d", i);
+    if (GetInt(row[7+i*8], &td->dirPrice[i].noDiscount, 0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    }//main for
+
+if (GetDouble(row[2+8*DIR_NUM], &td->tariffConf.fee, 0.0) < 0)
+    {
+    mysql_free_result(res);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[3+8*DIR_NUM], &td->tariffConf.free, 0.0) < 0)
+    {
+    mysql_free_result(res);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
+    {
+    mysql_free_result(res);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
+    mysql_close(sock);
+    return -1;
+    }
+
+    str = row[4+8*DIR_NUM];
+    param = "TraffType";
+    
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+if (!strcasecmp(str.c_str(), "up"))
+    td->tariffConf.traffType = TRAFF_UP;
+else
+    if (!strcasecmp(str.c_str(), "down"))
+        td->tariffConf.traffType = TRAFF_DOWN;
+    else
+        if (!strcasecmp(str.c_str(), "up+down"))
+            td->tariffConf.traffType = TRAFF_UP_DOWN;
+        else
+            if (!strcasecmp(str.c_str(), "max"))
+                td->tariffConf.traffType = TRAFF_MAX;
+            else
+                {
+                mysql_free_result(res);
+                errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType incorrect";
+                mysql_close(sock);
+                return -1;
+                }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveTariff(const TARIFF_DATA & td, const string & tariffName) const
+{
+string param;
+
+string res="UPDATE tariffs SET";
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, " PriceDayA%d=%f,", i, 
+        td.dirPrice[i].priceDayA * pt_mega);
+    res += param;
+
+    strprintf(&param, " PriceDayB%d=%f,", i, 
+        td.dirPrice[i].priceDayB * pt_mega);        
+    res += param;
+        
+    strprintf(&param, " PriceNightA%d=%f,", i,
+        td.dirPrice[i].priceNightA * pt_mega);
+    res += param;
+
+    strprintf(&param, " PriceNightB%d=%f,", i, 
+        td.dirPrice[i].priceNightB * pt_mega);
+    res += param;
+        
+    strprintf(&param, " Threshold%d=%d,", i, 
+        td.dirPrice[i].threshold);
+    res += param;
+
+    string s;
+    strprintf(&param, " Time%d", i);
+
+    strprintf(&s, "%0d:%0d-%0d:%0d", 
+            td.dirPrice[i].hDay,
+            td.dirPrice[i].mDay,
+            td.dirPrice[i].hNight,
+            td.dirPrice[i].mNight);
+
+    res += (param + "='" + s + "',");
+
+    strprintf(&param, " NoDiscount%d=%d,", i, 
+        td.dirPrice[i].noDiscount);
+    res += param;
+
+    strprintf(&param, " SinglePrice%d=%d,", i, 
+        td.dirPrice[i].singlePrice);
+    res += param;
+    }
+
+strprintf(&param, " PassiveCost=%f,", td.tariffConf.passiveCost);
+res += param;
+
+strprintf(&param, " Fee=%f,", td.tariffConf.fee);
+res += param;
+
+strprintf(&param, " Free=%f,", td.tariffConf.free);
+res += param;
+
+switch (td.tariffConf.traffType)
+    {
+    case TRAFF_UP:
+        res += " TraffType='up'";
+        break;
+    case TRAFF_DOWN:
+        res += " TraffType='down'";
+        break;
+    case TRAFF_UP_DOWN:
+        res += " TraffType='up+down'";
+        break;
+    case TRAFF_MAX:
+        res += " TraffType='max'";
+        break;
+    }
+strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't save admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree, 
+                                   time_t lastStat, 
+                                   const string & login) const
+{
+string res, stTime, endTime, tempStr;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+lt = localtime(&t);
+
+if (lt->tm_hour == 0 && lt->tm_min <= 5)
+    {
+        t -= 3600 * 24;
+        lt = localtime(&t);
+    }
+
+MYSQL_RES* result;
+MYSQL * sock;
+strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
+
+if (!(sock=MysqlConnect())){
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
+{
+    errorStr = "Couldn't get table " + tempStr + ":\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int num_rows =  mysql_num_rows(result);
+
+mysql_free_result(result);
+
+if (num_rows < 1)
+{
+    sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
+        "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
+        "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
+        "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
+    lt->tm_mon+1, lt->tm_year+1900);
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create WriteDetailedStat table:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+struct tm * lt1;
+struct tm * lt2;
+
+lt1 = localtime(&lastStat);
+
+int h1, m1, s1;
+int h2, m2, s2;
+
+h1 = lt1->tm_hour;
+m1 = lt1->tm_min;
+s1 = lt1->tm_sec;
+
+lt2 = localtime(&t);
+
+h2 = lt2->tm_hour;
+m2 = lt2->tm_min;
+s2 = lt2->tm_sec;
+    
+strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
+strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
+
+strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
+    "day=%d,startTime='%s',endTime='%s',", 
+    lt->tm_mon+1, lt->tm_year+1900,
+    login.c_str(),
+    lt->tm_mday,
+    stTime.c_str(),
+    endTime.c_str()
+    );
+
+int retRes;
+map<IP_DIR_PAIR, STAT_NODE>::const_iterator stIter;
+stIter = statTree->begin();
+
+while (stIter != statTree->end())
+    {
+        strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f", 
+                inet_ntostr(stIter->first.ip),
+                stIter->first.dir, 
+                stIter->second.down, 
+                stIter->second.up, 
+                stIter->second.cash
+            );
+    
+        if( (retRes = MysqlQuery((res+tempStr).c_str(),sock)) )
+        {
+            errorStr = "Couldn't insert data in WriteDetailedStat:\n";
+            errorStr += mysql_error(sock);
+            mysql_close(sock);
+            return -1;
+        }
+
+        result=mysql_store_result(sock);
+        if(result)
+            mysql_free_result(result);
+
+        ++stIter;
+    }
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddMessage(STG_MSG * msg, const string & login) const
+{
+struct timeval tv;
+
+gettimeofday(&tv, NULL);
+
+msg->header.id = ((long long)tv.tv_sec) * 1000000 + ((long long)tv.tv_usec);
+
+sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld", 
+    login.c_str(),
+    (long long)msg->header.id
+    );
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add message:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return EditMessage(*msg, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::EditMessage(const STG_MSG & msg, const string & login) const
+{
+string res;
+
+strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
+    "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
+    "WHERE login='%s' AND id=%lld LIMIT 1", 
+    msg.header.type,
+    msg.header.lastSendTime,
+    msg.header.creationTime,
+    msg.header.showTime,
+    msg.header.repeat,
+    msg.header.repeatPeriod,
+    (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
+    login.c_str(),
+    (long long)msg.header.id
+    );
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't edit message:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetMessage(uint64_t id, STG_MSG * msg, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+
+sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%lld LIMIT 1",
+    login.c_str(), id);
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't GetMessage:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't GetMessage:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+row = mysql_fetch_row(res);
+
+if(row[2]&&str2x(row[2], msg->header.type))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[3] && str2x(row[3], msg->header.lastSendTime))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[4] && str2x(row[4], msg->header.creationTime))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[5] && str2x(row[5], msg->header.showTime))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[6] && str2x(row[6], msg->header.repeat))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[7] && str2x(row[7], msg->header.repeatPeriod))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+msg->header.id = id;
+msg->text = row[8];
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelMessage(uint64_t id, const string & login) const
+{
+sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1", 
+    login.c_str(),(long long)id);
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete Message:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't GetMessageHdrs:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't GetMessageHdrs:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int i, num_rows =  mysql_num_rows(res);
+long long int unsigned id;
+
+for (i=0; i<num_rows; i++)
+{
+    row = mysql_fetch_row(res);
+    if (str2x(row[1], id))
+        continue;
+    
+    STG_MSG_HDR hdr;
+    if (row[2]) 
+        if(str2x(row[2], hdr.type))
+            continue;
+
+    if (row[3])
+        if(str2x(row[3], hdr.lastSendTime))
+            continue;
+
+    if (row[4])
+        if(str2x(row[4], hdr.creationTime))
+            continue;
+
+    if (row[5])
+        if(str2x(row[5], hdr.showTime))
+            continue;
+
+    if (row[6])
+        if(str2x(row[6], hdr.repeat))
+            continue;
+
+    if (row[7])
+        if(str2x(row[7], hdr.repeatPeriod))
+            continue;
+
+    hdr.id = id;
+    hdrsList->push_back(hdr);
+}
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
+
+    MYSQL * sock;
+    int ret=MysqlGetQuery(Query,sock);
+    mysql_close(sock);
+    return ret;
+}
+//-----------------------------------------------------------------------------
+int  MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
+    if (!(sock=MysqlConnect())) {
+        return -1;
+    }
+    return   MysqlQuery(Query,sock);
+}
+//-----------------------------------------------------------------------------
+MYSQL *  MYSQL_STORE::MysqlConnect() const {
+    MYSQL * sock;
+    if ( !(sock=mysql_init(NULL)) ){
+        errorStr= "mysql init susck\n";
+        return NULL;
+    }
+    if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
+            storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
+            0,0,NULL,0)))
+        {
+            errorStr = "Couldn't connect to mysql engine! With error:\n";
+            errorStr += mysql_error(sock);
+            return NULL;
+        }
+    else{
+         if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
+             errorStr = "Database lost !\n";
+             return NULL;
+         }
+    }
+    return sock;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/store/mysql/.#mysql_store.h.1.1.1.1 b/projects/stargazer/plugins/store/mysql/.#mysql_store.h.1.1.1.1
new file mode 100644 (file)
index 0000000..016bde5
--- /dev/null
@@ -0,0 +1,143 @@
+ /*
+ $Revision: 1.1.1.1 $
+ $Date: 2007/11/17 18:28:39 $
+ */
+
+
+#ifndef FILE_STORE_H
+#define FILE_STORE_H
+
+#include <string>
+
+#include "base_settings.h"
+#include "base_store.h"
+#include "user_traff.h"
+#include <mysql/mysql.h>
+
+using namespace std;
+//-----------------------------------------------------------------------------
+extern "C" BASE_STORE * GetStore();
+//-----------------------------------------------------------------------------
+class MYSQL_STORE_SETTINGS//: public BASE_SETTINGS
+{
+public:
+    MYSQL_STORE_SETTINGS();
+    virtual ~MYSQL_STORE_SETTINGS();
+    virtual int ParseSettings(const MODULE_SETTINGS & s);
+    virtual const string & GetStrError() const;
+
+    string  GetDBUser() const;
+    string  GetDBPassword() const;
+    string  GetDBHost() const;
+    string  GetDBName() const;
+
+private:
+    const MODULE_SETTINGS * settings;
+
+    int     ParseParam(const vector<PARAM_VALUE> & moduleParams, 
+                       const string & name, string & result);
+
+       string  errorStr;
+
+    string  dbUser;
+    string  dbPass;
+       string  dbName;
+    string  dbHost;
+};
+//-----------------------------------------------------------------------------
+class MYSQL_STORE: public BASE_STORE
+{
+public:
+    MYSQL_STORE();
+    virtual ~MYSQL_STORE();
+    virtual const string & GetStrError() const;
+
+    //User
+    virtual int GetUsersList(vector<string> * usersList) const;
+    virtual int AddUser(const string & login) const;
+    virtual int DelUser(const string & login) const;
+    virtual int SaveUserStat(const USER_STAT & stat, const string & login) const;
+    virtual int SaveUserConf(const USER_CONF & conf, const string & login) const;
+    virtual int RestoreUserStat(USER_STAT * stat, const string & login) const;
+    virtual int RestoreUserConf(USER_CONF * conf, const string & login) const;
+    virtual int WriteUserChgLog(const string & login,
+                                const string & admLogin,
+                                uint32_t       admIP,
+                                const string & paramName,
+                                const string & oldValue,
+                                const string & newValue,
+                                const string & message = "") const;
+    virtual int WriteUserConnect(const string & login, uint32_t ip) const;
+    virtual int WriteUserDisconnect(const string & login,
+                                    const DIR_TRAFF & up,
+                                    const DIR_TRAFF & down,
+                                    const DIR_TRAFF & sessionUp,
+                                    const DIR_TRAFF & sessionDown,
+                                    double cash,
+                                   double freeMb) const;
+
+    virtual int WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                  time_t lastStat,
+                                  const string & login) const;
+
+    virtual int AddMessage(STG_MSG * msg, const string & login) const;
+    virtual int EditMessage(const STG_MSG & msg, const string & login) const;
+    virtual int GetMessage(uint64_t id, STG_MSG * msg, const string & login) const;
+    virtual int DelMessage(uint64_t id, const string & login) const;
+    virtual int GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const;
+
+    virtual int SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const;
+
+    //Admin
+    virtual int GetAdminsList(vector<string> * adminsList) const;
+    virtual int AddAdmin(const string & login) const;
+    virtual int DelAdmin(const string & login) const;
+    virtual int RestoreAdmin(ADMIN_CONF * ac, const string & login) const;
+    virtual int SaveAdmin(const ADMIN_CONF & ac) const;
+
+    //Tariff
+    virtual int GetTariffsList(vector<string> * tariffsList) const;
+    virtual int AddTariff(const string & name) const;
+    virtual int DelTariff(const string & name) const;
+    virtual int SaveTariff(const TARIFF_DATA & td, const string & tariffName) const;
+    virtual int RestoreTariff(TARIFF_DATA * td, const string & tariffName) const;
+
+    //Corparation
+    virtual int GetCorpsList(vector<string> * corpsList) const {return 0;};
+    virtual int SaveCorp(const CORP_CONF & cc) const {return 0;};
+    virtual int RestoreCorp(CORP_CONF * cc, const string & name) const {return 0;};
+    virtual int AddCorp(const string & name) const {return 0;};
+    virtual int DelCorp(const string & name) const {return 0;};
+
+    // Services
+    virtual int GetServicesList(vector<string> * corpsList) const {return 0;};
+    virtual int SaveService(const SERVICE_CONF & sc) const {return 0;};
+    virtual int RestoreService(SERVICE_CONF * sc, const string & name) const {return 0;};
+    virtual int AddService(const string & name) const {return 0;};
+    virtual int DelService(const string & name) const {return 0;};
+
+    //virtual BASE_SETTINGS * GetStoreSettings();
+    virtual void            SetSettings(const MODULE_SETTINGS & s);
+    virtual int             ParseSettings();
+    virtual const string &  GetVersion() const;
+
+private:
+    virtual int WriteLogString(const string & str, const string & login) const;
+       int GetAllParams(vector<string> * ParamList, const string & table, const string & name) const;
+       int CheckAllTables(MYSQL * sock);
+       bool IsTablePresent(const string & str,MYSQL * sock);
+    mutable string          errorStr;
+//    int                                              Reconnect();
+    int                                                MysqlQuery(const char* sQuery,MYSQL * sock) const;
+    int                     MysqlGetQuery(const char * Query,MYSQL * & sock) const;
+    int                     MysqlSetQuery(const char * Query) const;
+    MYSQL  *                MysqlConnect() const ;
+    string                  version;
+    MYSQL_STORE_SETTINGS    storeSettings;
+    MODULE_SETTINGS         settings;
+       //mutable MYSQL                                 mysql;
+       //mutable MYSQL*                                        sock;
+};
+//-----------------------------------------------------------------------------
+
+#endif //FILE_STORE_H
diff --git a/projects/stargazer/plugins/store/mysql/Makefile b/projects/stargazer/plugins/store/mysql/Makefile
new file mode 100644 (file)
index 0000000..494a031
--- /dev/null
@@ -0,0 +1,20 @@
+###############################################################################
+# $Id: Makefile,v 1.6 2010/03/25 10:35:55 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_store_mysql.so
+
+SRCS = ./mysql_store.cpp
+
+STGLIBS = -lconffiles -lstg_common -lstg_crypto
+
+MYSQL_CFLAGS = $(shell mysql_config --cflags)
+MYSQL_LDFLAGS = $(shell mysql_config --libs_r)
+
+CXXFLAGS += $(MYSQL_CFLAGS)
+LIBS += $(MYSQL_LDFLAGS)
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/store/mysql/deps b/projects/stargazer/plugins/store/mysql/deps
new file mode 100644 (file)
index 0000000..ffffca1
--- /dev/null
@@ -0,0 +1,30 @@
+mysql_store.o: mysql_store.cpp /usr/include/mysql/mysql.h \
+ /usr/include/mysql/mysql_version.h /usr/include/mysql/mysql_com.h \
+ /usr/include/mysql/mysql_time.h /usr/include/mysql/my_list.h \
+ /usr/include/mysql/typelib.h /usr/include/mysql/my_alloc.h \
+ /usr/include/mysql/errmsg.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/common.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_const.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_ips.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/resetable.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_locker.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/noncopyable.h \
+ mysql_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_store.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_stat.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/corp_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/service_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/admin_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/tariff_conf.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/base_settings.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/stg_message.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/user_traff.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/blowfish.h Makefile ../../../../../Makefile.conf
+       $(CC) -c $< -g3 -W -Wall -I/usr/local/include -DARCH_LE -I/usr/include/mysql -DHAVE_ERRNO_AS_DEFINE=1 -DUNIV_LINUX -DUNIV_LINUX -fPIC -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -DDEBUG -DLINUX
diff --git a/projects/stargazer/plugins/store/mysql/mod_store_mysql.so b/projects/stargazer/plugins/store/mysql/mod_store_mysql.so
new file mode 100755 (executable)
index 0000000..1313d26
Binary files /dev/null and b/projects/stargazer/plugins/store/mysql/mod_store_mysql.so differ
diff --git a/projects/stargazer/plugins/store/mysql/mysql_store.cpp b/projects/stargazer/plugins/store/mysql/mysql_store.cpp
new file mode 100644 (file)
index 0000000..102be15
--- /dev/null
@@ -0,0 +1,2063 @@
+#include <sys/time.h>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <algorithm>
+
+#include <mysql.h>
+#include <errmsg.h>
+
+#include "user_ips.h"
+#include "user_conf.h"
+#include "user_stat.h"
+#include "mysql_store.h"
+#include "blowfish.h"
+
+#define adm_enc_passwd "cjeifY8m3"
+char qbuf[4096];
+
+using namespace std;
+
+const int pt_mega = 1024 * 1024;
+const string badSyms = "'`";
+const char repSym = '\"';
+const int RepitTimes = 3;
+
+int GetInt(const string & str, int * val, int defaultVal)
+{
+    char *res;
+    
+    *val = strtol(str.c_str(), &res, 10);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+int GetDouble(const string & str, double * val, double defaultVal)
+{
+    char *res;
+    
+    *val = strtod(str.c_str(), &res);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+int GetTime(const string & str, time_t * val, time_t defaultVal)
+{
+    char *res;
+    
+    *val = strtol(str.c_str(), &res, 10);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+//-----------------------------------------------------------------------------
+string ReplaceStr(string source, const string symlist, const char chgsym)
+{
+    string::size_type pos=0;
+
+    while( (pos = source.find_first_of(symlist,pos)) != string::npos)
+        source.replace(pos, 1,1, chgsym);
+
+    return source;
+}
+
+int GetULongLongInt(const string & str, uint64_t * val, uint64_t defaultVal)
+{
+    char *res;
+    
+    *val = strtoull(str.c_str(), &res, 10);
+    
+    if (*res != 0) 
+    {
+        *val = defaultVal; //Error!
+        return EINVAL;
+    }
+
+    return 0;
+} 
+
+class MYSQL_STORE_CREATOR
+{
+private:
+    MYSQL_STORE * ms;
+
+public:
+    MYSQL_STORE_CREATOR()
+        : ms(new MYSQL_STORE())
+        {
+        };
+    ~MYSQL_STORE_CREATOR()
+        {
+        delete ms;
+        };
+
+    MYSQL_STORE * GetStore()
+        {
+        return ms;
+        };
+} msc;
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+BASE_STORE * GetStore()
+{
+return msc.GetStore();
+}
+//-----------------------------------------------------------------------------
+MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
+    : settings(NULL)
+{
+}
+//-----------------------------------------------------------------------------
+MYSQL_STORE_SETTINGS::~MYSQL_STORE_SETTINGS()
+{
+
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE_SETTINGS::ParseParam(const vector<PARAM_VALUE> & moduleParams, 
+                        const string & name, string & result)
+{
+PARAM_VALUE pv;
+pv.param = name;
+vector<PARAM_VALUE>::const_iterator pvi;
+pvi = find(moduleParams.begin(), moduleParams.end(), pv);
+if (pvi == moduleParams.end())
+    {
+    errorStr = "Parameter \'" + name + "\' not found.";
+    return -1;
+    }
+    
+result = pvi->value[0];
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
+{
+if (ParseParam(s.moduleParams, "dbuser", dbUser) < 0)
+    return -1;
+if (ParseParam(s.moduleParams, "rootdbpass", dbPass) < 0)
+    return -1;
+if (ParseParam(s.moduleParams, "dbname", dbName) < 0)
+    return -1;
+if (ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+const string & MYSQL_STORE_SETTINGS::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBUser() const
+{
+return dbUser;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBPassword() const
+{
+return dbPass;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBHost() const
+{
+return dbHost;
+}
+//-----------------------------------------------------------------------------
+string MYSQL_STORE_SETTINGS::GetDBName() const
+{
+return dbName;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+MYSQL_STORE::MYSQL_STORE()
+{
+version = "mysql_store v.0.67";
+};
+//-----------------------------------------------------------------------------
+MYSQL_STORE::~MYSQL_STORE()
+{    
+};
+//-----------------------------------------------------------------------------
+void MYSQL_STORE::SetSettings(const MODULE_SETTINGS & s)
+{
+settings = s;
+}
+//-----------------------------------------------------------------------------
+int    MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
+{
+    int ret,i;
+
+    if( (ret = mysql_query(sock,sQuery)) )
+    {
+        for(i=0; i<RepitTimes; i++)
+        {
+            if( (ret = mysql_query(sock,sQuery)) )
+                ;//need to send error result
+            else
+                return 0;
+        }
+    }
+    
+    return ret;
+}
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::ParseSettings()
+{
+int ret = storeSettings.ParseSettings(settings);
+MYSQL mysql;
+MYSQL * sock;
+mysql_init(&mysql);
+if (ret)
+    errorStr = storeSettings.GetStrError();
+else
+{
+    if(storeSettings.GetDBPassword().length() == 0)
+    {
+        errorStr = "Database password must be not empty. Please read Manual.";
+        return -1;
+    }
+    
+    if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
+            storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
+            0,0,NULL,0)))
+        {
+            errorStr = "Couldn't connect to mysql engine! With error:\n";
+            errorStr += mysql_error(&mysql);
+            mysql_close(sock);
+            ret = -1;
+        }
+    else
+    {
+         if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
+         {
+             string res = "CREATE DATABASE " + storeSettings.GetDBName();
+            
+            if(MysqlQuery(res.c_str(),sock))
+            {
+                errorStr = "Couldn't create database! With error:\n";
+                errorStr += mysql_error(sock);
+                mysql_close(sock);
+                ret = -1;
+            }
+            else
+            {
+                 if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
+                 {
+                    errorStr = "Couldn't select database! With error:\n";
+                    errorStr += mysql_error(sock);
+                    mysql_close(sock);
+                    ret = -1;
+                 }
+                 ret = CheckAllTables(sock);
+            }
+         }
+         else
+             ret = CheckAllTables(sock);
+         mysql_close(sock);
+    }
+    
+}
+return ret;
+}
+//-----------------------------------------------------------------------------
+const string & MYSQL_STORE::GetStrError() const
+{
+return errorStr;
+}
+//-----------------------------------------------------------------------------
+const string & MYSQL_STORE::GetVersion() const
+{
+return version;
+}
+//-----------------------------------------------------------------------------
+bool MYSQL_STORE::IsTablePresent(const string & str,MYSQL * sock)
+{
+MYSQL_RES* result;
+
+if (!(result=mysql_list_tables(sock,str.c_str() )))
+{
+    errorStr = "Couldn't get tables list With error:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int num_rows =  mysql_num_rows(result);
+
+if(result)
+    mysql_free_result(result);
+
+return (num_rows == 1);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::CheckAllTables(MYSQL * sock)
+{
+//admins-----------------------------------------------------------------------
+if(!IsTablePresent("admins",sock))
+{
+    sprintf(qbuf,"CREATE TABLE admins (login VARCHAR(40) DEFAULT '' PRIMARY KEY,"\
+        "password VARCHAR(150) DEFAULT '*',ChgConf TINYINT DEFAULT 0,"\
+        "ChgPassword TINYINT DEFAULT 0,ChgStat TINYINT DEFAULT 0,"\
+        "ChgCash TINYINT DEFAULT 0,UsrAddDel TINYINT DEFAULT 0,"\
+        "ChgTariff TINYINT DEFAULT 0,ChgAdmin TINYINT DEFAULT 0)");
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create admin table list With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+
+    sprintf(qbuf,"INSERT INTO admins SET login='admin',"\
+        "password='geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa',"\
+        "ChgConf=1,ChgPassword=1,ChgStat=1,ChgCash=1,UsrAddDel=1,ChgTariff=1,ChgAdmin=1");
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create default admin. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+//tariffs-----------------------------------------------------------------------
+string param, res;
+if(!IsTablePresent("tariffs",sock))
+{
+    res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
+        
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " PriceDayA%d DOUBLE DEFAULT 0.0,", i); 
+        res += param;
+    
+        strprintf(&param, " PriceDayB%d DOUBLE DEFAULT 0.0,", i);
+        res += param;
+            
+        strprintf(&param, " PriceNightA%d DOUBLE DEFAULT 0.0,", i);
+        res += param;
+    
+        strprintf(&param, " PriceNightB%d DOUBLE DEFAULT 0.0,", i);
+        res += param;
+            
+        strprintf(&param, " Threshold%d INT DEFAULT 0,", i);
+        res += param;
+    
+        strprintf(&param, " Time%d VARCHAR(15) DEFAULT '0:0-0:0',", i);
+        res += param;
+    
+        strprintf(&param, " NoDiscount%d INT DEFAULT 0,", i);
+        res += param;
+    
+        strprintf(&param, " SinglePrice%d INT DEFAULT 0,", i);
+        res += param;
+        }
+    
+    res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"\
+        "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '')";
+    
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create tariffs table list With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+
+    res = "INSERT INTO tariffs SET name='tariff',";
+        
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " NoDiscount%d=1,", i);
+        res += param;
+    
+        strprintf(&param, " Threshold%d=0,", i);
+        res += param;
+    
+        strprintf(&param, " Time%d='0:0-0:0',", i);
+        res += param;
+    
+        if(i != 0 && i != 1)
+        {
+            strprintf(&param, " SinglePrice%d=0,", i);
+            res += param;        
+        }
+    
+        if(i != 1)
+        {
+            strprintf(&param, " PriceDayA%d=0.0,", i); 
+            res += param;        
+        }
+        if(i != 1)
+        {
+            strprintf(&param, " PriceDayB%d=0.0,", i);        
+            res += param;    
+        }
+    
+        if(i != 0)
+        {
+            strprintf(&param, " PriceNightA%d=0.0,", i); 
+            res += param;        
+        }
+        if(i != 0)
+        {
+            strprintf(&param, " PriceNightB%d=0.0,", i);        
+            res += param;    
+        }
+        }
+    
+    res += "PassiveCost=0.0, Fee=10.0, Free=0,"\
+        "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\
+        "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down'";
+    
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create default tariff. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+//users-----------------------------------------------------------------------
+if(!IsTablePresent("users",sock))
+{
+    res = "CREATE TABLE users (login VARCHAR(50) NOT NULL DEFAULT '' PRIMARY KEY, Password VARCHAR(150) NOT NULL DEFAULT '*',"\
+        "Passive INT(3) DEFAULT 0,Down INT(3) DEFAULT 0,DisabledDetailStat INT(3) DEFAULT 0,AlwaysOnline INT(3) DEFAULT 0,Tariff VARCHAR(40) NOT NULL DEFAULT '',"\
+        "Address VARCHAR(254) NOT NULL DEFAULT '',Phone VARCHAR(128) NOT NULL DEFAULT '',Email VARCHAR(50) NOT NULL DEFAULT '',"\
+        "Note TEXT NOT NULL,RealName VARCHAR(254) NOT NULL DEFAULT '',StgGroup VARCHAR(40) NOT NULL DEFAULT '',"\
+        "Credit DOUBLE DEFAULT 0, TariffChange VARCHAR(40) NOT NULL DEFAULT '',";
+    
+    for (int i = 0; i < USERDATA_NUM; i++)
+        {
+        strprintf(&param, " Userdata%d VARCHAR(254) NOT NULL,", i);
+        res += param;
+        }
+    
+    param = " CreditExpire INT(11) DEFAULT 0,";
+    res += param;
+    
+    strprintf(&param, " IP VARCHAR(254) DEFAULT '*',");
+    res += param;
+    
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " D%d BIGINT(30) DEFAULT 0,", i);
+        res += param;
+    
+        strprintf(&param, " U%d BIGINT(30) DEFAULT 0,", i);
+        res += param;
+        }
+    
+    strprintf(&param, "Cash DOUBLE DEFAULT 0,FreeMb DOUBLE DEFAULT 0,LastCashAdd DOUBLE DEFAULT 0,"\
+        "LastCashAddTime INT(11) DEFAULT 0,PassiveTime INT(11) DEFAULT 0,LastActivityTime INT(11) DEFAULT 0,"\
+        "NAS VARCHAR(17) NOT NULL, INDEX (AlwaysOnline), INDEX (IP), INDEX (Address),"\
+        " INDEX (Tariff),INDEX (Phone),INDEX (Email),INDEX (RealName))");
+    res += param;
+        
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create users table list With error:\n";
+        errorStr += mysql_error(sock);
+        errorStr += "\n\n" + res;
+        mysql_close(sock);
+        return -1;
+    }
+
+    res = "INSERT INTO users SET login='test',Address='',AlwaysOnline=0,"\
+        "Credit=0.0,CreditExpire=0,Down=0,Email='',DisabledDetailStat=0,"\
+        "StgGroup='',IP='192.168.1.1',Note='',Passive=0,Password='123456',"\
+        "Phone='', RealName='',Tariff='tariff',TariffChange='',Userdata0='',"\
+        "Userdata1='',";
+    
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " D%d=0,", i);
+        res += param;
+    
+        strprintf(&param, " U%d=0,", i);
+        res += param;
+        }
+    
+    res += "Cash=10.0,FreeMb=0.0,LastActivityTime=0,LastCashAdd=0,"\
+        "LastCashAddTime=0, PassiveTime=0";
+        
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create default user. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+/*
+//logs-----------------------------------------------------------------------
+if(!IsTablePresent("logs"))
+{
+    sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
+    
+    if(MysqlQuery(qbuf))
+    {
+        errorStr = "Couldn't create admin table list With error:\n";
+        errorStr += mysql_error(sock);
+        return -1;
+    }
+}
+*/
+//messages---------------------------------------------------------------------
+if(!IsTablePresent("messages",sock))
+{
+    sprintf(qbuf,"CREATE TABLE messages (login VARCHAR(40) DEFAULT '', id BIGINT, "\
+            "type INT, lastSendTime INT, creationTime INT, showTime INT,"\
+            "stgRepeat INT, repeatPeriod INT, text TEXT)");
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create messages table. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+//month_stat-------------------------------------------------------------------
+if(!IsTablePresent("stat",sock))
+{
+    res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
+    
+    for (int i = 0; i < DIR_NUM; i++)
+        {
+        strprintf(&param, " U%d BIGINT,", i); 
+        res += param;
+            
+        strprintf(&param, " D%d BIGINT,", i); 
+        res += param;
+        }
+        
+    res += " cash DOUBLE, INDEX (login))";
+    
+    if(MysqlQuery(res.c_str(),sock))
+    {
+        errorStr = "Couldn't create stat table. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+int MYSQL_STORE::GetAllParams(vector<string> * ParamList, 
+                            const string & table, const string & name) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock=NULL;
+unsigned int num,i;
+    
+ParamList->clear();
+    
+sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't GetAllParams Query for: ";
+    errorStr += name + " - " + table + "\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't GetAllParams Results for: ";
+    errorStr += name + " - " + table + "\n";
+    errorStr += mysql_error(sock);
+    return -1;
+}
+
+num = mysql_num_rows(res);
+
+for(i=0;i<num;i++)
+{
+    row = mysql_fetch_row(res);    
+    ParamList->push_back(row[0]);
+}
+
+mysql_free_result(res);
+mysql_close(sock);
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetUsersList(vector<string> * usersList) const
+{
+if(GetAllParams(usersList, "users", "login"))
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetAdminsList(vector<string> * adminsList) const
+{
+if(GetAllParams(adminsList, "admins", "login"))
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetTariffsList(vector<string> * tariffsList) const
+{
+if(GetAllParams(tariffsList, "tariffs", "name"))
+    return -1;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddUser(const string & login) const
+{
+sprintf(qbuf,"INSERT INTO users SET login='%s'", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add user:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelUser(const string & login) const
+{
+sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete user:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreUserConf(USER_CONF * conf, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+string query;
+
+query = "SELECT login, Password, Passive, Down, DisabledDetailStat, \
+         AlwaysOnline, Tariff, Address, Phone, Email, Note, \
+         RealName, StgGroup, Credit, TariffChange, ";
+
+for (int i = 0; i < USERDATA_NUM; i++)
+{
+    sprintf(qbuf, "Userdata%d, ", i);
+    query += qbuf;
+}
+
+query += "CreditExpire, IP FROM users WHERE login='";
+query += login + "' LIMIT 1";
+
+//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlGetQuery(query.c_str(),sock))
+{
+    errorStr = "Couldn't restore Tariff(on query):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore Tariff(on getting result):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+row = mysql_fetch_row(res);
+
+string param;
+
+conf->password = row[1];
+
+if (conf->password.empty())
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' password is blank.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[2],&conf->passive, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter Passive.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[3], &conf->disabled, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter Down.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[4], &conf->disabledDetailStat, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter DisabledDetailStat.";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[5], &conf->alwaysOnline, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter AlwaysOnline.";
+    mysql_close(sock);
+    return -1;
+    }
+
+conf->tariffName = row[6];
+
+if (conf->tariffName.empty()) 
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' tariff is blank.";
+    mysql_close(sock);
+    return -1;
+    }
+
+conf->address = row[7];
+conf->phone = row[8];
+conf->email = row[9];
+conf->note = row[10];
+conf->realName = row[11];
+conf->group = row[12];
+
+if (GetDouble(row[13], &conf->credit, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter Credit.";
+    mysql_close(sock);
+    return -1;
+    }
+
+conf->nextTariff = row[14];
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    conf->userdata[i] = row[15+i];
+    }
+
+GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
+    
+string ipStr = row[16+USERDATA_NUM];
+USER_IPS i;
+try
+    {
+    i = StrToIPS(ipStr);
+    }
+catch (string s)
+    {
+    mysql_free_result(res);
+    errorStr = "User \'" + login + "\' data not read. Parameter IP address. " + s;
+    mysql_close(sock);
+    return -1;
+    }
+conf->ips = i;
+
+mysql_free_result(res);
+mysql_close(sock);
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreUserStat(USER_STAT * stat, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+
+string query;
+
+query = "SELECT ";
+
+for (int i = 0; i < DIR_NUM; i++)
+{
+    sprintf(qbuf, "D%d, U%d, ", i, i);
+    query += qbuf;
+}
+
+query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityTime \
+          FROM users WHERE login = '";
+query += login + "'";
+
+//sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlGetQuery(query.c_str() ,sock))
+{
+    errorStr = "Couldn't restore UserStat(on query):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore UserStat(on getting result):\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+row = mysql_fetch_row(res);
+
+unsigned int startPos=0;
+
+char s[22];
+uint64_t traffU[DIR_NUM];
+uint64_t traffD[DIR_NUM];
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    sprintf(s, "D%d", i);
+    if (GetULongLongInt(row[startPos+i*2],&traffD[i], 0) != 0)
+        {
+        mysql_free_result(res);
+        errorStr = "User \'" + login + "\' stat not read. Parameter " + string(s);
+        mysql_close(sock);
+        return -1;
+        }
+    stat->down = traffD;
+
+    sprintf(s, "U%d", i);
+    if (GetULongLongInt(row[startPos+i*2+1], &traffU[i], 0) != 0)
+        {
+        mysql_free_result(res);
+        errorStr =   "User \'" + login + "\' stat not read. Parameter " + string(s);
+        mysql_close(sock);
+        return -1;
+        }
+    stat->up = traffU;
+    }//for
+
+startPos += (2*DIR_NUM);
+
+if (GetDouble(row[startPos], &stat->cash, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter Cash";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[startPos+1],&stat->freeMb, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter FreeMb";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[startPos+2], &stat->lastCashAdd, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAdd";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetTime(row[startPos+3], &stat->lastCashAddTime, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastCashAddTime";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetTime(row[startPos+4], &stat->passiveTime, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter PassiveTime";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetTime(row[startPos+5], &stat->lastActivityTime, 0) != 0)
+    {
+    mysql_free_result(res);
+    errorStr =   "User \'" + login + "\' stat not read. Parameter LastActivityTime";
+    mysql_close(sock);
+    return -1;
+    }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveUserConf(const USER_CONF & conf, const string & login) const
+{
+string param;
+string res;
+
+strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDetailStat = %d, "\
+    "AlwaysOnline=%d, Tariff='%s', Address='%s', Phone='%s', Email='%s', "\
+    "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ", 
+    conf.password.c_str(),
+    conf.passive,
+    conf.disabled,
+    conf.disabledDetailStat,
+    conf.alwaysOnline,
+    conf.tariffName.c_str(),
+    (ReplaceStr(conf.address,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.phone,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.email,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.note,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.realName,badSyms,repSym)).c_str(),
+    (ReplaceStr(conf.group,badSyms,repSym)).c_str(),
+    conf.credit,
+    conf.nextTariff.c_str()
+    );
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    strprintf(&param, " Userdata%d='%s',", i, 
+        (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
+    res += param;
+    }
+    
+strprintf(&param, " CreditExpire=%d,", conf.creditExpire);
+res += param;
+
+stringstream ipStr;
+ipStr << conf.ips;
+
+strprintf(&param, " IP='%s'", ipStr.str().c_str());
+res += param;
+
+strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't save user conf:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveUserStat(const USER_STAT & stat, const string & login) const
+{
+string param;
+string res;
+
+res = "UPDATE users SET";
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, " D%d=%lld,", i, stat.down[i]);
+    res += param;
+
+    strprintf(&param, " U%d=%lld,", i, stat.up[i]);
+    res += param;
+    }
+
+strprintf(&param, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
+    " PassiveTime=%d, LastActivityTime=%d", 
+    stat.cash,
+    stat.freeMb,
+    stat.lastCashAdd,
+    stat.lastCashAddTime,
+    stat.passiveTime,
+    stat.lastActivityTime
+    );
+res += param;
+
+strprintf(&param, " WHERE login='%s' LIMIT 1", login.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't save user stat:\n";
+//    errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteLogString(const string & str, const string & login) const
+{
+string res, tempStr;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+lt = localtime(&t);
+
+MYSQL_RES* result;
+MYSQL * sock;
+strprintf(&tempStr, "logs_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
+if (!(sock=MysqlConnect())){
+    errorStr = "Couldn't connect to Server";
+    return -1;
+}
+if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
+{
+    errorStr = "Couldn't get table " + tempStr + ":\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int num_rows =  mysql_num_rows(result);
+
+mysql_free_result(result);
+
+if (num_rows < 1)
+{
+    sprintf(qbuf,"CREATE TABLE logs_%02d_%4d (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)",
+    lt->tm_mon+1, lt->tm_year+1900);
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create WriteDetailedStat table:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+strprintf(&res, "%s -- %s",LogDate(t), str.c_str());
+
+string send;
+
+strprintf(&send,"INSERT INTO logs_%02d_%4d SET login='%s', text='%s'",
+        lt->tm_mon+1, lt->tm_year+1900,
+    login.c_str(), (ReplaceStr(res,badSyms,repSym)).c_str());
+
+if(MysqlQuery(send.c_str(),sock))
+{
+    errorStr = "Couldn't write log string:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+mysql_close(sock);
+return 0;
+
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserChgLog(const string & login,
+                                 const string & admLogin,
+                                 uint32_t       admIP,
+                                 const string & paramName,
+                                 const string & oldValue,
+                                 const string & newValue,
+                                 const string & message) const
+{
+string userLogMsg = "Admin \'" + admLogin + "\', " + inet_ntostring(admIP) + ": \'"
+    + paramName + "\' parameter changed from \'" + oldValue +
+    "\' to \'" + newValue + "\'. " + message;
+
+return WriteLogString(userLogMsg, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserConnect(const string & login, uint32_t ip) const
+{
+string logStr = "Connect, " + inet_ntostring(ip);
+return WriteLogString(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteUserDisconnect(const string & login,
+                                     const DIR_TRAFF & up,
+                                     const DIR_TRAFF & down,
+                                     const DIR_TRAFF & sessionUp,
+                                     const DIR_TRAFF & sessionDown,
+                                     double cash,
+                                     double freeMb,
+                                     const std::string & reason) const
+{
+string logStr = "Disconnect, ";
+stringstream sssu;
+stringstream sssd;
+stringstream ssmu;
+stringstream ssmd;
+stringstream sscash;
+
+ssmu << up;
+ssmd << down;
+
+sssu << sessionUp;
+sssd << sessionDown;
+
+sscash << cash;
+
+logStr += " session upload: \'";
+logStr += sssu.str();
+logStr += "\' session download: \'";
+logStr += sssd.str();
+logStr += "\' month upload: \'";
+logStr += ssmu.str();
+logStr += "\' month download: \'";
+logStr += ssmd.str();
+logStr += "\' cash: \'";
+logStr += sscash.str();
+logStr += "\'";
+
+return WriteLogString(logStr, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, 
+                                const string & login) const
+{
+string param, res;
+
+strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,", 
+    login.c_str(), month+1, year+1900);
+    
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, " U%d=%lld,", i, stat.up[i]); 
+    res += param;
+
+    strprintf(&param, " D%d=%lld,", i, stat.down[i]);        
+    res += param;
+    }
+    
+strprintf(&param, " cash=%f", stat.cash);        
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't SaveMonthStat:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::AddAdmin(const string & login) const
+{
+sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::DelAdmin(const string & login) const
+{
+sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------*/
+int MYSQL_STORE::SaveAdmin(const ADMIN_CONF & ac) const
+{
+char passwordE[2 * ADM_PASSWD_LEN + 2];
+char pass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+
+memset(pass, 0, sizeof(pass));
+memset(adminPass, 0, sizeof(adminPass));
+
+BLOWFISH_CTX ctx;
+EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+adminPass[ADM_PASSWD_LEN - 1] = 0;
+
+for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+    {
+    EncodeString(pass + 8*i, adminPass + 8*i, &ctx);
+    }
+
+pass[ADM_PASSWD_LEN - 1] = 0;
+Encode12(passwordE, pass, ADM_PASSWD_LEN);
+
+sprintf(qbuf,"UPDATE admins SET password='%s', ChgConf=%d, ChgPassword=%d, "\
+    "ChgStat=%d, ChgCash=%d, UsrAddDel=%d, ChgTariff=%d, ChgAdmin=%d "\
+    "WHERE login='%s' LIMIT 1", 
+    passwordE,
+    ac.priv.userConf,
+    ac.priv.userPasswd,
+    ac.priv.userStat,
+    ac.priv.userCash,
+    ac.priv.userAddDel,
+    ac.priv.tariffChg,
+    ac.priv.adminChg,
+    ac.login.c_str()
+    );
+
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't save admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreAdmin(ADMIN_CONF * ac, const string & login) const
+{
+char pass[ADM_PASSWD_LEN + 1];
+char password[ADM_PASSWD_LEN + 1];
+char passwordE[2*ADM_PASSWD_LEN + 2];
+BLOWFISH_CTX ctx;
+
+string p;
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't restore admin:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore admin:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if ( mysql_num_rows(res) == 0)
+{
+    mysql_free_result(res);
+    errorStr = "Couldn't restore admin as couldn't found him in table.\n";
+    mysql_close(sock);
+    return -1;
+}
+  
+row = mysql_fetch_row(res);
+
+p = row[1];
+int a;
+
+if(p.length() == 0)
+{
+    mysql_free_result(res);
+    errorStr = "Error in parameter password";
+    mysql_close(sock);
+    return -1;
+}
+
+memset(passwordE, 0, sizeof(passwordE));
+strncpy(passwordE, p.c_str(), 2*ADM_PASSWD_LEN);
+
+memset(pass, 0, sizeof(pass));
+
+if (passwordE[0] != 0)
+    {
+    Decode21(pass, passwordE);
+    EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+
+    for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
+        {
+        DecodeString(password + 8*i, pass + 8*i, &ctx);
+        }
+    }
+else
+    {
+    password[0] = 0;
+    }
+
+ac->password = password;
+
+if (GetInt(row[2], &a, 0) == 0) 
+    ac->priv.userConf = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgConf";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[3], &a, 0) == 0) 
+    ac->priv.userPasswd = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgPassword";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[4], &a, 0) == 0) 
+    ac->priv.userStat = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgStat";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[5], &a, 0) == 0) 
+    ac->priv.userCash = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgCash";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[6], &a, 0) == 0) 
+    ac->priv.userAddDel = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter UsrAddDel";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[7], &a, 0) == 0) 
+    ac->priv.tariffChg = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgTariff";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetInt(row[8], &a, 0) == 0) 
+    ac->priv.adminChg = a;
+else
+    {
+    mysql_free_result(res);
+    errorStr = "Error in parameter ChgAdmin";
+    mysql_close(sock);
+    return -1;
+    }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddTariff(const string & name) const
+{
+sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add tariff:\n";
+//    errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelTariff(const string & name) const
+{
+sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete tariff: ";
+//    errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::RestoreTariff(TARIFF_DATA * td, const string & tariffName) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't restore Tariff:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't restore Tariff:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+string str;
+td->tariffConf.name = tariffName;
+
+row = mysql_fetch_row(res);
+
+string param;
+for (int i = 0; i<DIR_NUM; i++)
+    {
+    strprintf(&param, "Time%d", i);
+    str = row[6+i*8];
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    ParseTariffTimeStr(str.c_str(), 
+                       td->dirPrice[i].hDay, 
+                       td->dirPrice[i].mDay, 
+                       td->dirPrice[i].hNight, 
+                       td->dirPrice[i].mNight);
+
+    strprintf(&param, "PriceDayA%d", i);
+    if (GetDouble(row[1+i*8], &td->dirPrice[i].priceDayA, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceDayA /= (1024*1024);
+
+    strprintf(&param, "PriceDayB%d", i);
+    if (GetDouble(row[2+i*8], &td->dirPrice[i].priceDayB, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceDayB /= (1024*1024);
+
+    strprintf(&param, "PriceNightA%d", i);
+    if (GetDouble(row[3+i*8], &td->dirPrice[i].priceNightA, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceNightA /= (1024*1024);
+
+    strprintf(&param, "PriceNightB%d", i);
+    if (GetDouble(row[4+i*8], &td->dirPrice[i].priceNightB, 0.0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    td->dirPrice[i].priceNightB /= (1024*1024);
+
+    strprintf(&param, "Threshold%d", i);
+    if (GetInt(row[5+i*8], &td->dirPrice[i].threshold, 0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    strprintf(&param, "SinglePrice%d", i);
+    if (GetInt(row[8+i*8], &td->dirPrice[i].singlePrice, 0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    strprintf(&param, "NoDiscount%d", i);
+    if (GetInt(row[7+i*8], &td->dirPrice[i].noDiscount, 0) < 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+    }//main for
+
+if (GetDouble(row[2+8*DIR_NUM], &td->tariffConf.fee, 0.0) < 0)
+    {
+    mysql_free_result(res);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter Fee";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[3+8*DIR_NUM], &td->tariffConf.free, 0.0) < 0)
+    {
+    mysql_free_result(res);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter Free";
+    mysql_close(sock);
+    return -1;
+    }
+
+if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
+    {
+    mysql_free_result(res);
+    errorStr = "Cannot read tariff " + tariffName + ". Parameter PassiveCost";
+    mysql_close(sock);
+    return -1;
+    }
+
+    str = row[4+8*DIR_NUM];
+    param = "TraffType";
+    
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+if (!strcasecmp(str.c_str(), "up"))
+    td->tariffConf.traffType = TRAFF_UP;
+else
+    if (!strcasecmp(str.c_str(), "down"))
+        td->tariffConf.traffType = TRAFF_DOWN;
+    else
+        if (!strcasecmp(str.c_str(), "up+down"))
+            td->tariffConf.traffType = TRAFF_UP_DOWN;
+        else
+            if (!strcasecmp(str.c_str(), "max"))
+                td->tariffConf.traffType = TRAFF_MAX;
+            else
+                {
+                mysql_free_result(res);
+                errorStr = "Cannot read tariff " + tariffName + ". Parameter TraffType incorrect";
+                mysql_close(sock);
+                return -1;
+                }
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::SaveTariff(const TARIFF_DATA & td, const string & tariffName) const
+{
+string param;
+
+string res="UPDATE tariffs SET";
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    strprintf(&param, " PriceDayA%d=%f,", i, 
+        td.dirPrice[i].priceDayA * pt_mega);
+    res += param;
+
+    strprintf(&param, " PriceDayB%d=%f,", i, 
+        td.dirPrice[i].priceDayB * pt_mega);        
+    res += param;
+        
+    strprintf(&param, " PriceNightA%d=%f,", i,
+        td.dirPrice[i].priceNightA * pt_mega);
+    res += param;
+
+    strprintf(&param, " PriceNightB%d=%f,", i, 
+        td.dirPrice[i].priceNightB * pt_mega);
+    res += param;
+        
+    strprintf(&param, " Threshold%d=%d,", i, 
+        td.dirPrice[i].threshold);
+    res += param;
+
+    string s;
+    strprintf(&param, " Time%d", i);
+
+    strprintf(&s, "%0d:%0d-%0d:%0d", 
+            td.dirPrice[i].hDay,
+            td.dirPrice[i].mDay,
+            td.dirPrice[i].hNight,
+            td.dirPrice[i].mNight);
+
+    res += (param + "='" + s + "',");
+
+    strprintf(&param, " NoDiscount%d=%d,", i, 
+        td.dirPrice[i].noDiscount);
+    res += param;
+
+    strprintf(&param, " SinglePrice%d=%d,", i, 
+        td.dirPrice[i].singlePrice);
+    res += param;
+    }
+
+strprintf(&param, " PassiveCost=%f,", td.tariffConf.passiveCost);
+res += param;
+
+strprintf(&param, " Fee=%f,", td.tariffConf.fee);
+res += param;
+
+strprintf(&param, " Free=%f,", td.tariffConf.free);
+res += param;
+
+switch (td.tariffConf.traffType)
+    {
+    case TRAFF_UP:
+        res += " TraffType='up'";
+        break;
+    case TRAFF_DOWN:
+        res += " TraffType='down'";
+        break;
+    case TRAFF_UP_DOWN:
+        res += " TraffType='up+down'";
+        break;
+    case TRAFF_MAX:
+        res += " TraffType='max'";
+        break;
+    }
+strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
+res += param;
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't save admin:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree, 
+                                   time_t lastStat, 
+                                   const string & login) const
+{
+string res, stTime, endTime, tempStr;
+time_t t;
+tm * lt;
+
+t = time(NULL);
+lt = localtime(&t);
+
+if (lt->tm_hour == 0 && lt->tm_min <= 5)
+    {
+        t -= 3600 * 24;
+        lt = localtime(&t);
+    }
+
+MYSQL_RES* result;
+MYSQL * sock;
+strprintf(&tempStr, "detailstat_%02d_%4d", lt->tm_mon+1, lt->tm_year+1900);
+
+if (!(sock=MysqlConnect())){
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(result=mysql_list_tables(sock,tempStr.c_str() )))
+{
+    errorStr = "Couldn't get table " + tempStr + ":\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int num_rows =  mysql_num_rows(result);
+
+mysql_free_result(result);
+
+if (num_rows < 1)
+{
+    sprintf(qbuf,"CREATE TABLE detailstat_%02d_%4d (login VARCHAR(40) DEFAULT '',"\
+        "day TINYINT DEFAULT 0,startTime TIME,endTime TIME,"\
+        "IP VARCHAR(17) DEFAULT '',dir INT DEFAULT 0,"\
+        "down BIGINT DEFAULT 0,up BIGINT DEFAULT 0, cash DOUBLE DEFAULT 0.0, INDEX (login), INDEX(dir), INDEX(day), INDEX(IP))",
+    lt->tm_mon+1, lt->tm_year+1900);
+    
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't create WriteDetailedStat table:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+}
+
+struct tm * lt1;
+struct tm * lt2;
+
+lt1 = localtime(&lastStat);
+
+int h1, m1, s1;
+int h2, m2, s2;
+
+h1 = lt1->tm_hour;
+m1 = lt1->tm_min;
+s1 = lt1->tm_sec;
+
+lt2 = localtime(&t);
+
+h2 = lt2->tm_hour;
+m2 = lt2->tm_min;
+s2 = lt2->tm_sec;
+    
+strprintf(&stTime, "%02d:%02d:%02d", h1, m1, s1);
+strprintf(&endTime, "%02d:%02d:%02d", h2, m2, s2);
+
+strprintf(&res,"INSERT INTO detailstat_%02d_%4d SET login='%s',"\
+    "day=%d,startTime='%s',endTime='%s',", 
+    lt->tm_mon+1, lt->tm_year+1900,
+    login.c_str(),
+    lt->tm_mday,
+    stTime.c_str(),
+    endTime.c_str()
+    );
+
+int retRes;
+map<IP_DIR_PAIR, STAT_NODE>::const_iterator stIter;
+stIter = statTree->begin();
+
+while (stIter != statTree->end())
+    {
+        strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f", 
+                inet_ntostring(stIter->first.ip).c_str(),
+                stIter->first.dir, 
+                stIter->second.down, 
+                stIter->second.up, 
+                stIter->second.cash
+            );
+    
+        if( (retRes = MysqlQuery((res+tempStr).c_str(),sock)) )
+        {
+            errorStr = "Couldn't insert data in WriteDetailedStat:\n";
+            errorStr += mysql_error(sock);
+            mysql_close(sock);
+            return -1;
+        }
+
+        result=mysql_store_result(sock);
+        if(result)
+            mysql_free_result(result);
+
+        ++stIter;
+    }
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::AddMessage(STG_MSG * msg, const string & login) const
+{
+struct timeval tv;
+
+gettimeofday(&tv, NULL);
+
+msg->header.id = ((long long)tv.tv_sec) * 1000000 + ((long long)tv.tv_usec);
+
+sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld", 
+    login.c_str(),
+    (long long)msg->header.id
+    );
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't add message:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return EditMessage(*msg, login);
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::EditMessage(const STG_MSG & msg, const string & login) const
+{
+string res;
+
+strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
+    "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
+    "WHERE login='%s' AND id=%lld LIMIT 1", 
+    msg.header.type,
+    msg.header.lastSendTime,
+    msg.header.creationTime,
+    msg.header.showTime,
+    msg.header.repeat,
+    msg.header.repeatPeriod,
+    (ReplaceStr(msg.text,badSyms,repSym)).c_str(),
+    login.c_str(),
+    (long long)msg.header.id
+    );
+
+if(MysqlSetQuery(res.c_str()))
+{
+    errorStr = "Couldn't edit message:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetMessage(uint64_t id, STG_MSG * msg, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+
+sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%lld LIMIT 1",
+    login.c_str(), id);
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't GetMessage:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't GetMessage:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+row = mysql_fetch_row(res);
+
+if(row[2]&&str2x(row[2], msg->header.type))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[3] && str2x(row[3], msg->header.lastSendTime))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[4] && str2x(row[4], msg->header.creationTime))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[5] && str2x(row[5], msg->header.showTime))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[6] && str2x(row[6], msg->header.repeat))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+if(row[7] && str2x(row[7], msg->header.repeatPeriod))
+{
+    mysql_free_result(res);
+    errorStr = "Invalid value in message header for user: " + login;
+    mysql_close(sock);
+    return -1;
+}
+
+msg->header.id = id;
+msg->text = row[8];
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::DelMessage(uint64_t id, const string & login) const
+{
+sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1", 
+    login.c_str(),(long long)id);
+    
+if(MysqlSetQuery(qbuf))
+{
+    errorStr = "Couldn't delete Message:\n";
+    //errorStr += mysql_error(sock);
+    return -1;
+}
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int MYSQL_STORE::GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const
+{
+MYSQL_RES *res;
+MYSQL_ROW row;
+MYSQL * sock;
+sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
+    
+if(MysqlGetQuery(qbuf,sock))
+{
+    errorStr = "Couldn't GetMessageHdrs:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+if (!(res=mysql_store_result(sock)))
+{
+    errorStr = "Couldn't GetMessageHdrs:\n";
+    errorStr += mysql_error(sock);
+    mysql_close(sock);
+    return -1;
+}
+
+unsigned int i, num_rows =  mysql_num_rows(res);
+long long int unsigned id = 0;
+
+for (i=0; i<num_rows; i++)
+{
+    row = mysql_fetch_row(res);
+    if (str2x(row[1], id))
+        continue;
+    
+    STG_MSG_HDR hdr;
+    if (row[2]) 
+        if(str2x(row[2], hdr.type))
+            continue;
+
+    if (row[3])
+        if(str2x(row[3], hdr.lastSendTime))
+            continue;
+
+    if (row[4])
+        if(str2x(row[4], hdr.creationTime))
+            continue;
+
+    if (row[5])
+        if(str2x(row[5], hdr.showTime))
+            continue;
+
+    if (row[6])
+        if(str2x(row[6], hdr.repeat))
+            continue;
+
+    if (row[7])
+        if(str2x(row[7], hdr.repeatPeriod))
+            continue;
+
+    hdr.id = id;
+    hdrsList->push_back(hdr);
+}
+
+mysql_free_result(res);
+mysql_close(sock);
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+int MYSQL_STORE::MysqlSetQuery(const char * Query) const {
+
+    MYSQL * sock;
+    int ret=MysqlGetQuery(Query,sock);
+    mysql_close(sock);
+    return ret;
+}
+//-----------------------------------------------------------------------------
+int  MYSQL_STORE::MysqlGetQuery(const char * Query,MYSQL * & sock) const {
+    if (!(sock=MysqlConnect())) {
+        return -1;
+    }
+    return   MysqlQuery(Query,sock);
+}
+//-----------------------------------------------------------------------------
+MYSQL *  MYSQL_STORE::MysqlConnect() const {
+    MYSQL * sock;
+    if ( !(sock=mysql_init(NULL)) ){
+        errorStr= "mysql init susck\n";
+        return NULL;
+    }
+    if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
+            storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
+            0,0,NULL,0)))
+        {
+            errorStr = "Couldn't connect to mysql engine! With error:\n";
+            errorStr += mysql_error(sock);
+            return NULL;
+        }
+    else{
+         if(mysql_select_db(sock, storeSettings.GetDBName().c_str())){
+             errorStr = "Database lost !\n";
+             return NULL;
+         }
+    }
+    return sock;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/store/mysql/mysql_store.h b/projects/stargazer/plugins/store/mysql/mysql_store.h
new file mode 100644 (file)
index 0000000..83a30e6
--- /dev/null
@@ -0,0 +1,144 @@
+ /*
+ $Revision: 1.4 $
+ $Date: 2010/01/19 11:07:57 $
+ */
+
+
+#ifndef FILE_STORE_H
+#define FILE_STORE_H
+
+#include <string>
+
+#include "base_settings.h"
+#include "base_store.h"
+#include "user_traff.h"
+#include <mysql/mysql.h>
+
+using namespace std;
+//-----------------------------------------------------------------------------
+extern "C" BASE_STORE * GetStore();
+//-----------------------------------------------------------------------------
+class MYSQL_STORE_SETTINGS//: public BASE_SETTINGS
+{
+public:
+    MYSQL_STORE_SETTINGS();
+    virtual ~MYSQL_STORE_SETTINGS();
+    virtual int ParseSettings(const MODULE_SETTINGS & s);
+    virtual const string & GetStrError() const;
+
+    string  GetDBUser() const;
+    string  GetDBPassword() const;
+    string  GetDBHost() const;
+    string  GetDBName() const;
+
+private:
+    const MODULE_SETTINGS * settings;
+
+    int     ParseParam(const vector<PARAM_VALUE> & moduleParams, 
+                       const string & name, string & result);
+
+       string  errorStr;
+
+    string  dbUser;
+    string  dbPass;
+       string  dbName;
+    string  dbHost;
+};
+//-----------------------------------------------------------------------------
+class MYSQL_STORE: public BASE_STORE
+{
+public:
+    MYSQL_STORE();
+    virtual ~MYSQL_STORE();
+    virtual const string & GetStrError() const;
+
+    //User
+    virtual int GetUsersList(vector<string> * usersList) const;
+    virtual int AddUser(const string & login) const;
+    virtual int DelUser(const string & login) const;
+    virtual int SaveUserStat(const USER_STAT & stat, const string & login) const;
+    virtual int SaveUserConf(const USER_CONF & conf, const string & login) const;
+    virtual int RestoreUserStat(USER_STAT * stat, const string & login) const;
+    virtual int RestoreUserConf(USER_CONF * conf, const string & login) const;
+    virtual int WriteUserChgLog(const string & login,
+                                const string & admLogin,
+                                uint32_t       admIP,
+                                const string & paramName,
+                                const string & oldValue,
+                                const string & newValue,
+                                const string & message = "") const;
+    virtual int WriteUserConnect(const string & login, uint32_t ip) const;
+    virtual int WriteUserDisconnect(const string & login,
+                                    const DIR_TRAFF & up,
+                                    const DIR_TRAFF & down,
+                                    const DIR_TRAFF & sessionUp,
+                                    const DIR_TRAFF & sessionDown,
+                                    double cash,
+                                    double freeMb,
+                                    const std::string & reason) const;
+
+    virtual int WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                  time_t lastStat,
+                                  const string & login) const;
+
+    virtual int AddMessage(STG_MSG * msg, const string & login) const;
+    virtual int EditMessage(const STG_MSG & msg, const string & login) const;
+    virtual int GetMessage(uint64_t id, STG_MSG * msg, const string & login) const;
+    virtual int DelMessage(uint64_t id, const string & login) const;
+    virtual int GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList, const string & login) const;
+
+    virtual int SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const;
+
+    //Admin
+    virtual int GetAdminsList(vector<string> * adminsList) const;
+    virtual int AddAdmin(const string & login) const;
+    virtual int DelAdmin(const string & login) const;
+    virtual int RestoreAdmin(ADMIN_CONF * ac, const string & login) const;
+    virtual int SaveAdmin(const ADMIN_CONF & ac) const;
+
+    //Tariff
+    virtual int GetTariffsList(vector<string> * tariffsList) const;
+    virtual int AddTariff(const string & name) const;
+    virtual int DelTariff(const string & name) const;
+    virtual int SaveTariff(const TARIFF_DATA & td, const string & tariffName) const;
+    virtual int RestoreTariff(TARIFF_DATA * td, const string & tariffName) const;
+
+    //Corparation
+    virtual int GetCorpsList(vector<string> *) const {return 0;};
+    virtual int SaveCorp(const CORP_CONF &) const {return 0;};
+    virtual int RestoreCorp(CORP_CONF *, const string &) const {return 0;};
+    virtual int AddCorp(const string &) const {return 0;};
+    virtual int DelCorp(const string &) const {return 0;};
+
+    // Services
+    virtual int GetServicesList(vector<string> *) const {return 0;};
+    virtual int SaveService(const SERVICE_CONF &) const {return 0;};
+    virtual int RestoreService(SERVICE_CONF *, const string &) const {return 0;};
+    virtual int AddService(const string &) const {return 0;};
+    virtual int DelService(const string &) const {return 0;};
+
+    //virtual BASE_SETTINGS * GetStoreSettings();
+    virtual void            SetSettings(const MODULE_SETTINGS & s);
+    virtual int             ParseSettings();
+    virtual const string &  GetVersion() const;
+
+private:
+    virtual int WriteLogString(const string & str, const string & login) const;
+       int GetAllParams(vector<string> * ParamList, const string & table, const string & name) const;
+       int CheckAllTables(MYSQL * sock);
+       bool IsTablePresent(const string & str,MYSQL * sock);
+    mutable string          errorStr;
+//    int                                              Reconnect();
+    int                                                MysqlQuery(const char* sQuery,MYSQL * sock) const;
+    int                     MysqlGetQuery(const char * Query,MYSQL * & sock) const;
+    int                     MysqlSetQuery(const char * Query) const;
+    MYSQL  *                MysqlConnect() const ;
+    string                  version;
+    MYSQL_STORE_SETTINGS    storeSettings;
+    MODULE_SETTINGS         settings;
+       //mutable MYSQL                                 mysql;
+       //mutable MYSQL*                                        sock;
+};
+//-----------------------------------------------------------------------------
+
+#endif //FILE_STORE_H
diff --git a/projects/stargazer/plugins/store/postgresql/Makefile b/projects/stargazer/plugins/store/postgresql/Makefile
new file mode 100644 (file)
index 0000000..522058d
--- /dev/null
@@ -0,0 +1,29 @@
+###############################################################################
+# $Id: Makefile,v 1.4 2010/04/26 12:44:42 faust Exp $
+###############################################################################
+
+include ../../../../../Makefile.conf
+
+PROG = mod_store_postgresql.so
+
+SRCS = ./postgresql_store.cpp \
+       ./postgresql_store_admins.cpp \
+       ./postgresql_store_corporations.cpp \
+       ./postgresql_store_messages.cpp \
+       ./postgresql_store_services.cpp \
+       ./postgresql_store_tariffs.cpp \
+       ./postgresql_store_users.cpp \
+       ./postgresql_store_utils.cpp
+
+STGLIBS = -lstg_common -lstg_crypto
+
+PG_CFLAGS = $(shell pg_config --includedir)
+PG_LDFLAGS = $(shell pg_config --libdir)
+
+CXXFLAGS +=  -I $(PG_CFLAGS)
+LDFLAGS += -L $(PG_LDFLAGS)
+
+LIBS += -lpq
+
+include ../../Makefile.in
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store.cpp
new file mode 100644 (file)
index 0000000..e316bea
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *    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>
+ */
+
+/*
+ *  This file contains a realization of a base postgresql-storage plugin class
+ *
+ *  v. 1.3
+ *  FreeMb logging on dosconnects added
+ *
+ *  v. 1.2
+ *  Reconnection on faults added
+ *
+ *  v. 1.1
+ *  tb_stats removed
+ *
+ *  v. 1.0
+ *  Initial implementation
+ *
+ *  $Revision: 1.5 $
+ *  $Date: 2010/01/06 10:43:48 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include <libpq-fe.h>
+
+#include "postgresql_store.h"
+#include "postgresql_store_utils.h"
+#include "base_settings.h"
+
+class POSTGRESQL_STORE_CREATOR
+{
+public:
+    POSTGRESQL_STORE_CREATOR()
+        : pqStore(new POSTGRESQL_STORE())
+        {
+        };
+    ~POSTGRESQL_STORE_CREATOR()
+        {
+        delete pqStore;
+        };
+    POSTGRESQL_STORE * GetStore() { return pqStore; };
+private:
+    POSTGRESQL_STORE * pqStore;
+} pqStoreeCreator;
+
+//-----------------------------------------------------------------------------
+BASE_STORE * GetStore()
+{
+return pqStoreeCreator.GetStore();
+}
+
+//-----------------------------------------------------------------------------
+POSTGRESQL_STORE::POSTGRESQL_STORE()
+    : connection(NULL)
+{
+server = "localhost";
+database = "stargazer";
+user = "stg";
+password = "123456";
+versionString = "postgresql_store v.1.3";
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+POSTGRESQL_STORE::~POSTGRESQL_STORE()
+{
+if (connection)
+    {
+    PQfinish(connection);
+    }
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::ParseSettings()
+{
+std::vector<PARAM_VALUE>::iterator i;
+string s;
+
+for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
+    {
+    s = i->param;
+    std::transform(s.begin(), s.end(), s.begin(), ToLower());
+    if (s == "server")
+        {
+        server = *(i->value.begin());
+        }
+    if (s == "database")
+        {
+        database = *(i->value.begin());
+        }
+    if (s == "user")
+        {
+        user = *(i->value.begin());
+        }
+    if (s == "password")
+        {
+        password = *(i->value.begin());
+        }
+    }
+
+clientEncoding = "KOI8";
+
+return Connect();
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::Connect()
+{
+std::string params;
+params = "host=" + server + " "
+       + "dbname=" + database + " "
+       + "user=" + user + " "
+       + "password=" + password;
+
+connection = PQconnectdb(params.c_str());
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    strError = PQerrorMessage(connection);
+    printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
+    return 1;
+    }
+
+if (PQsetClientEncoding(connection, clientEncoding.c_str()))
+    {
+    strError = PQerrorMessage(connection);
+    printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
+    return 1;
+    }
+
+return CheckVersion();
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::Reset() const
+{
+PQreset(connection);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    strError = PQerrorMessage(connection);
+    printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
+    return 1;
+    }
+
+if (PQsetClientEncoding(connection, clientEncoding.c_str()))
+    {
+    strError = PQerrorMessage(connection);
+    printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
+    return 1;
+    }
+
+return CheckVersion();
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::CheckVersion() const
+{
+
+if (StartTransaction())
+    {
+    strError = "Failed to start transaction";
+    printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PGresult * result = PQexec(connection, "SELECT MAX(version) FROM tb_info");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n");
+    RollbackTransaction();
+    return -1;
+    }
+
+if (str2x(PQgetvalue(result, 0, 0), version))
+    {
+    strError = "Invalid DB version";
+    PQclear(result);
+    RollbackTransaction();
+    printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PQclear(result);
+
+if (version < DB_MIN_VERSION)
+    {
+    strError = "DB version too old";
+    RollbackTransaction();
+    printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+if (version < 6)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): I recommend you to upgrade your DB to higher version to support FreeMb logging on disconnect. Current version is %d\n", version);
+    }
+
+if (CommitTransaction())
+    {
+    strError = "Failed to commit transaction";
+    printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store.h b/projects/stargazer/plugins/store/postgresql/postgresql_store.h
new file mode 100644 (file)
index 0000000..67119db
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *    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>
+ */
+
+/*
+ *  PostgreSQL storage class definition
+ *
+ *  $Revision: 1.8 $
+ *  $Date: 2010/01/19 11:06:53 $
+ *
+ */
+
+#ifndef POSTGRESQL_STORE_H
+#define POSTGRESQL_STORE_H
+
+#include <libpq-fe.h>
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "base_store.h"
+
+// Minimal DB version is 5
+// Recommended DB version is 6 (support FreeMb logging on disconnects)
+#define DB_MIN_VERSION 5
+
+extern "C" BASE_STORE * GetStore();
+
+class POSTGRESQL_STORE : public BASE_STORE {
+public:
+    POSTGRESQL_STORE();
+    virtual ~POSTGRESQL_STORE();
+
+    // Users
+    int GetUsersList(std::vector<std::string> * usersList) const;
+    int AddUser(const std::string & login) const;
+    int DelUser(const std::string & login) const;
+    int SaveUserStat(const USER_STAT & stat, const std::string & login) const;
+    int SaveUserConf(const USER_CONF & conf, const std::string & login) const;
+    int RestoreUserStat(USER_STAT * stat, const std::string & login) const;
+    int RestoreUserConf(USER_CONF * conf, const std::string & login) const;
+    int WriteUserChgLog(const std::string & login,
+                        const std::string & admLogin,
+                        uint32_t admIP,
+                        const std::string & paramName,
+                        const std::string & oldValue,
+                        const std::string & newValue,
+                        const std::string & message) const;
+    int WriteUserConnect(const std::string & login, uint32_t ip) const;
+    int WriteUserDisconnect(const std::string & login,
+                            const DIR_TRAFF & up,
+                            const DIR_TRAFF & down,
+                            const DIR_TRAFF & sessionUp,
+                            const DIR_TRAFF & sessionDown,
+                            double cash,
+                            double freeMb,
+                            const std::string & reason) const;
+    int WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                          time_t lastStat,
+                          const std::string & login) const;
+
+    // Messages
+    int AddMessage(STG_MSG * msg, const std::string & login) const;
+    int EditMessage(const STG_MSG & msg, const std::string & login) const;
+    int GetMessage(uint64_t id, STG_MSG * msg, const std::string & login) const;
+    int DelMessage(uint64_t id, const std::string & login) const;
+    int GetMessageHdrs(std::vector<STG_MSG_HDR> * hdrsList, const std::string & login) const;
+
+    // Stats
+    int SaveMonthStat(const USER_STAT & stat, int month, int year, const std::string  & login) const;
+
+    // Admins
+    int GetAdminsList(std::vector<std::string> * adminsList) const;
+    int SaveAdmin(const ADMIN_CONF & ac) const;
+    int RestoreAdmin(ADMIN_CONF * ac, const std::string & login) const;
+    int AddAdmin(const std::string & login) const;
+    int DelAdmin(const std::string & login) const;
+
+    // Tariffs
+    int GetTariffsList(std::vector<std::string> * tariffsList) const;
+    int AddTariff(const std::string & name) const;
+    int DelTariff(const string & name) const;
+    int SaveTariff(const TARIFF_DATA & td, const std::string & tariffName) const;
+    int RestoreTariff(TARIFF_DATA * td, const std::string & tariffName) const;
+
+    // Corporations
+    int GetCorpsList(std::vector<std::string> * corpsList) const;
+    int SaveCorp(const CORP_CONF & cc) const;
+    int RestoreCorp(CORP_CONF * cc, const std::string & name) const;
+    int AddCorp(const std::string & name) const;
+    int DelCorp(const std::string & name) const;
+
+    // Services
+    int GetServicesList(std::vector<std::string> * servicesList) const;
+    int SaveService(const SERVICE_CONF & sc) const;
+    int RestoreService(SERVICE_CONF * sc, const std::string & name) const;
+    int AddService(const std::string & name) const;
+    int DelService(const std::string & name) const;
+
+    // Settings
+    inline void SetSettings(const MODULE_SETTINGS & s) { settings = s; };
+    int ParseSettings();
+
+    inline const string & GetStrError() const { return strError; };
+    inline const string & GetVersion() const { return versionString; };
+private:
+    std::string versionString;
+    mutable std::string strError;
+    std::string server;
+    std::string database;
+    std::string user;
+    std::string password;
+    std::string clientEncoding;
+    MODULE_SETTINGS settings;
+    mutable pthread_mutex_t mutex;
+    mutable int version;
+
+    PGconn * connection;
+
+    int StartTransaction() const;
+    int CommitTransaction() const;
+    int RollbackTransaction() const;
+
+    int EscapeString(std::string & value) const;
+
+    std::string Int2TS(uint32_t value) const;
+    uint32_t TS2Int(const std::string & value) const;
+
+    int SaveStat(const USER_STAT & stat, const std::string & login, int year = 0, int month = 0) const;
+
+    int SaveUserServices(uint32_t uid, const std::vector<std::string> & services) const;
+    int SaveUserData(uint32_t uid, const std::vector<std::string> & data) const;
+    int SaveUserIPs(uint32_t uid, const USER_IPS & ips) const;
+
+    void MakeDate(std::string & date, int year = 0, int month = 0) const;
+
+    int Connect();
+    int Reset() const;
+    int CheckVersion() const;
+};
+
+extern const volatile time_t stgTime;
+
+#endif //POSTGRESQL_STORE_H
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_admins.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_admins.cpp
new file mode 100644 (file)
index 0000000..28bfbc0
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Administrators manipulation methods
+ *
+ *  $Revision: 1.2 $
+ *  $Date: 2009/06/09 12:32:39 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+#include "postgresql_store.h"
+#include "stg_locker.h"
+#include "admin_conf.h"
+#include "blowfish.h"
+
+#define adm_enc_passwd "cjeifY8m3"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetAdminsList(std::vector<std::string> * adminsList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+result = PQexec(connection, "SELECT login FROM tb_admins");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    adminsList->push_back(PQgetvalue(result, i, 0));
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetAdminsList(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveAdmin(const ADMIN_CONF & ac) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+char encodedPass[2 * ADM_PASSWD_LEN + 2];
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+memset(cryptedPass, 0, ADM_PASSWD_LEN + 1);
+strncpy(adminPass, ac.password.c_str(), ADM_PASSWD_LEN);
+EnDecodeInit(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+    EncodeString(cryptedPass + 8 * i, adminPass + 8 * i, &ctx);
+
+cryptedPass[ADM_PASSWD_LEN] = 0;
+Encode12(encodedPass, cryptedPass, ADM_PASSWD_LEN);
+
+std::string password = encodedPass;
+std::string login = ac.login;
+
+if (EscapeString(password))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to escape password'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(login))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "UPDATE tb_admins SET "
+          << "passwd = '" << password << "', "
+          << "chg_conf = " << ac.priv.userConf << ", "
+          << "chg_password = " << ac.priv.userPasswd << ", "
+          << "chg_stat = " << ac.priv.userStat << ", "
+          << "chg_cash = " << ac.priv.userCash << ", "
+          << "usr_add_del = " << ac.priv.userAddDel << ", "
+          << "chg_tariff = " << ac.priv.tariffChg << ", "
+          << "chg_admin = " << ac.priv.adminChg << " "
+      << "WHERE login = '" << login << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveAdmin(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreAdmin(ADMIN_CONF * ac, const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+char cryptedPass[ADM_PASSWD_LEN + 1];
+char adminPass[ADM_PASSWD_LEN + 1];
+BLOWFISH_CTX ctx;
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT login, passwd, \
+                 chg_conf, chg_password, chg_stat, \
+                 chg_cash, usr_add_del, chg_tariff, \
+                 chg_admin, chg_service, chg_corporation \
+          FROM tb_admins \
+          WHERE login = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch admin's data";
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+ac->login = PQgetvalue(result, 0, 0);
+ac->password = PQgetvalue(result, 0, 1);
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 2) << " "
+      << PQgetvalue(result, 0, 3) << " "
+      << PQgetvalue(result, 0, 4) << " "
+      << PQgetvalue(result, 0, 5) << " "
+      << PQgetvalue(result, 0, 6) << " "
+      << PQgetvalue(result, 0, 7) << " "
+      << PQgetvalue(result, 0, 8) << " "
+      << PQgetvalue(result, 0, 9) << " "
+      << PQgetvalue(result, 0, 10);
+
+PQclear(result);
+
+tuple >> ac->priv.userConf
+      >> ac->priv.userPasswd
+      >> ac->priv.userStat
+      >> ac->priv.userCash
+      >> ac->priv.userAddDel
+      >> ac->priv.tariffChg
+      >> ac->priv.adminChg;
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreAdmin(): 'Failed to commit transacion'\n");
+    return -1;
+    }
+
+if (ac->password == "")
+    {
+    return 0;
+    }
+
+Decode21(cryptedPass, ac->password.c_str());
+EnDecodeInit(adm_enc_passwd, sizeof(adm_enc_passwd), &ctx);
+for (int i = 0; i < ADM_PASSWD_LEN / 8; i++)
+    {
+    DecodeString(adminPass + 8 * i, cryptedPass + 8 * i, &ctx);
+    }
+ac->password = adminPass;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddAdmin(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "INSERT INTO tb_admins \
+              (login, passwd, \
+              chg_conf, chg_password, chg_stat, \
+              chg_cash, usr_add_del, chg_tariff, \
+              chg_admin, chg_service, chg_corporation) \
+          VALUES "
+          << "('" << elogin << "', \
+              '', 0, 0, 0, 0, 0, 0, 0, 0, 0)";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddAdmin(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelAdmin(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "DELETE FROM tb_admins WHERE login = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelAdmin(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_corporations.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_corporations.cpp
new file mode 100644 (file)
index 0000000..6fa3fd5
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Corporations manipulation methods
+ *
+ *  $Revision: 1.2 $
+ *  $Date: 2009/06/09 12:32:39 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+#include "postgresql_store.h"
+#include "stg_locker.h"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetCorpsList(vector<string> * corpsList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+result = PQexec(connection, "SELECT name FROM tb_corporations");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    corpsList->push_back(PQgetvalue(result, i, 0));
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetCorpsList(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveCorp(const CORP_CONF & cc) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = cc.name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "UPDATE tb_corporations SET "
+          << "cash = " << cc.cash
+      << "WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveCorp(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreCorp(CORP_CONF * cc, const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT cash FROM tb_corporations WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch corp's data";
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0);
+
+PQclear(result);
+
+tuple >> cc->cash;
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreCorp(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddCorp(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "INSERT INTO tb_corporations \
+              (name, cash) \
+          VALUES \
+              ('" << ename << "', 0)";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddCorp(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelCorp(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "DELETE FROM tb_corporations WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelCorp(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp
new file mode 100644 (file)
index 0000000..9eeea60
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ *    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>
+ */
+
+
+/*
+ *  Messages manipualtion methods
+ *
+ *  $Revision: 1.6 $
+ *  $Date: 2009/07/15 11:19:42 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+#include "postgresql_store.h"
+#include "stg_locker.h"
+#include "stg_message.h"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddMessage(STG_MSG * msg, const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+std::string etext = msg->text;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(etext))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to escape message text'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT sp_add_message("
+      << "'" << elogin << "', "
+      << "CAST(1 AS SMALLINT), " // Here need to be a version, but, it's uninitiated actually
+      << "CAST(" << msg->header.type << " AS SMALLINT), "
+      << "CAST('" << Int2TS(msg->header.lastSendTime) << "' AS TIMESTAMP), "
+      << "CAST('" << Int2TS(msg->header.creationTime) << "' AS TIMESTAMP), "
+      << msg->header.showTime << ", "
+      << "CAST(" << msg->header.repeat << " AS SMALLINT), "
+      << msg->header.repeatPeriod << ", "
+      << "'" << etext << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch newlly added message ID";
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0);
+
+PQclear(result);
+
+tuple >> msg->header.id;
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddMessage(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::EditMessage(const STG_MSG & msg,
+                                  const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+std::string etext = msg.text;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(etext))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to escape message text'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "UPDATE tb_messages SET "
+          << "fk_user = (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
+          << "ver = " << msg.header.ver << ", "
+          << "msg_type = " << msg.header.type << ", "
+          << "last_send_time = CAST('" << Int2TS(msg.header.lastSendTime) << "' AS TIMESTAMP), "
+          << "creation_time = CAST('" << Int2TS(msg.header.creationTime) << "' AS TIMESTAMP), "
+          << "show_time = " << msg.header.showTime << ", "
+          << "repeat = " << msg.header.repeat << ", "
+          << "repeat_period = " << msg.header.repeatPeriod << ", "
+          << "msg_text = '" << etext << "' "
+      << "WHERE pk_message = " << msg.header.id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::EditMessage(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetMessage(uint64_t id,
+                               STG_MSG * msg,
+                               const string &) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+string login;
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT ver, msg_type, last_send_time, \
+                 creation_time, show_time, repeat, \
+                 repeat_period, msg_text \
+          FROM tb_messages \
+          WHERE pk_message = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch message data";
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+/*std::stringstream tuple;
+
+for (int i = 0; i < 8; ++i)
+    {
+    tuple << PQgetvalue(result, 0, i) << " ";
+    }*/
+
+str2x(PQgetvalue(result, 0, 0), msg->header.ver);
+str2x(PQgetvalue(result, 0, 1), msg->header.type);
+msg->header.lastSendTime = TS2Int(PQgetvalue(result, 0, 2));
+msg->header.creationTime = TS2Int(PQgetvalue(result, 0, 3));
+str2x(PQgetvalue(result, 0, 4), msg->header.showTime);
+str2x(PQgetvalue(result, 0, 5), msg->header.repeat);
+str2x(PQgetvalue(result, 0, 6), msg->header.repeatPeriod);
+msg->text = PQgetvalue(result, 0, 7);
+
+PQclear(result);
+
+/*tuple >> msg->header.ver;
+tuple >> msg->header.type;
+tuple >> msg->header.lastSendTime;
+tuple >> msg->header.creationTime;
+tuple >> msg->header.showTime;
+tuple >> msg->header.repeat;
+tuple >> msg->header.repeatPeriod;
+tuple >> msg->text;*/
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessage(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelMessage(uint64_t id, const string &) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::stringstream query;
+query << "DELETE FROM tb_messages WHERE pk_message = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelMessage(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetMessageHdrs(vector<STG_MSG_HDR> * hdrsList,
+                                   const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT pk_message, ver, msg_type, \
+                 last_send_time, creation_time, show_time, \
+                 repeat, repeat_period \
+          FROM tb_messages \
+          WHERE fk_user IN \
+                (SELECT pk_user FROM tb_users \
+          WHERE name = '" << elogin << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    std::stringstream tuple;
+    STG_MSG_HDR header;
+    tuple << PQgetvalue(result, i, 0) << " ";
+    tuple << PQgetvalue(result, i, 1) << " ";
+    tuple << PQgetvalue(result, i, 2) << " ";
+    header.lastSendTime = TS2Int(PQgetvalue(result, i, 3));
+    header.creationTime = TS2Int(PQgetvalue(result, i, 4));
+    tuple << PQgetvalue(result, i, 5) << " ";
+    tuple << PQgetvalue(result, i, 6) << " ";
+    tuple << PQgetvalue(result, i, 7) << " ";
+
+    tuple >> header.id;
+    tuple >> header.ver;
+    tuple >> header.type;
+    tuple >> header.showTime;
+    tuple >> header.repeat;
+    tuple >> header.repeatPeriod;
+    hdrsList->push_back(header);
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetMessageHdrs(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_services.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_services.cpp
new file mode 100644 (file)
index 0000000..88b8049
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ *    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>
+ */
+
+
+/*
+ *  Services manipulation methods
+ *
+ *  $Revision: 1.2 $
+ *  $Date: 2009/06/09 12:32:40 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+#include "postgresql_store.h"
+#include "stg_locker.h"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetServicesList(vector<string> * servicesList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+result = PQexec(connection, "SELECT name FROM tb_services");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    servicesList->push_back(PQgetvalue(result, i, 0));
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetServicesList(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveService(const SERVICE_CONF & sc) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = sc.name;
+std::string ecomment = sc.comment;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(ecomment))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to escape comment'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "UPDATE tb_services SET "
+          << "comment = '" << ecomment << "', "
+          << "cost = " << sc.cost << ", "
+          << "pay_day = " << sc.payDay << " "
+      << "WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveService(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreService(SERVICE_CONF * sc,
+                                   const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT comment, cost, pay_day FROM tb_services WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch service's data";
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0) << " "
+      << PQgetvalue(result, 0, 1) << " "
+      << PQgetvalue(result, 0, 2);
+
+PQclear(result);
+
+tuple >> sc->comment
+      >> sc->cost
+      >> sc->payDay;
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreService(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddService(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::AddService(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "INSERT INTO tb_services \
+              (name, comment, cost, pay_day) \
+          VALUES \
+              ('" << ename << "', '', 0, 0)";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::AddService(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddService(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelService(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::DelService(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "DELETE FROM tb_services WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::DelService(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelService(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp
new file mode 100644 (file)
index 0000000..352dab0
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Tariffs manipulation methods
+ *
+ *  $Revision: 1.2 $
+ *  $Date: 2009/06/09 12:32:40 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <libpq-fe.h>
+
+#include "postgresql_store.h"
+#include "stg_locker.h"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetTariffsList(vector<string> * tariffsList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+result = PQexec(connection, "SELECT name FROM tb_tariffs");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    tariffsList->push_back(PQgetvalue(result, i, 0));
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddTariff(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT sp_add_tariff('" << ename << "', " << DIR_NUM << ")";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelTariff(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = name;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "DELETE FROM tb_tariffs WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveTariff(const TARIFF_DATA & td,
+                                 const string & tariffName) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = tariffName;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int32_t id, i;
+double pda, pdb, pna, pnb;
+int threshold;
+
+std::stringstream query;
+query << "SELECT pk_tariff FROM tb_tariffs WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch tariff ID";
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0);
+
+PQclear(result);
+
+tuple >> id;
+
+query.str("");
+query << "UPDATE tb_tariffs SET \
+              fee = " << td.tariffConf.fee << ", \
+              free = " << td.tariffConf.free << ", \
+              passive_cost = " << td.tariffConf.passiveCost << ", \
+              traff_type = " << td.tariffConf.traffType << " \
+          WHERE pk_tariff = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+for(i = 0; i < DIR_NUM; i++)
+    {
+
+    pda = td.dirPrice[i].priceDayA * 1024 * 1024;
+    pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
+
+    if (td.dirPrice[i].singlePrice)
+        {
+        pna = pda;
+        pnb = pdb;
+        }
+    else
+        {
+        pna = td.dirPrice[i].priceNightA * 1024 * 1024;
+        pnb = td.dirPrice[i].priceNightB * 1024 * 1024;
+        }
+
+    if (td.dirPrice[i].noDiscount)
+        {
+        threshold = 0xffFFffFF;
+        }
+    else
+        {
+        threshold = td.dirPrice[i].threshold;
+        }
+
+    std::stringstream query;
+    query << "UPDATE tb_tariffs_params SET \
+                  price_day_a = " << pda << ", \
+                  price_day_b = " << pdb << ", \
+                  price_night_a = " << pna << ", \
+                  price_night_b = " << pnb << ", \
+                  threshold = " << threshold << ", \
+                  time_day_begins = CAST('" << td.dirPrice[i].hDay
+                                            << ":"
+                                            << td.dirPrice[i].mDay << "' AS TIME), \
+                  time_day_ends = CAST('" << td.dirPrice[i].hNight
+                                          << ":"
+                                          << td.dirPrice[i].mNight << "' AS TIME) \
+             WHERE fk_tariff = " << id << " AND dir_num = " << i;
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_COMMAND_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
+        if (RollbackTransaction())
+            {
+            printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
+            }
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreTariff(TARIFF_DATA * td,
+                                  const string & tariffName) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string ename = tariffName;
+
+if (EscapeString(ename))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to escape name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+td->tariffConf.name = tariffName;
+
+std::stringstream query;
+query << "SELECT pk_tariff, \
+                 fee, \
+                free, \
+                passive_cost, \
+                traff_type \
+         FROM tb_tariffs WHERE name = '" << ename << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch tariff data";
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0) << " ";
+tuple << PQgetvalue(result, 0, 1) << " ";
+tuple << PQgetvalue(result, 0, 2) << " ";
+tuple << PQgetvalue(result, 0, 3) << " ";
+tuple << PQgetvalue(result, 0, 4) << " ";
+
+int id;
+tuple >> id;
+tuple >> td->tariffConf.fee;
+tuple >> td->tariffConf.free;
+tuple >> td->tariffConf.passiveCost;
+tuple >> td->tariffConf.traffType;
+
+PQclear(result);
+
+query.str("");
+query << "SELECT dir_num, \
+                 price_day_a, \
+                 price_day_b, \
+                price_night_a, \
+                price_night_b, \
+                threshold, \
+                EXTRACT(hour FROM time_day_begins), \
+                EXTRACT(minute FROM time_day_begins), \
+                EXTRACT(hour FROM time_day_ends), \
+                EXTRACT(minute FROM time_day_ends) \
+         FROM tb_tariffs_params \
+         WHERE fk_tariff = " << id;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+tuples = PQntuples(result);
+
+if (tuples != DIR_NUM)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Tariff params count and DIR_NUM does not feet (wanted %d, actually %d)'\n", DIR_NUM, tuples);
+    }
+
+for (int i = 0; i < std::min(tuples, DIR_NUM); ++i)
+    {
+    std::stringstream tuple;
+    tuple << PQgetvalue(result, i, 0) << " ";
+    tuple << PQgetvalue(result, i, 1) << " ";
+    tuple << PQgetvalue(result, i, 2) << " ";
+    tuple << PQgetvalue(result, i, 3) << " ";
+    tuple << PQgetvalue(result, i, 4) << " ";
+    tuple << PQgetvalue(result, i, 5) << " ";
+    tuple << PQgetvalue(result, i, 6) << " ";
+    tuple << PQgetvalue(result, i, 7) << " ";
+    tuple << PQgetvalue(result, i, 8) << " ";
+    tuple << PQgetvalue(result, i, 9) << " ";
+
+    int dir;
+
+    tuple >> dir;
+    tuple >> td->dirPrice[dir].priceDayA;
+    td->dirPrice[dir].priceDayA /= 1024 * 1024;
+    tuple >> td->dirPrice[dir].priceDayB;
+    td->dirPrice[dir].priceDayB /= 1024 * 1024;
+    tuple >> td->dirPrice[dir].priceNightA;
+    td->dirPrice[dir].priceNightA /= 1024 * 1024;
+    tuple >> td->dirPrice[dir].priceNightB;
+    td->dirPrice[dir].priceNightB /= 1024 * 1024;
+    tuple >> td->dirPrice[dir].threshold;
+    tuple >> td->dirPrice[dir].hDay;
+    tuple >> td->dirPrice[dir].mDay;
+    tuple >> td->dirPrice[dir].hNight;
+    tuple >> td->dirPrice[dir].mNight;
+
+    if (td->dirPrice[dir].priceDayA == td->dirPrice[dir].priceNightA &&
+        td->dirPrice[dir].priceDayB == td->dirPrice[dir].priceNightB)
+        {
+        td->dirPrice[dir].singlePrice = true;
+        }
+    else
+        {
+        td->dirPrice[dir].singlePrice = false;
+        }
+    if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
+        {
+        td->dirPrice[dir].noDiscount = true;
+        }
+    else
+        {
+
+        td->dirPrice[dir].noDiscount = false;
+        }
+
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
new file mode 100644 (file)
index 0000000..6a40979
--- /dev/null
@@ -0,0 +1,1565 @@
+/*
+ *    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>
+ */
+
+/*
+ *  User manipulation methods
+ *
+ *  $Revision: 1.14 $
+ *  $Date: 2010/05/07 07:26:36 $
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <ctime>
+
+#include <libpq-fe.h>
+
+#include "stg_const.h"
+#include "postgresql_store.h"
+#include "stg_locker.h"
+#include "../../../stg_timer.h"
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::GetUsersList(vector<string> * usersList) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+result = PQexec(connection, "SELECT name FROM tb_users");
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    usersList->push_back(PQgetvalue(result, i, 0));
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::AddUser(const string & name) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = name;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT sp_add_user('" << elogin << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::DelUser(const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "DELETE FROM tb_users WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserStat(const USER_STAT & stat,
+                                   const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+return SaveStat(stat, login);
+}
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveStat(const USER_STAT & stat,
+                               const string & login,
+                               int year,
+                               int month) const
+{
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "UPDATE tb_users SET "
+            "cash = " << stat.cash << ", "
+            "free_mb = " << stat.freeMb << ", "
+            "last_activity_time = CAST('" << Int2TS(stat.lastActivityTime) << "' AS TIMESTAMP), "
+            "last_cash_add = " << stat.lastCashAdd << ", "
+            "last_cash_add_time = CAST('" << Int2TS(stat.lastCashAddTime) << "' AS TIMESTAMP), "
+            "passive_time = " << stat.passiveTime << " "
+         "WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+std::string date;
+
+MakeDate(date, year, month);
+
+for (int dir = 0; dir < DIR_NUM; ++dir)
+    {
+    query.str("");
+    query << "SELECT sp_add_stats_traffic ("
+                "'" << elogin << "', "
+                "CAST('" << date << "' AS DATE), "
+                "CAST(" << dir << " AS SMALLINT), "
+                "CAST(" << stat.up[dir] << " AS BIGINT), "
+                "CAST(" << stat.down[dir] << " AS BIGINT))";
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_TUPLES_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
+        if (RollbackTransaction())
+            {
+            printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
+            }
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserConf(const USER_CONF & conf,
+                                 const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch user's ID";
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0);
+
+PQclear(result);
+
+uint32_t uid;
+
+tuple >> uid;
+
+std::string eaddress = conf.address;
+std::string eemail = conf.email;
+std::string egroup = conf.group;
+std::string enote = conf.note;
+std::string epassword = conf.password;
+std::string ephone = conf.phone;
+std::string erealname = conf.realName;
+std::string etariffname = conf.tariffName;
+std::string enexttariff = conf.nextTariff;
+std::string ecorporation = conf.corp;
+
+if (EscapeString(eaddress))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape address'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(eemail))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape email'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(egroup))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape group'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(enote))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape note'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(epassword))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape password'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(ephone))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape phone'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(erealname))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape real name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(etariffname))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape tariff name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(enexttariff))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape next tariff name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(ecorporation))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape corporation name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+query.str("");
+query << "UPDATE tb_users SET "
+             "address = '" << eaddress << "', "
+             "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
+             "credit = " << conf.credit << ", "
+             "credit_expire = CAST('" << Int2TS(conf.creditExpire) << "' AS TIMESTAMP), "
+             "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
+             "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
+             "email = '" << eemail << "', "
+             "grp = '" << egroup << "', "
+             "note = '" << enote << "', "
+             "passive = " << (conf.passive ? "'t'" : "'f'") << ", "
+             "passwd = '" << epassword << "', "
+             "phone = '" << ephone << "', "
+             "real_name = '" << erealname << "', "
+             "fk_tariff = (SELECT pk_tariff "
+                   "FROM tb_tariffs "
+                   "WHERE name = '" << etariffname << "'), "
+             "fk_tariff_change = (SELECT pk_tariff "
+                   "FROM tb_tariffs "
+                   "WHERE name = '" << enexttariff << "'), "
+             "fk_corporation = (SELECT pk_corporation "
+                   "FROM tb_corporations "
+                   "WHERE name = '" << ecorporation << "') "
+         "WHERE pk_user = " << uid;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+if (SaveUserServices(uid, conf.service))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+if (SaveUserData(uid, conf.userdata))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's data'\n");
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+if (SaveUserIPs(uid, conf.ips))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's IPs'\n");
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreUserStat(USER_STAT * stat,
+                                    const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT cash, free_mb, "
+            "last_activity_time, last_cash_add, "
+            "last_cash_add_time, passive_time "
+         "FROM tb_users "
+         "WHERE name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch user's stat";
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream tuple;
+tuple << PQgetvalue(result, 0, 0) << " ";
+tuple << PQgetvalue(result, 0, 1) << " ";
+stat->lastActivityTime = TS2Int(PQgetvalue(result, 0, 2));
+tuple << PQgetvalue(result, 0, 3) << " ";
+stat->lastCashAddTime = TS2Int(PQgetvalue(result, 0, 4));
+tuple << PQgetvalue(result, 0, 5) << " ";
+
+PQclear(result);
+
+tuple >> stat->cash
+      >> stat->freeMb
+      >> stat->lastCashAdd
+      >> stat->passiveTime;
+
+query.str("");
+
+query << "SELECT dir_num, upload, download "
+         "FROM tb_stats_traffic "
+         "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND "
+               "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP))";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    std::stringstream tuple;
+    tuple << PQgetvalue(result, i, 0) << " ";
+    tuple << PQgetvalue(result, i, 1) << " ";
+    tuple << PQgetvalue(result, i, 2) << " ";
+
+    int dir;
+
+    tuple >> dir;
+    tuple >> stat->up[dir];
+    tuple >> stat->down[dir];
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::RestoreUserConf(USER_CONF * conf,
+                                    const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin = login;
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT tb_users.pk_user, tb_users.address, tb_users.always_online, "
+                "tb_users.credit, tb_users.credit_expire, tb_users.disabled, "
+                "tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, "
+                "tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, "
+                "tb_users.real_name, tf1.name, tf2.name, tb_corporations.name "
+         "FROM tb_users LEFT JOIN tb_tariffs AS tf1 "
+                            "ON tf1.pk_tariff = tb_users.fk_tariff "
+                       "LEFT JOIN tb_tariffs AS tf2 "
+                            "ON tf2.pk_tariff = tb_users.fk_tariff_change "
+                       "LEFT JOIN tb_corporations "
+                            "ON tb_corporations.pk_corporation = tb_users.fk_corporation "
+         "WHERE tb_users.name = '" << elogin << "'";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch user's stat";
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+uint32_t uid;
+
+std::stringstream tuple;
+
+tuple << PQgetvalue(result, 0, 0) << " ";               // uid
+conf->address = PQgetvalue(result, 0, 1);               // address
+conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1);
+tuple << PQgetvalue(result, 0, 3) << " ";               // credit
+conf->creditExpire = TS2Int(PQgetvalue(result, 0, 4));  // creditExpire
+conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1);
+conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1);
+conf->email = PQgetvalue(result, 0, 7);                 // email
+conf->group = PQgetvalue(result, 0, 8);                 // group
+conf->note = PQgetvalue(result, 0, 9);                  // note
+conf->passive = !strncmp(PQgetvalue(result, 0, 10), "t", 1);
+conf->password = PQgetvalue(result, 0, 11);             // password
+conf->phone = PQgetvalue(result, 0, 12);                // phone
+conf->realName = PQgetvalue(result, 0, 13);             // realName
+conf->tariffName = PQgetvalue(result, 0, 14);           // tariffName
+conf->nextTariff = PQgetvalue(result, 0, 15);           // nextTariff
+conf->corp = PQgetvalue(result, 0, 16);                 // corp
+
+PQclear(result);
+
+if (conf->tariffName == "")
+    conf->tariffName = NO_TARIFF_NAME;
+if (conf->corp == "")
+    conf->corp = NO_CORP_NAME;
+
+tuple >> uid
+      >> conf->credit;
+
+query.str("");
+query << "SELECT name FROM tb_services "
+         "WHERE pk_service IN (SELECT fk_service "
+                              "FROM tb_users_services "
+                              "WHERE fk_user = " << uid << ")";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    conf->service.push_back(PQgetvalue(result, i, 0));
+    }
+
+PQclear(result);
+
+query.str("");
+query << "SELECT num, data "
+         "FROM tb_users_data "
+         "WHERE fk_user = " << uid;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+tuples = PQntuples(result);
+
+for (int i = 0; i < tuples; ++i)
+    {
+    int num;
+    if (str2x(PQgetvalue(result, i, 0), num))
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to convert string to int'\n");
+        }
+    else
+        {
+        conf->userdata[i] = PQgetvalue(result, i, 1);
+        }
+    }
+
+PQclear(result);
+
+query.str("");
+query << "SELECT host(ip), masklen(ip) "
+         "FROM tb_allowed_ip "
+         "WHERE fk_user = " << uid;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+tuples = PQntuples(result);
+
+conf->ips.Erase();
+for (int i = 0; i < tuples; ++i)
+    {
+    IP_MASK ipm;
+
+    int ip, mask;
+
+    ip = inet_strington(PQgetvalue(result, i, 0));
+
+    if (str2x(PQgetvalue(result, i, 1), mask))
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to fetch mask'\n");
+        continue;
+        }
+
+    ipm.ip = ip;
+    ipm.mask = mask;
+
+    conf->ips.Add(ipm);
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteUserChgLog(const string & login,
+                                    const string & admLogin,
+                                    uint32_t admIP,
+                                    const string & paramName,
+                                    const string & oldValue,
+                                    const string & newValue,
+                                    const string & message = "") const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin(login);
+std::string eadminLogin(admLogin);
+std::string eparam(paramName);
+std::string eold(oldValue);
+std::string enew(newValue);
+std::string emessage(message);
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(eadminLogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape admin's login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(eparam))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape param's name'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(eold))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape old value'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+if (EscapeString(enew))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape new value'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+query << "SELECT sp_add_param_log_entry("
+            "'" << elogin << "', "
+            "'" << eadminLogin << "', CAST('"
+            << inet_ntostring(admIP) << "/24' AS INET), "
+            "'" << eparam << "', "
+            "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+            "'" << eold << "', "
+            "'" << enew << "', "
+            "'" << emessage << "')";
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteUserConnect(const string & login, uint32_t ip) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin(login);
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+if (version < 6)
+    {
+    query << "SELECT sp_add_session_log_entry("
+                 "'" << elogin << "', "
+                 "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                 "'c', CAST('"
+                 << inet_ntostring(ip) << "/32' AS INET), 0)";
+    }
+else
+    {
+    query << "SELECT sp_add_session_log_entry("
+                 "'" << elogin << "', "
+                 "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                 "'c', CAST('"
+                 << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
+    }
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+PQclear(result);
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteUserDisconnect(const string & login,
+                    const DIR_TRAFF & up,
+                    const DIR_TRAFF & down,
+                    const DIR_TRAFF & sessionUp,
+                    const DIR_TRAFF & sessionDown,
+                    double cash,
+                    double freeMb,
+                    const std::string & reason) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin(login);
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::string ereason(reason);
+
+if (EscapeString(ereason))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape reason'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+std::stringstream query;
+if (version < 6)
+    {
+    // Old database version - no freeMb logging support
+    query << "SELECT sp_add_session_log_entry("
+                "'" << elogin << "', "
+                "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                "'d', CAST('0.0.0.0/0' AS INET), "
+                << cash << ")";
+    }
+else
+    {
+    query << "SELECT sp_add_session_log_entry("
+                "'" << elogin << "', "
+                "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                "'d', CAST('0.0.0.0/0' AS INET), "
+                << cash << ", " << freeMb << ", '" << ereason << "')";
+    }
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_TUPLES_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+    if (RollbackTransaction())
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+        }
+    return -1;
+    }
+
+int tuples = PQntuples(result);
+
+if (tuples != 1)
+    {
+    strError = "Failed to fetch session's log ID";
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+uint32_t lid;
+
+if (str2x(PQgetvalue(result, 0, 0), lid))
+    {
+    strError = "Failed to convert string to int";
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+    PQclear(result);
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+PQclear(result);
+
+for (int i = 0; i < DIR_NUM; ++i)
+    {
+    std::stringstream query;
+    query << "INSERT INTO tb_sessions_data "
+                "(fk_session_log, "
+                 "dir_num, "
+                 "session_upload, "
+                 "session_download, "
+                 "month_upload, "
+                 "month_download)"
+             "VALUES ("
+                << lid << ", "
+                << i << ", "
+                << sessionUp[i] << ", "
+                << sessionDown[i] << ", "
+                << up[i] << ", "
+                << down[i] << ")";
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_COMMAND_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
+        if (RollbackTransaction())
+            {
+            printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
+            }
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::WriteDetailedStat(const map<IP_DIR_PAIR, STAT_NODE> * statTree,
+                                      time_t lastStat,
+                                      const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (PQstatus(connection) != CONNECTION_OK)
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
+    if (Reset())
+        {
+        strError = "Connection lost";
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
+        return -1;
+        }
+    }
+
+PGresult * result;
+
+if (StartTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to start transaction'\n");
+    return -1;
+    }
+
+std::string elogin(login);
+
+if (EscapeString(elogin))
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to escape login'\n");
+    if (RollbackTransaction())
+       {
+       printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
+       }
+    return -1;
+    }
+
+map<IP_DIR_PAIR, STAT_NODE>::const_iterator it;
+time_t currTime = time(NULL);
+
+for (it = statTree->begin(); it != statTree->end(); ++it)
+    {
+    std::stringstream query;
+    query << "INSERT INTO tb_detail_stats "
+                "(till_time, from_time, fk_user, "
+                 "dir_num, ip, download, upload, cost) "
+             "VALUES ("
+                "CAST('" << Int2TS(currTime) << "' AS TIMESTAMP), "
+                "CAST('" << Int2TS(lastStat) << "' AS TIMESTAMP), "
+                "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
+                << it->first.dir << ", "
+                << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
+                << it->second.down << ", "
+                << it->second.up << ", "
+                << it->second.cash << ")";
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_COMMAND_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
+        if (RollbackTransaction())
+            {
+            printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
+            }
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+if (CommitTransaction())
+    {
+    printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to commit transaction'\n");
+    return -1;
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, const string & login) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+return SaveStat(stat, login, year, month);
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserServices(uint32_t uid,
+                                       const std::vector<std::string> & services) const
+{
+PGresult * result;
+
+std::stringstream query;
+query << "DELETE FROM tb_users_services WHERE fk_user = " << uid;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PQclear(result);
+
+std::vector<std::string>::const_iterator it;
+
+for (it = services.begin(); it != services.end(); ++it)
+    {
+    std::string ename = *it;
+
+    if (EscapeString(ename))
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): 'Failed to escape service name'\n");
+        return -1;
+        }
+
+    std::stringstream query;
+    query << "INSERT INTO tb_users_services "
+                "(fk_user, fk_service) "
+             "VALUES "
+                "(" << uid << ", "
+                  "(SELECT pk_service "
+                   "FROM tb_services "
+                   "WHERE name = '" << ename << "'))";
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_COMMAND_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserIPs(uint32_t uid,
+                                  const USER_IPS & ips) const
+{
+PGresult * result;
+
+std::stringstream query;
+query << "DELETE FROM tb_allowed_ip WHERE fk_user = " << uid;
+
+result = PQexec(connection, query.str().c_str());
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PQclear(result);
+
+for (int i = 0; i < ips.Count(); ++i)
+    {
+    std::stringstream query;
+    query << "INSERT INTO tb_allowed_ip "
+                "(fk_user, ip) "
+             "VALUES "
+                "(" << uid << ", CAST('"
+                    << inet_ntostring(ips[i].ip) << "/"
+                    << static_cast<int>(ips[i].mask) << "' AS INET))";
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_COMMAND_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+return 0;
+}
+
+//-----------------------------------------------------------------------------
+int POSTGRESQL_STORE::SaveUserData(uint32_t uid,
+                                   const std::vector<std::string> & data) const
+{
+for (unsigned i = 0; i < data.size(); ++i)
+    {
+    std::string edata = data[i];
+
+    if (EscapeString(edata))
+        {
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): 'Failed to escape userdata field'\n");
+        return -1;
+        }
+
+    PGresult * result;
+
+    std::stringstream query;
+    query << "SELECT sp_set_user_data("
+                << uid << ", "
+                << "CAST(" << i << " AS SMALLINT), "
+                << "'" << edata << "')";
+
+    result = PQexec(connection, query.str().c_str());
+
+    if (PQresultStatus(result) != PGRES_TUPLES_OK)
+        {
+        strError = PQresultErrorMessage(result);
+        PQclear(result);
+        printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): '%s'\n", strError.c_str());
+        return -1;
+        }
+
+    PQclear(result);
+    }
+
+return 0;
+}
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp
new file mode 100644 (file)
index 0000000..28a1789
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *    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>
+ */
+
+/*
+ *  Vairous utility methods
+ *
+ *  $Revision: 1.3 $
+ *  $Date: 2009/10/22 10:01:08 $
+ *
+ */
+
+#include <string>
+#include <ctime>
+
+#include <libpq-fe.h>
+
+#include "common.h"
+
+#include "postgresql_store.h"
+
+int POSTGRESQL_STORE::StartTransaction() const
+{
+PGresult * result = PQexec(connection, "BEGIN");
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::StartTransaction(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PQclear(result);
+
+return 0;
+}
+
+int POSTGRESQL_STORE::CommitTransaction() const
+{
+PGresult * result = PQexec(connection, "COMMIT");
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::CommitTransaction(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PQclear(result);
+
+return 0;
+}
+
+int POSTGRESQL_STORE::RollbackTransaction() const
+{
+PGresult * result = PQexec(connection, "ROLLBACK");
+
+if (PQresultStatus(result) != PGRES_COMMAND_OK)
+    {
+    strError = PQresultErrorMessage(result);
+    PQclear(result);
+    printfd(__FILE__, "POSTGRESQL_STORE::RollbackTransaction(): '%s'\n", strError.c_str());
+    return -1;
+    }
+
+PQclear(result);
+
+return 0;
+}
+
+int POSTGRESQL_STORE::EscapeString(std::string & value) const
+{
+int error = 0;
+char * buf = new char[(value.length() << 1) + 1];
+
+PQescapeStringConn(connection,
+                  buf,
+                  value.c_str(),
+                  value.length(),
+                  &error);
+
+if (error)
+    {
+    strError = PQerrorMessage(connection);
+    printfd(__FILE__, "POSTGRESQL_STORE::EscapeString(): '%s'\n", strError.c_str());
+    delete buf;
+    return -1;
+    }
+
+value = buf;
+
+delete[] buf;
+return 0;
+}
+
+std::string POSTGRESQL_STORE::Int2TS(uint32_t ts) const
+{
+char buf[32];
+struct tm brokenTime;
+time_t tt = ts;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+gmtime_r(&tt, &brokenTime);
+
+strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
+
+return buf;
+}
+
+uint32_t POSTGRESQL_STORE::TS2Int(const std::string & ts) const
+{
+struct tm brokenTime;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+stg_strptime(ts.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime);
+
+return stg_timegm(&brokenTime);
+}
+
+void POSTGRESQL_STORE::MakeDate(std::string & date, int year, int month) const
+{
+struct tm brokenTime;
+
+brokenTime.tm_wday = 0;
+brokenTime.tm_yday = 0;
+brokenTime.tm_isdst = 0;
+
+if (year)
+    {
+    brokenTime.tm_hour = 0;
+    brokenTime.tm_min = 0;
+    brokenTime.tm_sec = 0;
+    brokenTime.tm_year = year;
+    brokenTime.tm_mon = month;
+    }
+else
+    {
+    time_t curTime = stgTime;
+    /*time(&curTime);*/
+
+    localtime_r(&curTime, &brokenTime);
+    }
+
+brokenTime.tm_mday = DaysInMonth(brokenTime.tm_year + 1900, brokenTime.tm_mon);
+
+char buf[32];
+
+strftime(buf, 32, "%Y-%m-%d", &brokenTime);
+
+date = buf;
+}
+
diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.h b/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.h
new file mode 100644 (file)
index 0000000..e09cccd
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef POSTGRESQL_UTILS_STORE_H
+#define POSTGRESQL_UTILS_STORE_H
+
+#include <functional>
+
+struct ToLower : public std::unary_function<char, char>
+{
+char operator() (char c) const  { return std::tolower(c); }
+};
+
+#endif
diff --git a/projects/stargazer/sandboxstart b/projects/stargazer/sandboxstart
new file mode 100755 (executable)
index 0000000..348244d
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+sandbox_dir=$1
+
+export LD_LIBRARY_PATH=$sandbox_dir/libs/
+
+$sandbox_dir/sbin/stargazer $sandbox_dir/etc/stargazer
+
+if [ $? == 0 ]
+then 
+    echo "Start successfull"
+       exit 0
+else
+    echo "Start failed"
+       exit 1
+fi
+
diff --git a/projects/stargazer/script_executer.cpp b/projects/stargazer/script_executer.cpp
new file mode 100644 (file)
index 0000000..dfc737e
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#include "common.h"
+
+using namespace std;
+
+#define MAX_SCRIPT_LEN  (256)
+
+static int msgid;
+static bool nonstop;
+
+//-----------------------------------------------------------------------------
+struct SCRIPT_DATA
+{
+    long    mtype;
+    char    script[MAX_SCRIPT_LEN];
+} sd;
+//-----------------------------------------------------------------------------
+static void CatchUSR1Executer(int)
+{
+//printfd(__FILE__, "CatchUSR1Executer\n");
+exit(0);
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+int ScriptExec(const string & str)
+{
+if (str.length() >= MAX_SCRIPT_LEN)
+    return -1;
+
+/*printfd(__FILE__, "2 Script schedule: %s\n", str.c_str());
+
+if (access(str.c_str(), X_OK))
+    return -1;*/
+
+struct msgbuf * mbuf;
+int ret;
+strncpy(sd.script, str.c_str(), MAX_SCRIPT_LEN);
+sd.mtype = 1;
+mbuf = (struct msgbuf * )&sd;
+ret = msgsnd(msgid, mbuf, MAX_SCRIPT_LEN, 0);
+if (ret < 0)
+    {
+    printfd(__FILE__, "snd ERROR!\n");
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void Executer(int msgKey, int msgID, pid_t pid, char * procName)
+{
+msgid = msgID;
+if (pid)
+    return;
+nonstop = true;
+//printfd(__FILE__, "close(pipeOut) %d pid=%d\n", pipeOut, getpid());
+
+//printfd(__FILE__, "Executer started %d\n", getpid());
+#ifdef LINUX
+memset(procName, 0, strlen(procName));
+strcpy(procName, "stg-exec");
+#else
+setproctitle("stg-exec");
+#endif
+
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR1);
+newsa.sa_handler = CatchUSR1Executer;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR1, &newsa, &oldsa);
+
+int ret;
+
+SCRIPT_DATA sd;
+
+while (nonstop)
+    {
+    sd.mtype = 1;
+    //printfd(__FILE__, "Waiting for msgrcv... msgid=%d pid=%d\n", msgid, getpid());
+    ret = msgrcv(msgid, &sd, MAX_SCRIPT_LEN, 0, 0);
+
+    if (ret < 0)
+        {
+        usleep(20000);
+        continue;
+        }
+    //printfd(__FILE__, "Script execute: %s\n", sd.script);
+    system(sd.script);
+    }
+exit(0);
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/scripts/clean_db b/projects/stargazer/scripts/clean_db
new file mode 100755 (executable)
index 0000000..31a85a9
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# Этот скрипт производит очистку файловой БД stargazer-а.
+# Его можно вызывать вручную или покрону, к примеру раз в неделю или раз в месяц.
+
+
+# Эта переменная задает сколько месяцев детальной статистики оставить в БД
+SAVE_MONTHS=3
+
+# Эта переменная задает сколько строк оставить в логах юзеров
+MAX_LOG_LINES=5000
+
+# Тут определяется путь к БД
+DB=/var/stargazer/
+
+
+
+
+declare -i NOW=`date +%s`
+declare -i DT=SAVE_MONTHS*31*24*3600
+declare -i stat_time=0
+
+for usr in $DB/users/*
+do
+    echo cleaning `basename $usr`
+    for ys in $usr/detail_stat/*
+    do
+       year=`basename $ys`
+       
+       for ms in $ys/*
+       do
+           month=`basename $ms`
+            stat_time=`date --date="$year/$month/01" +%s`          
+           
+           if (( $NOW - $stat_time > $DT ))
+           then
+               rm -fr $ms
+           fi
+       done
+    done
+    tail -n $MAX_LOG_LINES $usr/log > /tmp/stg_usr_log.`basename $usr`
+    mv -f /tmp/stg_usr_log.`basename $usr` $usr/log
+done
+
diff --git a/projects/stargazer/scripts/monitor b/projects/stargazer/scripts/monitor
new file mode 100755 (executable)
index 0000000..1f608a7
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# Данный скрипт производит мониторинг СТГ-сервера на зависание и в 
+# случае его зависания перезапускает.
+# Для работы скрипта в настройках СТГ должен быть указан параметер
+# MonitorDir 
+# Скрипт отрабатывает один раз и выходит. Т.е. он не работает постоянно 
+# и следит за СТГ. Его нужно вызывать по крону или как-то еще с нужной
+# периодичностью!!!
+
+
+# Путь к файлам монитора. Должен совпадать со значением MonitorDir 
+# в настройках сервера
+MONITOR_DIR=/var/stargazer/monitor/
+
+
+# Максимальная задержка обновления файлов монитора в секундах.
+# При привышении этого значения сервер считается зависшим и будет 
+# перезапущен
+DT=300
+
+
+
+
+declare -i now=`date +%s`
+declare -i DT=300
+declare -i file_time=0
+
+stg_running=`ps ax | grep stargazer`
+if [ -z "$stg_running" ]
+then
+    echo "Stargazer is not running"
+    exit 0
+fi
+
+#wakeuper for traffcounter
+ping -c 1 127.0.0.1 > /dev/null
+sleep 1
+
+for mon in $MONITOR_DIR/*
+do
+    if [ ! -r $mon ]
+    then
+        echo "no monitor files"
+        exit 0
+    fi
+    file_time=`stat -c%Y $mon`
+
+    if (( $now - $file_time > $DT )) 
+    then
+        echo "Stargazer is deadlocked!"
+               
+       # Команда остаовки СТГ
+       killall -KILL stargazer
+               
+       rm -f $MONITOR_DIR/*
+       sleep 15
+       
+       # Команда запуска СТГ
+       /etc/init.d/stargazer start
+       
+    fi
+    
+done
+
+
diff --git a/projects/stargazer/scripts/shaper/OnConnect b/projects/stargazer/scripts/shaper/OnConnect
new file mode 100755 (executable)
index 0000000..67bf32b
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+int_iface=eth1
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+default_speed=32kbit
+
+# =========== shaping by tariff ===========
+#tariff=$(grep -i "^tariff=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
+#echo "tariff=$tariff" > /var/stargazer/users/$LOGIN/connect.log
+#case $tariff in
+#    minimum)  speedkb=128kbit;;  # 128 kbit
+#    middle)   speedkb=256kbit;;  # 256 kbi
+#    maximum)  speedkb=512kbit;;        # 512 kbit
+#    *)        speedkb=$default_speed;;  # default speed
+#esac
+# ========= shaping by tariff end ========= 
+
+# ========= shaping by userdata0 ==========
+speedR=$(grep -i "^Userdata0=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
+speed=$(echo $speedR | grep "^[0-9]*[0-9]$")
+
+if [ -z "$speed" ] 
+then
+    speedkb=$default_speed
+else
+    speedkb="$speed"kbit
+fi
+# ======= shaping by userdata0 end ========
+
+declare -i mark=$ID+10
+
+echo "$mark" > /var/stargazer/users/$LOGIN/shaper_mark
+echo "$speedkb" > /var/stargazer/users/$LOGIN/shaper_rate
+
+iptables -t mangle -A FORWARD -d $IP -j MARK --set-mark $mark
+
+tc class add dev $int_iface parent 1:1 classid 1:$mark htb rate $speedkb burst 40k
+tc filter add dev $int_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:$mark
+
diff --git a/projects/stargazer/scripts/shaper/OnDisconnect b/projects/stargazer/scripts/shaper/OnDisconnect
new file mode 100755 (executable)
index 0000000..e015eec
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+int_iface=eth1
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$4
+
+mark=$(cat /var/stargazer/users/$LOGIN/shaper_mark)
+rate=$(cat /var/stargazer/users/$LOGIN/shaper_rate)
+
+if [ -n "$mark" ]
+then
+    iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+    while [ $? == 0 ]
+    do
+           iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+    done
+fi
+
+tc filter del dev $int_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:$mark
+tc class del dev $int_iface parent 1:1 classid 1:$mark htb rate $rate burst 40k
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
+
diff --git a/projects/stargazer/scripts/shaper/Readme.txt b/projects/stargazer/scripts/shaper/Readme.txt
new file mode 100644 (file)
index 0000000..a5fd925
--- /dev/null
@@ -0,0 +1,59 @@
+Настройка шейпера для STG в Linux.
+
+По мотивам форума:
+http://local.com.ua/forum/index.php?showtopic=7920
+
+Настройка сводится к указанию сетевого интерфейса, обращенного к пользователю 
+в скриптах shaper.sh, shaper.stop.sh, OnConnect и OnDisconnect, и уточнению 
+скоростоей и тарифов в скрипте OnConnect (если нужно).
+
+Скрипты сделаны для БД на файлах, однако, сделать их для БД на Firebird или 
+MySQL не составит большого труда.
+
+В OnConnect есть два типа шейпинга.
+1. На основании тарифа. Т.е. для каждого тарифа у задана скорость и задано 
+дефолтное значение, на случай отсутсвия тарифа в списке скоростей или 
+забывчивости админа.
+2. На основании Userdata0. В этом поле просто прописывается число равное 
+скорости в kbit/sec. Также есть дефолтное значение скорости в 32 kbit/sec 
+на случай отсутсвия в Userdata0 корректного значения.
+
+В скрипте первый способ закомментирован. Для того чтобы выбрать один из них нужно
+либо удалить, либо закомментировать строчики между
+
+# ========= shaping by tariff ==========
+.........
+# ======= shaping by tariff end ========
+
+
+# ========= shaping by userdata0 ==========
+.........
+# ======= shaping by userdata0 end ========
+
+
+и нужную часть расскоментировать, если она закомментрована.
+
+Скрипт shaper.sh должен быть выполнен один раз при загрузке системы.
+
+Интерфейс обращенный к пользователю определяется в переменной
+int_iface= 
+(присутствует во всех 4-х файлах shaper.sh, shaper.stop.sh, OnConnect и 
+OnDisconnect !!!)
+
+Скорость по умолчанию в OnConnect в переменной default_speed
+
+Зависимость скорости от тарифа задается в следующем фрагменте кода:
+case $tariff in
+    minimum)  speedkb=128kbit;;
+    middle)   speedkb=256kbit;;
+    maximum)  speedkb=512kbit;;
+    *)        speedkb=$default_speed;;
+esac
+
+Т.е. тут нужно вместо minimum, ... maximum подставить имена ваших тарифов 
+и соотв. скорость. Пользователи с тарифами не указанными в списке будут иметь 
+дефолтную скорость.
+
+Скорость ограничевается только для входящего тарафика, однако расширить 
+эти скрипты для исходящего не составит труда.
diff --git a/projects/stargazer/scripts/shaper/shaper.sh b/projects/stargazer/scripts/shaper/shaper.sh
new file mode 100755 (executable)
index 0000000..2b4f042
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+int_iface=eth1
+
+iptables -t mangle --flush
+
+tc qdisc add dev $int_iface root handle 1: htb
+tc class add dev $int_iface parent 1: classid 1:1 htb rate 100mbit ceil 100mbit burst 200k
+
diff --git a/projects/stargazer/scripts/shaper/shaper.stop.sh b/projects/stargazer/scripts/shaper/shaper.stop.sh
new file mode 100755 (executable)
index 0000000..993a13a
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+int_iface=eth1
+
+#iptables -t mangle --flush
+
+tc qdisc del dev $int_iface root handle 1: htb
+
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/Readme b/projects/stargazer/scripts/shaper_vpn_radius/Readme
new file mode 100644 (file)
index 0000000..772dddd
--- /dev/null
@@ -0,0 +1,58 @@
+Настройка такой конфигурации происходит в 3 этапа:
+1. Настройка VPN с использованием pptpd;
+2. Настройка авторизации VPN через FreeRADIUS;
+3. Настройка шейпера;
+
+1. Настройка VPN
+
+Необходимо установить пакеты ppp и pptpd. Также необходима поддержка PPP в ядре:
+    Device Drivers  --->
+        Network device support  --->
+            <M> PPP (point-to-point protocol) support
+            <M>   PPP support for sync tty ports
+            <M>   PPP Deflate compression
+            <M>   PPP BSD-Compress compression
+            <M>   PPP MPPE compression (encryption) (EXPERIMENTAL)
+            <M>   PPP over Ethernet (EXPERIMENTAL)
+В файле /etc/pptpd.conf прописываем файл настроек PPP (параметр option). Также
+указываем адреса сервера внутри сети VPN (параметр localip) и диапазон адресов 
+клиентов (параметр remoteip). См. пример файла конфигурации.
+В настройках PPP указываем имя сервера (параметр name), параметры шифрования. 
+Для использования шифрования MPPE необходима его поддержка в ядре. Кроме того, 
+в процессе аутентификации MPPE использует MS-CHAPv2. По этому при 
+использовании шифрования MPPE также необходимо указать необходимость 
+поддержки MS-CHAPv2 клиентом. По желанию указываем proxyarp (для того чтобы 
+клиенты в сети VPN "видели" друг друга) и defaultroute. Прописываем в файле 
+/etc/ppp/chap-secrets тестового пользователя и проверяем работоспособность 
+VPN.
+
+2. Настройка авторизации VPN через FreeRADIUS
+
+Необходимо установить пакет freeradius.
+Настройку сервера (файл radiusd.conf) проводим в соответствии с документацией 
+на модуль rlm_stg.so (см. документацию на систему Stargazer).
+Настройку Stargazer с плагином для FreeRADIUS проводим в соответствиии с 
+документацией на модуль mod_radius.so (см. документацию на систему Stargazer).
+В файле clients.conf, расположенном в дирректории с конфигурационными файлами 
+FreeRADIUS, описываем, какие клиенты могут использовать FreeRADIUS. 
+Рекомендуется заменить стандартный пароль, которым шифруется обмен информации 
+с клиентом, "testing123" на что-то более приемлимое с точки зрения безопасности. 
+После этого запускаем FreeRADIUS и удостоверяемся, что он работает строчкой 
+"Mon Mar 31 16:06:17 2008 : Info: Ready to process requests." в журнале 
+(обычно, /var/log/radius/radius.log). Если журнал FreeRADIUS не позволяет 
+определить проблему - можно запустить сервер в отладочном режме с ключем -X. 
+В этом режиме более детальное журналирование проводится в консоль.
+Если на данном этапе все работает - в файл насттроек PPP прописываем строчку 
+plugin radius.so. После этого VPN должен нормально авторизоваться 
+пользователями системы Stargazer.
+
+3. Настройка шейпера
+
+Собственно настройки шейпер не требует. Всё, что нужно прописано в скриптах 
+OnConnect и OnDisconnect. Шейпер предназначен для работы с хранилищем на 
+файлах, однако, переделать скипт под MySQL или Firebird не составит труда.
+Скорость для пользоватлея задается в поле Userdata0 в kbit/sec. В этом поле 
+должно быть прописано просто число без всяких kbit/sec и т.п. Если в этом поле
+у пользователя нет данных или стоит некорректное значение, пользователь будет 
+ограничен скоростью определенной в переменной default_speed в скрипте 
+OnConnect.
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/firewall/firewall b/projects/stargazer/scripts/shaper_vpn_radius/firewall/firewall
new file mode 100755 (executable)
index 0000000..36a2703
--- /dev/null
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+#adsl-start
+
+modprobe ip_queue
+
+int_addr=10.0.0.2
+ext_addr=192.168.1.34
+
+int_net=10.0.0.0/16
+ext_net=192.168.1.0/24
+
+echo 1 > /proc/sys/net/ipv4/ip_forward
+
+iptables -P INPUT DROP
+iptables -P OUTPUT ACCEPT
+iptables -P FORWARD ACCEPT
+
+iptables -t nat -F
+iptables -t filter -F
+
+# 
+#iptables -A INPUT  -d $ip1 -j ACCEPT
+#iptables -A OUTPUT -s $ip1 -j ACCEPT
+
+# Разрешам говорить самому с собой
+iptables -A INPUT  -d 127.0.0.1 -j ACCEPT
+iptables -A OUTPUT -s 127.0.0.1 -j ACCEPT
+
+#iptables -A INPUT  -d $ip4 -j ACCEPT
+#iptables -A INPUT  -s $ip4 -j ACCEPT
+#iptables -A OUTPUT -s $ip4 -j ACCEPT
+#iptables -A OUTPUT -d $ip4 -j ACCEPT
+
+iptables -A INPUT  -p icmp -j ACCEPT
+iptables -A OUTPUT -p icmp -j ACCEPT
+
+iptables -A INPUT  -p 47 -j ACCEPT
+iptables -A FORWARD -p 47 -j ACCEPT
+iptables -A OUTPUT -p 47 -j ACCEPT
+
+#SSH On this machine
+iptables -A INPUT  -p tcp -d $int_addr --dport 22 -j ACCEPT
+iptables -A OUTPUT -p tcp -s $int_addr --sport 22 -j ACCEPT
+iptables -A INPUT  -p tcp -d $ext_addr --dport 22 -j ACCEPT
+iptables -A OUTPUT -p tcp -s $ext_addr --sport 22 -j ACCEPT
+
+#WEB On this machine
+#iptables -A INPUT  -p tcp -d $ip2 --dport 80 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 --sport 80 -j ACCEPT
+#iptables -A INPUT  -p tcp -d $ip3 --dport 80 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 --sport 80 -j ACCEPT
+
+#PPTP
+iptables -A INPUT   -p tcp --dport 1723 -j ACCEPT
+iptables -A OUTPUT  -p tcp --sport 1723 -j ACCEPT
+iptables -A INPUT  -p udp --dport 1723 -j ACCEPT
+iptables -A OUTPUT -p udp --sport 1723 -j ACCEPT
+
+#FTP
+#iptables -A INPUT  -p tcp -d $ip2 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 -j ACCEPT
+#iptables -A INPUT  -p tcp -d $ip3 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 -j ACCEPT
+
+#iptables -A INPUT  -p tcp -d $ip2 --dport 20:21 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 --sport 20:21 -j ACCEPT
+#iptables -A INPUT  -p tcp -d $ip3 --dport 20:21 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 --sport 20:21 -j ACCEPT
+
+#iptables -A INPUT  -p tcp -d $ip2 --dport 1024:65535 --sport 1024:65535 -j ACCEPT
+#iptables -A INPUT  -p tcp -d $ip3 --dport 1024:65535 --sport 1024:65535 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip2 --sport 1024:65535 --dport 1024:65535 -j ACCEPT
+#iptables -A OUTPUT -p tcp -s $ip3 --sport 1024:65535 --dport 1024:65535 -j ACCEPT
+
+#DNS
+iptables -A INPUT  -p tcp --sport 53 -j ACCEPT
+iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
+iptables -A INPUT  -p udp --sport 53 -j ACCEPT
+iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
+
+#iptables -t nat -A PREROUTING -p tcp -d $ip1 --dport 80 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -d $ip2 --dport 80 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -d $ip3 --dport 80 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -d $ip4 --dport 80 -j ACCEPT
+
+#iptables -t nat -A PREROUTING -p tcp -s 192.168.1.7 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp -s 192.168.1.16 -j ACCEPT
+#iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3128
+
+iptables -t nat -A POSTROUTING -d 0.0.0.0/0 -s 192.168.2.0/24 -j MASQUERADE
+
+
+
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/freeradius/clients.conf b/projects/stargazer/scripts/shaper_vpn_radius/freeradius/clients.conf
new file mode 100644 (file)
index 0000000..a855b2d
--- /dev/null
@@ -0,0 +1,78 @@
+#
+# clients.conf - client configuration directives
+#
+#######################################################################
+
+#######################################################################
+#
+#  Definition of a RADIUS client (usually a NAS).
+#
+#  The information given here over rides anything given in the
+#  'clients' file, or in the 'naslist' file.  The configuration here
+#  contains all of the information from those two files, and allows
+#  for more configuration items.
+#
+#  The "shortname" is be used for logging.  The "nastype", "login" and
+#  "password" fields are mainly used for checkrad and are optional.
+#
+
+#
+#  Defines a RADIUS client.  The format is 'client [hostname|ip-address]'
+#
+#  '127.0.0.1' is another name for 'localhost'.  It is enabled by default,
+#  to allow testing of the server after an initial installation.  If you
+#  are not going to be permitting RADIUS queries from localhost, we suggest
+#  that you delete, or comment out, this entry.
+#
+client 127.0.0.1 {
+       #
+       #  The shared secret use to "encrypt" and "sign" packets between
+       #  the NAS and FreeRADIUS.  You MUST change this secret from the
+       #  default, otherwise it's not a secret any more!
+       #
+       #  The secret can be any string, up to 31 characters in length.
+       #
+       secret          = testing123
+
+       #
+       #  The short name is used as an alias for the fully qualified
+       #  domain name, or the IP address.
+       #
+       shortname       = localhost
+
+       #
+       # the following three fields are optional, but may be used by
+       # checkrad.pl for simultaneous use checks
+       #
+
+       #
+       # The nastype tells 'checkrad.pl' which NAS-specific method to
+       #  use to query the NAS for simultaneous use.
+       #
+       #  Permitted NAS types are:
+       #
+       #       cisco
+       #       computone
+       #       livingston
+       #       max40xx
+       #       multitech
+       #       netserver
+       #       pathras
+       #       patton
+       #       portslave
+       #       tc
+       #       usrhiper
+       #       other           # for all other types
+
+       #
+       nastype     = other     # localhost isn't usually a NAS...
+
+       #
+       #  The following two configurations are for future use.
+       #  The 'naspasswd' file is currently used to store the NAS
+       #  login name and password, which is used by checkrad.pl
+       #  when querying the NAS for simultaneous use.
+       #
+#      login       = !root
+#      password    = someadminpas
+}
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/freeradius/radiusd.conf b/projects/stargazer/scripts/shaper_vpn_radius/freeradius/radiusd.conf
new file mode 100644 (file)
index 0000000..c41d28d
--- /dev/null
@@ -0,0 +1,1119 @@
+##
+## radiusd.conf        -- FreeRADIUS server configuration file.
+##
+##     http://www.freeradius.org/
+##     $Id: radiusd.conf,v 1.1 2008/03/31 13:54:59 faust Exp $
+##
+
+#      The location of other config files and
+#      logfiles are declared in this file
+#
+#      Also general configuration for modules can be done
+#      in this file, it is exported through the API to
+#      modules that ask for it.
+#
+#      The configuration variables defined here are of the form ${foo}
+#      They are local to this file, and do not change from request to
+#      request.
+#
+#      The per-request variables are of the form %{Attribute-Name}, and
+#      are taken from the values of the attribute in the incoming
+#      request.  See 'doc/variables.txt' for more information.
+
+prefix = /usr
+exec_prefix = /usr
+sysconfdir = /etc
+localstatedir = /var
+sbindir = ${exec_prefix}/sbin
+logdir = /var/log/freeradius
+raddbdir = /etc/freeradius
+radacctdir = ${logdir}/radacct
+
+#  Location of config and logfiles.
+confdir = ${raddbdir}
+run_dir = ${localstatedir}/run/freeradius
+
+#
+#  The logging messages for the server are appended to the
+#  tail of this file.
+#
+log_file = ${logdir}/radius.log
+
+#
+# libdir: Where to find the rlm_* modules.
+#
+#   This should be automatically set at configuration time.
+#
+#   If the server builds and installs, but fails at execution time
+#   with an 'undefined symbol' error, then you can use the libdir
+#   directive to work around the problem.
+#
+#   The cause is usually that a library has been installed on your
+#   system in a place where the dynamic linker CANNOT find it.  When
+#   executing as root (or another user), your personal environment MAY
+#   be set up to allow the dynamic linker to find the library.  When
+#   executing as a daemon, FreeRADIUS MAY NOT have the same
+#   personalized configuration.
+#
+#   To work around the problem, find out which library contains that symbol,
+#   and add the directory containing that library to the end of 'libdir',
+#   with a colon separating the directory names.  NO spaces are allowed.
+#
+#   e.g. libdir = /usr/local/lib:/opt/package/lib
+#
+#   You can also try setting the LD_LIBRARY_PATH environment variable
+#   in a script which starts the server.
+#
+#   If that does not work, then you can re-configure and re-build the
+#   server to NOT use shared libraries, via:
+#
+#      ./configure --disable-shared
+#      make
+#      make install
+#
+libdir = /usr/lib/freeradius
+
+#  pidfile: Where to place the PID of the RADIUS server.
+#
+#  The server may be signalled while it's running by using this
+#  file.
+#
+#  This file is written when ONLY running in daemon mode.
+#
+#  e.g.:  kill -HUP `cat /var/run/freeradius/freeradius.pid`
+#
+pidfile = ${run_dir}/freeradius.pid
+
+
+# user/group: The name (or #number) of the user/group to run radiusd as.
+#
+#   If these are commented out, the server will run as the user/group
+#   that started it.  In order to change to a different user/group, you
+#   MUST be root ( or have root privleges ) to start the server.
+#
+#   We STRONGLY recommend that you run the server with as few permissions
+#   as possible.  That is, if you're not using shadow passwords, the
+#   user and group items below should be set to 'nobody'.
+#
+#    On SCO (ODT 3) use "user = nouser" and "group = nogroup".
+#
+#  NOTE that some kernels refuse to setgid(group) when the value of
+#  (unsigned)group is above 60000; don't use group nobody on these systems!
+#
+#  On systems with shadow passwords, you might have to set 'group = shadow'
+#  for the server to be able to read the shadow password file.  If you can
+#  authenticate users while in debug mode, but not in daemon mode, it may be
+#  that the debugging mode server is running as a user that can read the
+#  shadow info, and the user listed below can not.
+#
+user = freerad
+group = freerad
+
+#  max_request_time: The maximum time (in seconds) to handle a request.
+#
+#  Requests which take more time than this to process may be killed, and
+#  a REJECT message is returned.
+#
+#  WARNING: If you notice that requests take a long time to be handled,
+#  then this MAY INDICATE a bug in the server, in one of the modules
+#  used to handle a request, OR in your local configuration.
+#
+#  This problem is most often seen when using an SQL database.  If it takes
+#  more than a second or two to receive an answer from the SQL database,
+#  then it probably means that you haven't indexed the database.  See your
+#  SQL server documentation for more information.
+#
+#  Useful range of values: 5 to 120
+#
+max_request_time = 30
+
+#  delete_blocked_requests: If the request takes MORE THAN 'max_request_time'
+#  to be handled, then maybe the server should delete it.
+#
+#  If you're running in threaded, or thread pool mode, this setting
+#  should probably be 'no'.  Setting it to 'yes' when using a threaded
+#  server MAY cause the server to crash!
+#
+delete_blocked_requests = no
+
+#  cleanup_delay: The time to wait (in seconds) before cleaning up
+#  a reply which was sent to the NAS.
+#
+#  The RADIUS request is normally cached internally for a short period
+#  of time, after the reply is sent to the NAS.  The reply packet may be
+#  lost in the network, and the NAS will not see it.  The NAS will then
+#  re-send the request, and the server will respond quickly with the
+#  cached reply.
+#
+#  If this value is set too low, then duplicate requests from the NAS
+#  MAY NOT be detected, and will instead be handled as seperate requests.
+#
+#  If this value is set too high, then the server will cache too many
+#  requests, and some new requests may get blocked.  (See 'max_requests'.)
+#
+#  Useful range of values: 2 to 10
+#
+cleanup_delay = 5
+
+#  max_requests: The maximum number of requests which the server keeps
+#  track of.  This should be 256 multiplied by the number of clients.
+#  e.g. With 4 clients, this number should be 1024.
+#
+#  If this number is too low, then when the server becomes busy,
+#  it will not respond to any new requests, until the 'cleanup_delay'
+#  time has passed, and it has removed the old requests.
+#
+#  If this number is set too high, then the server will use a bit more
+#  memory for no real benefit.
+#
+#  If you aren't sure what it should be set to, it's better to set it
+#  too high than too low.  Setting it to 1000 per client is probably
+#  the highest it should be.
+#
+#  Useful range of values: 256 to infinity
+#
+max_requests = 1024
+
+#  bind_address:  Make the server listen on a particular IP address, and
+#  send replies out from that address.  This directive is most useful
+#  for machines with multiple IP addresses on one interface.
+#
+#  It can either contain "*", or an IP address, or a fully qualified
+#  Internet domain name.  The default is "*"
+#
+#  As of 1.0, you can also use the "listen" directive.  See below for
+#  more information.
+#
+bind_address = *
+
+#  port: Allows you to bind FreeRADIUS to a specific port.
+#
+#  The default port that most NAS boxes use is 1645, which is historical.
+#  RFC 2138 defines 1812 to be the new port.  Many new servers and
+#  NAS boxes use 1812, which can create interoperability problems.
+#
+#  The port is defined here to be 0 so that the server will pick up
+#  the machine's local configuration for the radius port, as defined
+#  in /etc/services.
+#
+#  If you want to use the default RADIUS port as defined on your server,
+#  (usually through 'grep radius /etc/services') set this to 0 (zero).
+#
+#  A port given on the command-line via '-p' over-rides this one.
+#
+#  As of 1.0, you can also use the "listen" directive.  See below for
+#  more information.
+#
+port = 0
+
+#
+#  By default, the server uses "bind_address" to listen to all IP's
+#  on a machine, or just one IP.  The "port" configuration is used
+#  to select the authentication port used when listening on those
+#  addresses.
+#
+#  If you want the server to listen on additional addresses, you can
+#  use the "listen" section.  A sample section (commented out) is included
+#  below.  This "listen" section duplicates the functionality of the
+#  "bind_address" and "port" configuration entries, but it only listens
+#  for authentication packets.
+#
+#  If you comment out the "bind_address" and "port" configuration entries,
+#  then it becomes possible to make the server accept only accounting,
+#  or authentication packets.  Previously, it always listened for both
+#  types of packets, and it was impossible to make it listen for only
+#  one type of packet.
+#
+#listen {
+       #  IP address on which to listen.
+       #  Allowed values are:
+       #       dotted quad (1.2.3.4)
+       #       hostname    (radius.example.com)
+       #       wildcard    (*)
+#      ipaddr = *
+
+       #  Port on which to listen.
+       #  Allowed values are:
+       #       integer port number (1812)
+       #       0 means "use /etc/services for the proper port"
+#      port = 0
+
+       #  Type of packets to listen for.
+       #  Allowed values are:
+       #       auth    listen for authentication packets
+       #       acct    listen for accounting packets
+       #
+#      type = auth
+#}
+
+
+#  hostname_lookups: Log the names of clients or just their IP addresses
+#  e.g., www.freeradius.org (on) or 206.47.27.232 (off).
+#
+#  The default is 'off' because it would be overall better for the net
+#  if people had to knowingly turn this feature on, since enabling it
+#  means that each client request will result in AT LEAST one lookup
+#  request to the nameserver.   Enabling hostname_lookups will also
+#  mean that your server may stop randomly for 30 seconds from time
+#  to time, if the DNS requests take too long.
+#
+#  Turning hostname lookups off also means that the server won't block
+#  for 30 seconds, if it sees an IP address which has no name associated
+#  with it.
+#
+#  allowed values: {no, yes}
+#
+hostname_lookups = no
+
+#  Core dumps are a bad thing.  This should only be set to 'yes'
+#  if you're debugging a problem with the server.
+#
+#  allowed values: {no, yes}
+#
+allow_core_dumps = no
+
+#  Regular expressions
+#
+#  These items are set at configure time.  If they're set to "yes",
+#  then setting them to "no" turns off regular expression support.
+#
+#  If they're set to "no" at configure time, then setting them to "yes"
+#  WILL NOT WORK.  It will give you an error.
+#
+regular_expressions    = yes
+extended_expressions   = yes
+
+#  Log the full User-Name attribute, as it was found in the request.
+#
+# allowed values: {no, yes}
+#
+log_stripped_names = no
+
+#  Log authentication requests to the log file.
+#
+#  allowed values: {no, yes}
+#
+log_auth = no
+
+#  Log passwords with the authentication requests.
+#  log_auth_badpass  - logs password if it's rejected
+#  log_auth_goodpass - logs password if it's correct
+#
+#  allowed values: {no, yes}
+#
+log_auth_badpass = no
+log_auth_goodpass = no
+
+# usercollide:  Turn "username collision" code on and off.  See the
+# "doc/duplicate-users" file
+#
+#  WARNING
+#  !!!!!!!  Setting this to "yes" may result in the server behaving
+#  !!!!!!!  strangely.  The "username collision" code will ONLY work
+#  !!!!!!!  with clear-text passwords.  Even then, it may not do what
+#  !!!!!!!  you want, or what you expect.
+#  !!!!!!!
+#  !!!!!!!  We STRONGLY RECOMMEND that you do not use this feature,
+#  !!!!!!!  and that you find another way of acheiving the same goal.
+#  !!!!!!!
+#  !!!!!!!  e,g. module fail-over.  See 'doc/configurable_failover'
+#  WARNING
+#
+usercollide = no
+
+# lower_user / lower_pass:  
+# Lower case the username/password "before" or "after"
+# attempting to authenticate.  
+#
+#  If "before", the server will first modify the request and then try
+#  to auth the user.  If "after", the server will first auth using the
+#  values provided by the user.  If that fails it will reprocess the
+#  request after modifying it as you specify below.
+#
+#  This is as close as we can get to case insensitivity.  It is the
+#  admin's job to ensure that the username on the auth db side is
+#  *also* lowercase to make this work
+#
+# Default is 'no' (don't lowercase values)
+# Valid values = "before" / "after" / "no"
+#
+lower_user = no
+lower_pass = no
+
+# nospace_user / nospace_pass:
+#
+#  Some users like to enter spaces in their username or password
+#  incorrectly.  To save yourself the tech support call, you can
+#  eliminate those spaces here:
+#
+# Default is 'no' (don't remove spaces)
+# Valid values = "before" / "after" / "no" (explanation above)
+#
+nospace_user = no
+nospace_pass = no
+
+#  The program to execute to do concurrency checks.
+checkrad = ${sbindir}/checkrad
+
+# SECURITY CONFIGURATION
+#
+#  There may be multiple methods of attacking on the server.  This
+#  section holds the configuration items which minimize the impact
+#  of those attacks
+#
+security {
+       #
+       #  max_attributes: The maximum number of attributes
+       #  permitted in a RADIUS packet.  Packets which have MORE
+       #  than this number of attributes in them will be dropped.
+       #
+       #  If this number is set too low, then no RADIUS packets
+       #  will be accepted.
+       #
+       #  If this number is set too high, then an attacker may be
+       #  able to send a small number of packets which will cause
+       #  the server to use all available memory on the machine.
+       #
+       #  Setting this number to 0 means "allow any number of attributes"
+       max_attributes = 200
+
+       #
+       #  reject_delay: When sending an Access-Reject, it can be
+       #  delayed for a few seconds.  This may help slow down a DoS
+       #  attack.  It also helps to slow down people trying to brute-force
+       #  crack a users password.
+       #
+       #  Setting this number to 0 means "send rejects immediately"
+       #
+       #  If this number is set higher than 'cleanup_delay', then the
+       #  rejects will be sent at 'cleanup_delay' time, when the request
+       #  is deleted from the internal cache of requests.
+       #
+       #  Useful ranges: 1 to 5
+       reject_delay = 1
+
+       #
+       #  status_server: Whether or not the server will respond
+       #  to Status-Server requests.
+       #
+       #  Normally this should be set to "no", because they're useless.
+       #  See: http://www.freeradius.org/rfc/rfc2865.html#Keep-Alives
+       #
+       #  However, certain NAS boxes may require them. 
+       #
+       #  When sent a Status-Server message, the server responds with
+       #  an Access-Accept packet, containing a Reply-Message attribute,
+       #  which is a string describing how long the server has been
+       #  running.
+       #
+       status_server = no
+}
+
+# PROXY CONFIGURATION
+#
+#  proxy_requests: Turns proxying of RADIUS requests on or off.
+#
+#  The server has proxying turned on by default.  If your system is NOT
+#  set up to proxy requests to another server, then you can turn proxying
+#  off here.  This will save a small amount of resources on the server.
+#
+#  If you have proxying turned off, and your configuration files say
+#  to proxy a request, then an error message will be logged.
+#
+#  To disable proxying, change the "yes" to "no", and comment the
+#  $INCLUDE line.
+#
+#  allowed values: {no, yes}
+#
+proxy_requests  = yes
+$INCLUDE  ${confdir}/proxy.conf
+
+
+# CLIENTS CONFIGURATION
+#
+#  Client configuration is defined in "clients.conf".  
+#
+
+#  The 'clients.conf' file contains all of the information from the old
+#  'clients' and 'naslist' configuration files.  We recommend that you
+#  do NOT use 'client's or 'naslist', although they are still
+#  supported.
+#
+#  Anything listed in 'clients.conf' will take precedence over the
+#  information from the old-style configuration files.
+#
+$INCLUDE  ${confdir}/clients.conf
+
+
+# SNMP CONFIGURATION
+#
+#  Snmp configuration is only valid if SNMP support was enabled
+#  at compile time.
+#
+#  To enable SNMP querying of the server, set the value of the
+#  'snmp' attribute to 'yes'
+#
+snmp   = no
+$INCLUDE  ${confdir}/snmp.conf
+
+
+# THREAD POOL CONFIGURATION
+#
+#  The thread pool is a long-lived group of threads which
+#  take turns (round-robin) handling any incoming requests.
+#
+#  You probably want to have a few spare threads around,
+#  so that high-load situations can be handled immediately.  If you
+#  don't have any spare threads, then the request handling will
+#  be delayed while a new thread is created, and added to the pool.
+#
+#  You probably don't want too many spare threads around,
+#  otherwise they'll be sitting there taking up resources, and
+#  not doing anything productive.
+#
+#  The numbers given below should be adequate for most situations.
+#
+thread pool {
+       #  Number of servers to start initially --- should be a reasonable
+       #  ballpark figure.
+       start_servers = 5
+
+       #  Limit on the total number of servers running.
+       #
+       #  If this limit is ever reached, clients will be LOCKED OUT, so it
+       #  should NOT BE SET TOO LOW.  It is intended mainly as a brake to
+       #  keep a runaway server from taking the system with it as it spirals
+       #  down...
+       #
+       #  You may find that the server is regularly reaching the
+       #  'max_servers' number of threads, and that increasing
+       #  'max_servers' doesn't seem to make much difference.
+       #
+       #  If this is the case, then the problem is MOST LIKELY that
+       #  your back-end databases are taking too long to respond, and
+       #  are preventing the server from responding in a timely manner.
+       #
+       #  The solution is NOT do keep increasing the 'max_servers'
+       #  value, but instead to fix the underlying cause of the
+       #  problem: slow database, or 'hostname_lookups=yes'.
+       #
+       #  For more information, see 'max_request_time', above.
+       #
+       max_servers = 32
+
+       #  Server-pool size regulation.  Rather than making you guess
+       #  how many servers you need, FreeRADIUS dynamically adapts to
+       #  the load it sees, that is, it tries to maintain enough
+       #  servers to handle the current load, plus a few spare
+       #  servers to handle transient load spikes.
+       #
+       #  It does this by periodically checking how many servers are
+       #  waiting for a request.  If there are fewer than
+       #  min_spare_servers, it creates a new spare.  If there are
+       #  more than max_spare_servers, some of the spares die off.
+       #  The default values are probably OK for most sites.
+       #
+       min_spare_servers = 3
+       max_spare_servers = 10
+
+       #  There may be memory leaks or resource allocation problems with
+       #  the server.  If so, set this value to 300 or so, so that the
+       #  resources will be cleaned up periodically.
+       #
+       #  This should only be necessary if there are serious bugs in the
+       #  server which have not yet been fixed.
+       #
+       #  '0' is a special value meaning 'infinity', or 'the servers never
+       #  exit'
+       max_requests_per_server = 0
+}
+
+# MODULE CONFIGURATION
+#
+#  The names and configuration of each module is located in this section.
+#
+#  After the modules are defined here, they may be referred to by name,
+#  in other sections of this configuration file.
+#
+modules {
+       #
+       #  Each module has a configuration as follows:
+       #
+       #       name [ instance ] {
+       #               config_item = value
+       #               ...
+       #       }
+       #
+       #  The 'name' is used to load the 'rlm_name' library
+       #  which implements the functionality of the module.
+       #
+       #  The 'instance' is optional.  To have two different instances
+       #  of a module, it first must be referred to by 'name'.
+       #  The different copies of the module are then created by
+       #  inventing two 'instance' names, e.g. 'instance1' and 'instance2'
+       #
+       #  The instance names can then be used in later configuration
+       #  INSTEAD of the original 'name'.  See the 'radutmp' configuration
+       #  below for an example.
+       #
+
+       # PAP module to authenticate users based on their stored password
+       #
+       #  Supports multiple encryption schemes
+       #  clear: Clear text
+       #  crypt: Unix crypt
+       #    md5: MD5 ecnryption
+       #   sha1: SHA1 encryption.
+       #  DEFAULT: crypt
+       pap {
+               encryption_scheme = crypt
+       }
+
+       # CHAP module
+       #
+       #  To authenticate requests containing a CHAP-Password attribute.
+       #
+       chap {
+               authtype = CHAP
+       }
+
+       #  Extensible Authentication Protocol
+       #
+       #  For all EAP related authentications.
+       #  Now in another file, because it is very large.
+       #
+$INCLUDE ${confdir}/eap.conf
+
+       # Microsoft CHAP authentication
+       #
+       #  This module supports MS-CHAP and MS-CHAPv2 authentication.
+       #  It also enforces the SMB-Account-Ctrl attribute.
+       #
+       mschap {
+               #
+               #  As of 0.9, the mschap module does NOT support
+               #  reading from /etc/smbpasswd.
+               #
+               #  If you are using /etc/smbpasswd, see the 'passwd'
+               #  module for an example of how to use /etc/smbpasswd
+
+               # if use_mppe is not set to no mschap will
+               # add MS-CHAP-MPPE-Keys for MS-CHAPv1 and
+               # MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2
+               #
+               use_mppe = yes
+               authtype = MS-CHAP
+
+               # if mppe is enabled require_encryption makes
+               # encryption moderate
+               #
+               #require_encryption = yes
+
+               # require_strong always requires 128 bit key
+               # encryption
+               #
+               #require_strong = yes
+
+               # Windows sends us a username in the form of
+               # DOMAIN\user, but sends the challenge response
+               # based on only the user portion.  This hack
+               # corrects for that incorrect behavior.
+               #
+               #with_ntdomain_hack = no
+
+               # The module can perform authentication itself, OR
+               # use a Windows Domain Controller.  This configuration
+               # directive tells the module to call the ntlm_auth
+               # program, which will do the authentication, and return
+               # the NT-Key.  Note that you MUST have "winbindd" and
+               # "nmbd" running on the local machine for ntlm_auth
+               # to work.  See the ntlm_auth program documentation
+               # for details.
+               #
+               # Be VERY careful when editing the following line!
+               #
+               #ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{Stripped-User-Name:-%{User-Name:-None}} --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00}"
+       }
+
+       # Preprocess the incoming RADIUS request, before handing it off
+       # to other modules.
+       #
+       #  This module processes the 'huntgroups' and 'hints' files.
+       #  In addition, it re-writes some weird attributes created
+       #  by some NASes, and converts the attributes into a form which
+       #  is a little more standard.
+       #
+       preprocess {
+               huntgroups = ${confdir}/huntgroups
+               hints = ${confdir}/hints
+
+               # This hack changes Ascend's wierd port numberings
+               # to standard 0-??? port numbers so that the "+" works
+               # for IP address assignments.
+               with_ascend_hack = no
+               ascend_channels_per_line = 23
+
+               # Windows NT machines often authenticate themselves as
+               # NT_DOMAIN\username
+               #
+               # If this is set to 'yes', then the NT_DOMAIN portion
+               # of the user-name is silently discarded.
+               #
+               # This configuration entry SHOULD NOT be used.
+               # See the "realms" module for a better way to handle
+               # NT domains.
+               with_ntdomain_hack = no
+
+               # Specialix Jetstream 8500 24 port access server.
+               #
+               # If the user name is 10 characters or longer, a "/"
+               # and the excess characters after the 10th are
+               # appended to the user name.
+               #
+               # If you're not running that NAS, you don't need
+               # this hack.
+               with_specialix_jetstream_hack = no
+
+               # Cisco (and Quintum in Cisco mode) sends it's VSA attributes
+               # with the attribute name *again* in the string, like:
+               #
+               #   H323-Attribute = "h323-attribute=value".
+               #
+               # If this configuration item is set to 'yes', then
+               # the redundant data in the the attribute text is stripped
+               # out.  The result is:
+               #
+               #  H323-Attribute = "value"
+               #
+               # If you're not running a Cisco or Quintum NAS, you don't
+               # need this hack.
+               with_cisco_vsa_hack = no
+       }
+
+       # Write a detailed log of all accounting records received.
+       #
+       detail {
+               #  Note that we do NOT use NAS-IP-Address here, as
+               #  that attribute MAY BE from the originating NAS, and
+               #  NOT from the proxy which actually sent us the
+               #  request.  The Client-IP-Address attribute is ALWAYS
+               #  the address of the client which sent us the
+               #  request.
+               #
+               #  The following line creates a new detail file for
+               #  every radius client (by IP address or hostname).
+               #  In addition, a new detail file is created every
+               #  day, so that the detail file doesn't have to go
+               #  through a 'log rotation'
+               #
+               #  If your detail files are large, you may also want
+               #  to add a ':%H' (see doc/variables.txt) to the end
+               #  of it, to create a new detail file every hour, e.g.:
+               #
+               #   ..../detail-%Y%m%d:%H
+               #
+               #  This will create a new detail file for every hour.
+               #
+               detailfile = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
+
+               #
+               #  The Unix-style permissions on the 'detail' file.
+               #
+               #  The detail file often contains secret or private
+               #  information about users.  So by keeping the file
+               #  permissions restrictive, we can prevent unwanted
+               #  people from seeing that information.
+               detailperm = 0600
+
+               #
+               # Certain attributes such as User-Password may be
+               # "sensitive", so they should not be printed in the
+               # detail file.  This section lists the attributes
+               # that should be suppressed.
+               #
+               # The attributes should be listed one to a line.
+               #
+               #suppress {
+                       # User-Password
+               #}
+       }
+
+       #
+       #  Create a unique accounting session Id.  Many NASes re-use
+       #  or repeat values for Acct-Session-Id, causing no end of
+       #  confusion.
+       #
+       #  This module will add a (probably) unique session id 
+       #  to an accounting packet based on the attributes listed
+       #  below found in the packet.  See doc/rlm_acct_unique for
+       #  more information.
+       #
+       acct_unique {
+               key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port"
+       }
+
+       #  Write a 'utmp' style file, of which users are currently
+       #  logged in, and where they've logged in from.
+       #
+       #  This file is used mainly for Simultaneous-Use checking,
+       #  and also 'radwho', to see who's currently logged in.
+       #
+       radutmp {
+               #  Where the file is stored.  It's not a log file,
+               #  so it doesn't need rotating.
+               #
+               filename = ${logdir}/radutmp
+
+               #  The field in the packet to key on for the
+               #  'user' name,  If you have other fields which you want
+               #  to use to key on to control Simultaneous-Use,
+               #  then you can use them here.
+               #
+               #  Note, however, that the size of the field in the
+               #  'utmp' data structure is small, around 32
+               #  characters, so that will limit the possible choices
+               #  of keys.
+               #
+               #  You may want instead: %{Stripped-User-Name:-%{User-Name}}
+               username = %{User-Name}
+
+
+               #  Whether or not we want to treat "user" the same
+               #  as "USER", or "User".  Some systems have problems
+               #  with case sensitivity, so this should be set to
+               #  'no' to enable the comparisons of the key attribute
+               #  to be case insensitive.
+               #
+               case_sensitive = yes
+
+               #  Accounting information may be lost, so the user MAY
+               #  have logged off of the NAS, but we haven't noticed.
+               #  If so, we can verify this information with the NAS,
+               #
+               #  If we want to believe the 'utmp' file, then this
+               #  configuration entry can be set to 'no'.
+               #
+               check_with_nas = yes            
+
+               # Set the file permissions, as the contents of this file
+               # are usually private.
+               perm = 0600
+
+               callerid = "yes"
+       }
+
+       # "Safe" radutmp - does not contain caller ID, so it can be
+       # world-readable, and radwho can work for normal users, without
+       # exposing any information that isn't already exposed by who(1).
+       #
+       # This is another 'instance' of the radutmp module, but it is given
+       # then name "sradutmp" to identify it later in the "accounting"
+       # section.
+       radutmp sradutmp {
+               filename = ${logdir}/sradutmp
+               perm = 0644
+               callerid = "no"
+       }
+
+       # attr_filter - filters the attributes received in replies from
+       # proxied servers, to make sure we send back to our RADIUS client
+       # only allowed attributes.
+       attr_filter {
+               attrsfile = ${confdir}/attrs
+       }
+
+       #  counter module:
+       #  This module takes an attribute (count-attribute).
+       #  It also takes a key, and creates a counter for each unique
+       #  key.  The count is incremented when accounting packets are
+       #  received by the server.  The value of the increment depends
+       #  on the attribute type.
+       #  If the attribute is Acct-Session-Time or of an integer type we add the
+       #  value of the attribute. If it is anything else we increase the
+       #  counter by one.
+       #
+       #  The 'reset' parameter defines when the counters are all reset to
+       #  zero.  It can be hourly, daily, weekly, monthly or never.
+       #
+       #  hourly: Reset on 00:00 of every hour
+       #  daily: Reset on 00:00:00 every day
+       #  weekly: Reset on 00:00:00 on sunday
+       #  monthly: Reset on 00:00:00 of the first day of each month
+       #
+       #  It can also be user defined. It should be of the form:
+       #  num[hdwm] where:
+       #  h: hours, d: days, w: weeks, m: months
+       #  If the letter is ommited days will be assumed. In example:
+       #  reset = 10h (reset every 10 hours)
+       #  reset = 12  (reset every 12 days)
+       #
+       #
+       #  The check-name attribute defines an attribute which will be
+       #  registered by the counter module and can be used to set the
+       #  maximum allowed value for the counter after which the user
+       #  is rejected.
+       #  Something like:
+       #
+       #  DEFAULT Max-Daily-Session := 36000
+       #          Fall-Through = 1
+       #
+       #  You should add the counter module in the instantiate
+       #  section so that it registers check-name before the files
+       #  module reads the users file.
+       #
+       #  If check-name is set and the user is to be rejected then we
+       #  send back a Reply-Message and we log a Failure-Message in
+       #  the radius.log
+       #  If the count attribute is Acct-Session-Time then on each login
+       #  we send back the remaining online time as a Session-Timeout attribute
+       #
+       #  The counter-name can also be used instead of using the check-name
+       #  like below:
+       #
+       #  DEFAULT  Daily-Session-Time > 3600, Auth-Type = Reject
+       #      Reply-Message = "You've used up more than one hour today"
+       #
+       #  The allowed-servicetype attribute can be used to only take
+       #  into account specific sessions. For example if a user first
+       #  logs in through a login menu and then selects ppp there will
+       #  be two sessions. One for Login-User and one for Framed-User
+       #  service type. We only need to take into account the second one.
+       #
+       #  The module should be added in the instantiate, authorize and
+       #  accounting sections.  Make sure that in the authorize
+       #  section it comes after any module which sets the
+       #  'check-name' attribute.
+       #
+       counter daily {
+               filename = ${raddbdir}/db.daily
+               key = User-Name
+               count-attribute = Acct-Session-Time
+               reset = daily
+               counter-name = Daily-Session-Time
+               check-name = Max-Daily-Session
+               allowed-servicetype = Framed-User
+               cache-size = 5000
+       }
+
+       #
+       # The "always" module is here for debugging purposes. Each
+       # instance simply returns the same result, always, without
+       # doing anything.
+       always fail {
+               rcode = fail
+       }
+       always reject {
+               rcode = reject
+       }
+       always ok {
+               rcode = ok
+               simulcount = 0
+               mpp = no
+       }
+
+       stg {
+               local_port = 6667
+               server = localhost
+               port = 6666
+               password = 123456
+       }
+
+}
+
+# Instantiation
+#
+#  This section orders the loading of the modules.  Modules
+#  listed here will get loaded BEFORE the later sections like
+#  authorize, authenticate, etc. get examined.
+#
+#  This section is not strictly needed.  When a section like
+#  authorize refers to a module, it's automatically loaded and
+#  initialized.  However, some modules may not be listed in any
+#  of the following sections, so they can be listed here.
+#
+#  Also, listing modules here ensures that you have control over
+#  the order in which they are initalized.  If one module needs
+#  something defined by another module, you can list them in order
+#  here, and ensure that the configuration will be OK.
+#
+instantiate {
+       stg
+}
+
+#  Authorization. First preprocess (hints and huntgroups files),
+#  then realms, and finally look in the "users" file.
+#
+#  The order of the realm modules will determine the order that
+#  we try to find a matching realm.
+#
+#  Make *sure* that 'preprocess' comes before any realm if you 
+#  need to setup hints for the remote radius server
+authorize {
+       #
+       #  The preprocess module takes care of sanitizing some bizarre
+       #  attributes in the request, and turning them into attributes
+       #  which are more standard.
+       #
+       #  It takes care of processing the 'raddb/hints' and the
+       #  'raddb/huntgroups' files.
+       #
+       #  It also adds the %{Client-IP-Address} attribute to the request.
+       preprocess
+
+       #
+       #  The chap module will set 'Auth-Type := CHAP' if we are
+       #  handling a CHAP request and Auth-Type has not already been set
+       chap
+
+       #
+       #  If the users are logging in with an MS-CHAP-Challenge
+       #  attribute for authentication, the mschap module will find
+       #  the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP'
+       #  to the request, which will cause the server to then use
+       #  the mschap module for authentication.
+       mschap
+
+       #
+       #  This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP
+       #  authentication.
+       #
+       #  It also sets the EAP-Type attribute in the request
+       #  attribute list to the EAP type from the packet.
+       eap
+
+       stg
+}
+
+
+#  Authentication.
+#
+#
+#  This section lists which modules are available for authentication.
+#  Note that it does NOT mean 'try each module in order'.  It means
+#  that a module from the 'authorize' section adds a configuration
+#  attribute 'Auth-Type := FOO'.  That authentication type is then
+#  used to pick the apropriate module from the list below.
+#
+
+#  In general, you SHOULD NOT set the Auth-Type attribute.  The server
+#  will figure it out on its own, and will do the right thing.  The
+#  most common side effect of erroneously setting the Auth-Type
+#  attribute is that one authentication method will work, but the
+#  others will not.
+#
+#  The common reasons to set the Auth-Type attribute by hand
+#  is to either forcibly reject the user, or forcibly accept him.
+#
+authenticate {
+       #
+       #  PAP authentication, when a back-end database listed
+       #  in the 'authorize' section supplies a password.  The
+       #  password can be clear-text, or encrypted.
+       Auth-Type PAP {
+               stg
+               pap
+       }
+
+       #
+       #  Most people want CHAP authentication
+       #  A back-end database listed in the 'authorize' section
+       #  MUST supply a CLEAR TEXT password.  Encrypted passwords
+       #  won't work.
+       Auth-Type CHAP {
+               stg
+               chap
+       }
+
+       #
+       #  MSCHAP authentication.
+       Auth-Type MS-CHAP {
+               stg
+               mschap
+       }
+
+       #
+       #  Allow EAP authentication.
+       eap
+}
+
+
+#
+#  Pre-accounting.  Decide which accounting type to use.
+#
+preacct {
+       preprocess
+
+       #
+       #  Ensure that we have a semi-unique identifier for every
+       #  request, and many NAS boxes are broken.
+       acct_unique
+}
+
+#
+#  Accounting.  Log the accounting data.
+#
+accounting {
+       #
+       #  Create a 'detail'ed log of the packets.
+       #  Note that accounting requests which are proxied
+       #  are also logged in the detail file.
+       detail
+#      daily
+
+       #
+       #  For Simultaneous-Use tracking.
+       #
+       #  Due to packet losses in the network, the data here
+       #  may be incorrect.  There is little we can do about it.
+       radutmp
+
+       stg
+
+}
+
+
+#  Session database, used for checking Simultaneous-Use. Either the radutmp 
+#  or rlm_sql module can handle this.
+#  The rlm_sql module is *much* faster
+session {
+       radutmp
+}
+
+
+#  Post-Authentication
+#  Once we KNOW that the user has been authenticated, there are
+#  additional steps we can take.
+post-auth {
+       stg
+}
+
+#
+#  When the server decides to proxy a request to a home server,
+#  the proxied request is first passed through the pre-proxy
+#  stage.  This stage can re-write the request, or decide to
+#  cancel the proxy.
+#
+#  Only a few modules currently have this method.
+#
+pre-proxy {
+}
+
+#
+#  When the server receives a reply to a request it proxied
+#  to a home server, the request may be massaged here, in the
+#  post-proxy stage.
+#
+post-proxy {
+       #
+       #  If you are proxying LEAP, you MUST configure the EAP
+       #  module, and you MUST list it here, in the post-proxy
+       #  stage.
+       #
+       #  You MUST also use the 'nostrip' option in the 'realm'
+       #  configuration.  Otherwise, the User-Name attribute
+       #  in the proxied request will not match the user name
+       #  hidden inside of the EAP packet, and the end server will
+       #  reject the EAP request.
+       #
+       eap
+}
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/ppp/ip-down.d/stg b/projects/stargazer/scripts/shaper_vpn_radius/ppp/ip-down.d/stg
new file mode 100755 (executable)
index 0000000..e9c7eaf
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+rm -f /var/stargazer/ifaces/$PPP_REMOTE
\ No newline at end of file
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/ppp/ip-up.d/stg b/projects/stargazer/scripts/shaper_vpn_radius/ppp/ip-up.d/stg
new file mode 100755 (executable)
index 0000000..6a0b645
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo $PPP_IFACE > /var/stargazer/ifaces/$PPP_REMOTE
\ No newline at end of file
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/ppp/pptpd-options b/projects/stargazer/scripts/shaper_vpn_radius/ppp/pptpd-options
new file mode 100644 (file)
index 0000000..af58ba4
--- /dev/null
@@ -0,0 +1,97 @@
+###############################################################################
+# $Id: pptpd-options,v 1.1 2008/03/31 13:55:20 faust Exp $
+#
+# Sample Poptop PPP options file /etc/ppp/pptpd-options
+# Options used by PPP when a connection arrives from a client.
+# This file is pointed to by /etc/pptpd.conf option keyword.
+# Changes are effective on the next connection.  See "man pppd".
+#
+# You are expected to change this file to suit your system.  As
+# packaged, it requires PPP 2.4.2 and the kernel MPPE module.
+###############################################################################
+
+
+# Authentication
+
+# Name of the local system for authentication purposes 
+# (must match the second field in /etc/ppp/chap-secrets entries)
+name pptpd
+
+# Optional: domain name to use for authentication
+# domain mydomain.net
+
+# Strip the domain prefix from the username before authentication.
+# (applies if you use pppd with chapms-strip-domain patch)
+#chapms-strip-domain
+
+
+# Encryption
+# Debian: on systems with a kernel built with the package
+# kernel-patch-mppe >= 2.4.2 and using ppp >= 2.4.2, ...
+# {{{
+refuse-pap
+refuse-chap
+refuse-mschap
+# Require the peer to authenticate itself using MS-CHAPv2 [Microsoft
+# Challenge Handshake Authentication Protocol, Version 2] authentication.
+require-mschap-v2
+# Require MPPE 128-bit encryption
+# (note that MPPE requires the use of MSCHAP-V2 during authentication)
+require-mppe-128
+# }}}
+
+
+
+
+# Network and Routing
+
+# If pppd is acting as a server for Microsoft Windows clients, this
+# option allows pppd to supply one or two DNS (Domain Name Server)
+# addresses to the clients.  The first instance of this option
+# specifies the primary DNS address; the second instance (if given)
+# specifies the secondary DNS address.
+# Attention! This information may not be taken into account by a Windows
+# client. See KB311218 in Microsoft's knowledge base for more information.
+#ms-dns 10.0.0.1
+#ms-dns 10.0.0.2
+
+# If pppd is acting as a server for Microsoft Windows or "Samba"
+# clients, this option allows pppd to supply one or two WINS (Windows
+# Internet Name Services) server addresses to the clients.  The first
+# instance of this option specifies the primary WINS address; the
+# second instance (if given) specifies the secondary WINS address.
+#ms-wins 10.0.0.3
+#ms-wins 10.0.0.4
+
+# Add an entry to this system's ARP [Address Resolution Protocol]
+# table with the IP address of the peer and the Ethernet address of this
+# system.  This will have the effect of making the peer appear to other
+# systems to be on the local ethernet.
+# (you do not need this if your PPTP server is responsible for routing
+# packets to the clients -- James Cameron)
+proxyarp
+
+# Debian: do not replace the default route
+defaultroute
+
+
+# Logging
+
+# Enable connection debugging facilities.
+# (see your syslog configuration for where pppd sends to)
+#debug
+
+# Print out all the option values which have been set.
+# (often requested by mailing list to verify options)
+#dump
+
+
+# Miscellaneous
+
+# Create a UUCP-style lock file for the pseudo-tty to ensure exclusive
+# access.
+lock
+
+# Disable BSD-Compress compression
+nobsdcomp 
+plugin radius.so
\ No newline at end of file
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/pptpd.conf b/projects/stargazer/scripts/shaper_vpn_radius/pptpd.conf
new file mode 100644 (file)
index 0000000..5c64b83
--- /dev/null
@@ -0,0 +1,82 @@
+###############################################################################
+# $Id: pptpd.conf,v 1.1 2008/03/31 13:54:13 faust Exp $
+#
+# Sample Poptop configuration file /etc/pptpd.conf
+#
+# Changes are effective when pptpd is restarted.
+###############################################################################
+
+# TAG: ppp
+#      Path to the pppd program, default '/usr/sbin/pppd' on Linux
+#
+#ppp /usr/sbin/pppd
+
+# TAG: option
+#      Specifies the location of the PPP options file.
+#      By default PPP looks in '/etc/ppp/options'
+#
+option /etc/ppp/pptpd-options
+
+# TAG: debug
+#      Turns on (more) debugging to syslog
+#
+#debug
+
+# TAG: stimeout
+#      Specifies timeout (in seconds) on starting ctrl connection
+#
+# stimeout 10
+
+# TAG: noipparam
+#       Suppress the passing of the client's IP address to PPP, which is
+#       done by default otherwise.
+#
+#noipparam
+
+# TAG: logwtmp
+#      Use wtmp(5) to record client connections and disconnections.
+#
+logwtmp
+
+# TAG: bcrelay <if>
+#      Turns on broadcast relay to clients from interface <if>
+#
+#bcrelay eth1
+
+# TAG: localip
+# TAG: remoteip
+#      Specifies the local and remote IP address ranges.
+#
+#       Any addresses work as long as the local machine takes care of the
+#       routing.  But if you want to use MS-Windows networking, you should
+#       use IP addresses out of the LAN address space and use the proxyarp
+#       option in the pppd options file, or run bcrelay.
+#
+#      You can specify single IP addresses seperated by commas or you can
+#      specify ranges, or both. For example:
+#
+#              192.168.0.234,192.168.0.245-249,192.168.0.254
+#
+#      IMPORTANT RESTRICTIONS:
+#
+#      1. No spaces are permitted between commas or within addresses.
+#
+#      2. If you give more IP addresses than MAX_CONNECTIONS, it will
+#         start at the beginning of the list and go until it gets 
+#         MAX_CONNECTIONS IPs. Others will be ignored.
+#
+#      3. No shortcuts in ranges! ie. 234-8 does not mean 234 to 238,
+#         you must type 234-238 if you mean this.
+#
+#      4. If you give a single localIP, that's ok - all local IPs will
+#         be set to the given one. You MUST still give at least one remote
+#         IP for each simultaneous client.
+#
+# (Recommended)
+#localip 192.168.0.1
+#remoteip 192.168.0.234-238,192.168.0.245
+# or
+#localip 192.168.0.234-238,192.168.0.245
+#remoteip 192.168.1.234-238,192.168.1.245
+localip 192.168.2.1
+remoteip 192.168.2.2-254
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/radiusclient/servers b/projects/stargazer/scripts/shaper_vpn_radius/radiusclient/servers
new file mode 100644 (file)
index 0000000..03a1d94
--- /dev/null
@@ -0,0 +1 @@
+localhost testing123
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnChange b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnChange
new file mode 100755 (executable)
index 0000000..a927228
--- /dev/null
@@ -0,0 +1,6 @@
+login=$1
+param=$2
+oldValue=$3
+newValue=$4
+
+#echo "User: '$login'. Parameter $param changed from '$oldValue' to '$newValue'" >> /var/stargazer/users.chg.log
\ No newline at end of file
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnConnect b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnConnect
new file mode 100755 (executable)
index 0000000..099a219
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+#Этот скрипт вызывается в момент, когда пользователь
+#успешно прошел авторизацию на сервере. Задача скрипта - перестроить 
+#файрвол так, что бы пользователь получил доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to connect
+DIRS=$5
+
+iptables -A INPUT -s $IP -j QUEUE
+iptables -A OUTPUT -d $IP -j QUEUE
+iptables -A FORWARD -s $IP -j QUEUE
+iptables -A FORWARD -d $IP -j QUEUE
+
+# shaper
+
+default_speed=32
+
+speedR=$(grep -i "^Userdata0=" /var/stargazer/users/$LOGIN/conf | cut -f 2 -d"=")
+#echo "speedR=$speedR" >> /var/stargazer/users/$LOGIN/connect.log
+speed=$(echo $speedR | grep "^[0-9]*[0-9]$")
+
+if [ -z "$speed" ] 
+then
+    speed=$default_speed
+fi
+
+speedkbit=$speed"kbit"
+
+#echo "speed=$speedkbit" >> /var/stargazer/users/$LOGIN/connect.log
+declare -i mark=$ID+1
+
+iptables -t mangle -A FORWARD -d $IP -j MARK --set-mark $mark
+
+sleep 1
+
+if [ -f "/var/stargazer/ifaces/$IP" ]
+then
+    #echo "1" >> /var/stargazer/users/$LOGIN/connect.log
+    ppp_iface=$(cat /var/stargazer/ifaces/$IP)
+else
+    #echo "2" >> /var/stargazer/users/$LOGIN/connect.log
+    exit 0
+fi
+
+tc qdisc add dev $ppp_iface root handle 1: htb
+tc class add dev $ppp_iface parent 1: classid 1:1 htb rate 100mbit ceil 100mbit burst 200k
+tc class add dev $ppp_iface parent 1:1 classid 1:10 htb rate $speedkbit burst 20k
+tc filter add dev $ppp_iface parent 1: protocol ip prio 3 handle $mark fw classid 1:10
+
+#echo "C `date +%Y.%m.%d-%H.%M.%S` $IP $CASH $ID $mark $speed $ppp_iface" >> /var/stargazer/users/$LOGIN/connect.log
+
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnDisconnect b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnDisconnect
new file mode 100755 (executable)
index 0000000..f6b387b
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+# Этот скрипт вызывается в момент, когда пользователь
+# желает отключится от интернета или вышел таймаут у пользователя
+# и сервер сам отключает пользователя
+# Задача скрипта подобна задаче скрипта OnConnect - перестроить 
+# файрвол так, что бы пользователю закрыть доступ в интернет
+
+# Login
+LOGIN=$1
+
+#user IP
+IP=$2
+
+#cash
+CASH=$3
+
+#user ID
+ID=$4
+
+#Selected dirs to disconnect
+DIRS=$4
+
+#echo "D `date +%Y.%m.%d-%H.%M.%S` $IP $CASH" >> /var/stargazer/users/$LOGIN/connect.log
+
+iptables -D INPUT -s $IP -j QUEUE
+while [ $? == 0 ]
+do
+    iptables -D INPUT -s $IP -j QUEUE
+done
+
+iptables -D OUTPUT -d $IP -j QUEUE
+while [ $? == 0 ]
+do
+    iptables -D OUTPUT -d $IP -j QUEUE
+done
+
+iptables -D FORWARD -s $IP -j QUEUE
+while [ $? == 0 ]
+do
+    iptables -D FORWARD -s $IP -j QUEUE
+done
+
+iptables -D FORWARD -d $IP -j QUEUE
+while [ $? == 0 ]
+do
+    iptables -D FORWARD -d $IP -j QUEUE
+done
+
+
+
+declare -i mark=$ID+1
+
+iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+while [ $? == 0 ]
+do
+    iptables -t mangle -D FORWARD -d $IP -j MARK --set-mark $mark
+done
+
+
+if [ -f /var/stargazer/ifaces/$IP ]
+    ppp_iface=$(cat /var/stargazer/ifaces/$IP)
+else
+    exit 0
+fi
+
+tc qdisc del dev $ppp_iface root
+
+
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnUserAdd b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnUserAdd
new file mode 100755 (executable)
index 0000000..a3ee3a9
--- /dev/null
@@ -0,0 +1,12 @@
+# Использование (неиспользование) этого скрипта дело вкуса.
+# Он не выполняет критических функций. Его задача автматизировать
+# действия характерные при добавлении пользователя сети, например добавлекние 
+# пользователю почты
+
+# Login
+login=$1
+
+#echo "added user $login" >> /var/stargazer/add_del.log
+
+
+
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnUserDel b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/OnUserDel
new file mode 100755 (executable)
index 0000000..3be6046
--- /dev/null
@@ -0,0 +1,5 @@
+# Login
+login=$1
+
+#echo "deleted user $login" >> /var/stargazer/add_del.log
+
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/rules b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/rules
new file mode 100644 (file)
index 0000000..3fb4828
--- /dev/null
@@ -0,0 +1,3 @@
+ALL     192.168.0.0/16  DIR1 
+ALL     10.0.0.0/8      DIR2
+ALL     0.0.0.0/0       DIR0
\ No newline at end of file
diff --git a/projects/stargazer/scripts/shaper_vpn_radius/stargazer/stargazer.conf b/projects/stargazer/scripts/shaper_vpn_radius/stargazer/stargazer.conf
new file mode 100644 (file)
index 0000000..221c85c
--- /dev/null
@@ -0,0 +1,298 @@
+
+# Имя лог-файла куда пишутся события
+LogFile = /var/log/stargazer.log
+
+
+
+# Имя файла в котором определяются правила подсчета трафика
+Rules = /etc/stargazer/rules
+
+
+
+# Время через которое пишется d БД детальная статистика пользователя
+# Значения: 1, 1/2, 1/4, 1/6.
+# 1 - раз в чаc, 1/2 - раз в пол часа, 1/4 - раз в 15 мин, 1/6 - раз в 10 мин
+DetailStatWritePeriod=1/6
+
+
+
+# Периодичность записи записи в БД информации о статистике пользователя (минуты)
+# При большом кол-ве пользователей эту величину стоит увеличить, т.к.
+# запись в БД может занимать длительное время.
+# Значения: 1...1440 (минуты)
+StatWritePeriod = 10
+
+
+
+# День снятия абонплаты
+# Значения: 0...31. 0 - Последний день месяца
+DayFee = 1
+
+
+
+# Абонплата снимается в последний (yes) или первый (no) день учетного периода.
+# Это влияет на то, как будет снята абонплата (АП) при переходе на новый тариф.
+# Если у пользователя был тариф A с АП=100 и он хочет перейти на тариф B с АП=200,
+# то при переходе на новый тариф со счета пользователя снимется 100, если
+# DayFeeIsLastDay = yes и 200, если DayFeeIsLastDay = no
+DayFeeIsLastDay = yes
+
+
+
+# День сброса данных о трафике за месяц и день перехода пользователей на новые тарифы
+# Значения: 0...31. 0 - Последний день месяца
+DayResetTraff = 1
+
+
+
+# "Размазанное" снятие абонплаты. Снятие АП не раз в месяц, а каждый
+# день 1/30 или 1/31 части АП
+# Значения: yes, no
+SpreadFee = no
+
+
+
+# Данная опция определяет может ли пользователь получить доступ в интерент
+# если у него на счету нет денег, но остался предоплаченный трафик
+# Значения: yes, no
+FreeMbAllowInet = no
+
+
+
+# Эта опция определяет что будет писаться в стоимость трафика в detail_stat.
+# Если у пользователя еще есть предоплаченный трафик и WriteFreeMbTraffCost = no,
+# то в detail_stat стоимость будет 0. Если у пользователя уже нет
+# предоплаченного трафика и WriteFreeMbTraffCost = no, то в detail_stat
+# будет записана стоиость трафика. При WriteFreeMbTraffCost = yes стоимость
+# трафика будет записана в любом случае.
+WriteFreeMbTraffCost = no
+
+
+
+# Необязательный параметр. Указывает снимать полную абонплату у пользователя даже
+# если он быз заморожен только часть учетного периода.
+# По умолчанию установлен в no
+# FullFee=no
+
+# Необязательный параметр указывающий показывать на счету и позволять 
+# использовать пользователю абонплату. По умолчанию установлен в yes
+# ShowFeeInCash=yes
+
+
+
+# Названия направлений. Направления без названий не будут отображаться в
+# авторизаторе и конфигураторе. Названия состоящие из нескольких слов должны
+# быть взяты в кавычки
+<DirNames>
+    DirName0 = Local
+    DirName1 = City
+    DirName2 = World
+    DirName3 =
+    DirName4 =
+    DirName5 =
+    DirName6 =
+    DirName7 =
+    DirName8 =
+    DirName9 =
+</DirNames>
+
+
+
+# Кол-во запускаемых процессов stg-exec.
+# Эти процессы отвечают за выполнение скриптов OnConnect, OnDisconnect, ...
+# Кол-во процессов означает сколько скриптов могут выполнятся одновременно.
+# Значения: 1...1024
+ExecutersNum = 2
+
+
+
+# Message Key для stg-exec.
+# Идентификатор очереди сообщений для выполнятеля скриптов.
+# Его изменение может понадобится если есть необходимость запустить несколько
+# экземпляров stg. Если вы не понимаете, что это, не трогайте этот параметр!
+# Значения: 0...2^32
+# Значение по умолчанию: 5555
+# ExecMsgKey = 5555
+
+
+
+# Путь к директории, в которой находятся модули сервера
+ModulesPath = /usr/lib/stg
+
+# Определяет директорию, в которой будут находится файлы "монитора"
+# работы сервера. В этой директории будут созданы пустые файлы, время 
+# модификации которых будет меняться примерно раз в минуту. Если какой-то 
+# компонент сервера зависнет, файл(ы) перестанет обновлятся, и по этому 
+# признаку можно определить сбой в работе сервера и при надобности 
+# перезапустить. Если параметр не указан или пустой, мониторинг производится 
+# не будет. Параметр не является обязательным, по умолчанию пустой.
+# MonitorDir=/var/stargazer/monitor
+
+
+################################################################################
+# Store module
+# Настройки плагина работающего с БД сервера
+
+# Второй параметр - это имя модуля без mod_ в начале и .so в конце
+# Т.е. полное имя модуля mod_store_files.so
+<StoreModule store_files>
+
+    # Рабочая директория сервера, тут содержатся данные о тарифах, пользователях,
+    # администраторах и т.д.
+    WorkDir = /var/stargazer
+
+
+    # Владелец, группа и права доступа на файлы статистики (stat) пользователя
+    ConfOwner = root
+    ConfGroup = root
+    ConfMode = 600
+
+
+    # Владелец, группа и права доступа на файлы конфигурации (conf) пользователя
+    StatOwner = root
+    StatGroup = root
+    StatMode = 640
+
+    # Владелец, группа и права доступа на лог-файлы (log) пользователя
+    UserLogOwner = root
+    UserLogGroup = root
+    UserLogMode = 640
+
+</StoreModule>
+
+#<StoreModule store_firebird>
+#    # Адрес сервера БД
+#    server=localhost
+#
+#    # Путь к БД на сервере или ее алиас
+#    path=/var/stg/stargazer.fdb
+#
+#    # Имя пользователя БД
+#    user=stg
+#
+#    # Пароль пользователя БД
+#    password=123456
+#</StoreModule>
+
+#<StoreModule store_mysql>
+#    # Имя пользователя БД
+#    dbuser = stg
+#
+#    # Пароль пользователя БД
+#    rootdbpass = 123456
+#
+#    # Имя БД на сервере
+#    dbname = stg
+#
+#    # Адрес сервера БД
+#    dbhost = localhost
+#</StoreModule>
+
+
+
+################################################################################
+# Прочие модули
+
+<Modules>
+
+    # Настройки плагина авторизации Always Online "mod_auth_ao.so"
+    # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+    # Т.е. полное имя модуля mod_auth_ao.so
+    #<Module auth_ao>
+    #</Module>
+
+
+
+    # Настройки плагина авторизации InetAccess "mod_auth_ia.so"
+    # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+    # Т.е. полное имя модуля mod_auth_ia.so
+    #<Module auth_ia>
+    #    Port = 5555
+    #    UserDelay = 15
+    #    UserTimeout = 65
+    #    FreeMb = 0
+    #</Module>
+
+
+
+    # Настройки модуля конфигурации SgConfig "mod_conf_sg.so"
+    # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+    <Module conf_sg>
+
+        # Порт по которому сервер взаимодействует с конфигуратором
+        # Значения: 1...65535
+        Port = 5555
+
+    </Module>
+
+
+
+    # Модуль захвата трафика "mod_cap_ether.so"
+    # Второй параметер - это имя модуля без mod_ в начале и .so в конце
+    # Без параметров. Только имя модуля.
+    <Module cap_ipq>
+        # Модуль без параметров
+    </Module>
+
+
+
+    # Настройки модуля пингующего пользователей "mod_ping.so"
+    # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+    <Module ping>
+
+        # Время, в секундах, между пингами одного и того же пользователя
+        # Значения: 10...3600
+        PingDelay = 15
+
+    </Module>
+    
+    <Module radius>
+       Password = 123456
+       ServerIP = 127.0.0.1
+       Port = 6666
+       AuthServices = Login-User
+       AcctServices = Framed-User
+    </Module>
+
+#    # Настройки модуля для удаленного выполнения скриптов OnConnect и
+#    # OnDisconnect "mod_remote_script.so"
+#    # Второй параметр - это имя модуля без mod_ в начале и .so в конце
+#    <Module remote_script>
+#
+#        # Время, в секундах, между посылками подтверждений, того, что пользователь
+#        # всё еще онлайн
+#        # Значения: 10...600
+#        SendPeriod = 15
+#
+#        # Соответствие подсетей, в которой находится пользователь и
+#        # соответствующего роутера. Первая часть строки - подсеть, заданная
+#        # как IP-адрес и маска, через пробел - IP-адрес роутера на котором
+#        # должны выполняться скрипты
+#        # Например эта запись "192.168.1.0/24 192.168.1.1" означает, что для
+#        # всех пользователей из подсети 192.168.1.0/24, скрипты будут
+#        # выполняться на роутере с адресом 192.168.1.1
+#        # Subnet0...Subnet100
+#        Subnet0 = 192.168.1.0/24 192.168.1.7
+#        Subnet1 = 192.168.2.0/24 192.168.2.5
+#        Subnet2 = 192.168.3.0/24 192.168.2.5
+#        Subnet3 = 192.168.4.0/24 192.168.2.5
+#
+#        # Пароль для шифрования пакетов между stg-сервером и сервером,
+#        # выполняющим скрипты
+#        Password = 123456
+#
+#        # Этот параметр определяет какие параметры пользователя передаются
+#        # на удаленный сервер
+#        # Cash, FreeMb, Passive, Disabled, AlwaysOnline, TariffName, NextTariff, Address,
+#        # Note, Group, Email, RealName, Credit, EnabledDirs, Userdata0...Userdata9
+#        UserParams=Cash Tariff EnabledDirs
+#
+#        # Порт по которому сервер отсылает сообщения на роутер
+#        # Значения: 1...65535
+#        Port = 9999
+#
+#    </Module>
+
+</Modules>
+################################################################################
+
diff --git a/projects/stargazer/settings.cpp b/projects/stargazer/settings.cpp
new file mode 100644 (file)
index 0000000..9fcacc0
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ *    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>
+ */
+
+/*
+$Revision: 1.45 $
+$Date: 2010/08/19 13:42:30 $
+$Author: faust $
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+
+using namespace std;
+
+#include "settings.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+SETTINGS::SETTINGS()
+    : confDir("/etc/stargazer"),
+      scriptDir("/etc/stargazer"),
+      pidFile("/var/run/stargazer.pid"),
+      monitoring(false),
+      detailStatWritePeriod(dsPeriod_1_6),
+      statWritePeriod(10),
+      stgExecMsgKey(5555),
+      executersNum(1),
+      fullFee(false),
+      dayFee(0),
+      dayResetTraff(0),
+      spreadFee(false),
+      freeMbAllowInet(false),
+      dayFeeIsLastDay(false),
+      writeFreeMbTraffCost(false),
+      showFeeInCash(true),
+      logger(GetStgLogger())
+{
+}
+//-----------------------------------------------------------------------------
+SETTINGS::SETTINGS(const std::string & cd)
+    : confDir(cd),
+      scriptDir(cd),
+      pidFile(),
+      monitoring(false),
+      detailStatWritePeriod(dsPeriod_1_6),
+      statWritePeriod(10),
+      stgExecMsgKey(5555),
+      executersNum(1),
+      fullFee(false),
+      dayFee(0),
+      dayResetTraff(0),
+      spreadFee(false),
+      freeMbAllowInet(false),
+      dayFeeIsLastDay(false),
+      writeFreeMbTraffCost(false),
+      showFeeInCash(true),
+      logger(GetStgLogger())
+{
+}
+//-----------------------------------------------------------------------------
+SETTINGS::SETTINGS(const SETTINGS & rval)
+    : confDir(rval.confDir),
+      scriptDir(rval.scriptDir),
+      detailStatWritePeriod(dsPeriod_1_6),
+      statWritePeriod(10),
+      dayFee(0),
+      dayResetTraff(0),
+      freeMbAllowInet(false),
+      dayFeeIsLastDay(false),
+      writeFreeMbTraffCost(false),
+      logger(GetStgLogger())
+{
+spreadFee = rval.spreadFee;
+pidFile = rval.pidFile;
+stgExecMsgKey = rval.stgExecMsgKey;
+executersNum = rval.executersNum;
+showFeeInCash = rval.showFeeInCash;
+fullFee = rval.fullFee;
+monitoring = rval.monitoring;
+}
+//-----------------------------------------------------------------------------
+SETTINGS::~SETTINGS()
+{
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseYesNo(const string & value, bool * val)
+{
+if (0 == strcasecmp(value.c_str(), "yes"))
+    {
+    *val = true;
+    return 0;
+    }
+if (0 == strcasecmp(value.c_str(), "no"))
+    {
+    *val = false;
+    return 0;
+    }
+
+strError = "Incorrect value \'" + value + "\'.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseInt(const string & value, int * val)
+{
+/*char *res;
+*val = strtol(value.c_str(), &res, 10);*/
+if (str2x<int>(value, *val))
+    {
+    strError = "Cannot convert \'" + value + "\' to integer.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseIntInRange(const string & value, int min, int max, int * val)
+{
+if (ParseInt(value, val) != 0)
+    return -1;
+
+if (*val < min || *val > max)
+    {
+    strError = "Value \'" + value + "\' out of range.";
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseModuleSettings(const DOTCONFDocumentNode * node, vector<PARAM_VALUE> * params)
+{
+/*if (!node)
+    return 0;*/
+const DOTCONFDocumentNode * childNode;
+PARAM_VALUE pv;
+const char * value;
+
+pv.param = node->getName();
+
+if (node->getValue(1))
+    {
+    strError = "Unexpected value \'" + string(node->getValue(1)) + "\'.";
+    return -1;
+    }
+
+value = node->getValue(0);
+
+if (!value)
+    {
+    strError = "Module name expected.";
+    return -1;
+    }
+
+childNode = node->getChildNode();
+while (childNode)
+    {
+    pv.param = childNode->getName();
+    int i = 0;
+    while ((value = childNode->getValue(i)) != NULL)
+        {
+        //printfd(__FILE__, "--> param=\'%s\' value=\'%s\'\n", childNode->getName(), value);
+        pv.value.push_back(value);
+        i++;
+        }
+    params->push_back(pv);
+    pv.value.clear();
+    childNode = childNode->getNextNode();
+    }
+
+/*for (unsigned i = 0; i < params->size(); i++)
+    {
+    printfd(__FILE__, "param \'%s\'\n", (*params)[i].param.c_str());
+    for (unsigned j = 0; j < (*params)[i].value.size(); j++)
+        {
+        printfd(__FILE__, "value \'%s\'\n", (*params)[i].value[j].c_str());
+        }
+    }*/
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+string SETTINGS::GetStrError() const
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+void SETTINGS::ErrorCallback(void * data, const char * buf)
+{
+    printfd(__FILE__, buf);
+    SETTINGS * settings = static_cast<SETTINGS *>(data);
+    settings->logger(buf);
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ReadSettings()
+{
+const char * requiredOptions[] = {
+    "ModulesPath",
+    "Modules",
+    "StoreModule",
+    "Rules",
+    "LogFile",
+    "DetailStatWritePeriod",
+    "DayFee",
+    "DayResetTraff",
+    "SpreadFee",
+    "FreeMbAllowInet",
+    "DayFeeIsLastDay",
+    "WriteFreeMbTraffCost",
+    NULL
+    };
+int storeModulesCount = 0;
+modulesSettings.clear();
+
+DOTCONFDocument conf(DOTCONFDocument::CASEINSENSITIVE);
+conf.setErrorCallback(SETTINGS::ErrorCallback, this);
+conf.setRequiredOptionNames(requiredOptions);
+string confFile = confDir + "/stargazer.conf";
+
+//printfd(__FILE__, "Conffile: %s\n", confFile.c_str());
+
+if(conf.setContent(confFile.c_str()) != 0)
+    {
+    strError = "Cannot read file " + confFile;
+    return -1;
+    }
+
+const DOTCONFDocumentNode * node = conf.getFirstNode();
+
+while (node)
+    {
+    if (strcasecmp(node->getName(), "ScriptDir") == 0)
+        {
+        scriptDir = node->getValue(0);
+        //printfd(__FILE__, "LogFile: %s\n", logFile.c_str());
+        }
+
+    if (strcasecmp(node->getName(), "LogFile") == 0)
+        {
+        logFile = node->getValue(0);
+        //printfd(__FILE__, "LogFile: %s\n", logFile.c_str());
+        }
+
+    if (strcasecmp(node->getName(), "PIDFile") == 0)
+        {
+        pidFile = node->getValue(0);
+        //printfd(__FILE__, "PIDFile: %s\n", pidFile.c_str());
+        }
+
+    if (strcasecmp(node->getName(), "ModulesPath") == 0)
+        {
+        modulesPath = node->getValue(0);
+        //printfd(__FILE__, "ModulesPath: %s\n", logFile.c_str());
+        }
+
+    if (strcasecmp(node->getName(), "Rules") == 0)
+        {
+        rules = node->getValue(0);
+        //printfd(__FILE__, "Rules: %s\n", rules.c_str());
+        }
+
+    if (strcasecmp(node->getName(), "DetailStatWritePeriod") == 0)
+        {
+        if (ParseDetailStatWritePeriod(node->getValue(0)) != 0)
+            {
+            strError = "Incorrect DetailStatWritePeriod value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DetailStatWritePeriod: %d\n", detailStatWritePeriod);
+        }
+
+    if (strcasecmp(node->getName(), "StatWritePeriod") == 0)
+        {
+        if (ParseIntInRange(node->getValue(0), 1, 1440, &statWritePeriod) != 0)
+            {
+            strError = "Incorrect StatWritePeriod value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "StatWritePeriod: %d\n", statWritePeriod);
+        }
+
+    if (strcasecmp(node->getName(), "ExecMsgKey") == 0)
+        {
+        if (ParseInt(node->getValue(0), &stgExecMsgKey) != 0)
+            {
+            strError = "Incorrect ExecMsgKey value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        }
+
+    if (strcasecmp(node->getName(), "ExecutersNum") == 0)
+        {
+        if (ParseIntInRange(node->getValue(0), 1, 1024, &executersNum) != 0)
+            {
+            strError = "Incorrect ExecutersNum value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DayResetTraff: %d\n", dayResetTraff);
+        }
+
+    /*if (strcasecmp(node->getName(), "ExecutersWaitTimeout") == 0)
+        {
+        if (ParseIntInRange(node->getValue(0), 1, 600, &executersWaitTimeout) != 0)
+            {
+            strError = "Incorrect ExecutersWaitTimeout value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DayResetTraff: %d\n", dayResetTraff);
+        }*/
+
+    if (strcasecmp(node->getName(), "DayFee") == 0)
+        {
+        if (ParseIntInRange(node->getValue(0), 0, 31, &dayFee) != 0)
+            {
+            strError = "Incorrect DayFee value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DayFee: %d\n", dayFee);
+        }
+
+    if (strcasecmp(node->getName(), "FullFee") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &fullFee) != 0)
+            {
+            strError = "Incorrect FullFee value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DayFee: %d\n", dayFee);
+        }
+
+    if (strcasecmp(node->getName(), "DayResetTraff") == 0)
+        {
+        if (ParseIntInRange(node->getValue(0), 0, 31, &dayResetTraff) != 0)
+            {
+            strError = "Incorrect DayResetTraff value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DayResetTraff: %d\n", dayResetTraff);
+        }
+
+    if (strcasecmp(node->getName(), "SpreadFee") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &spreadFee) != 0)
+            {
+            strError = "Incorrect SpreadFee value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "SpreadFee: %d\n", spreadFee);
+        }
+
+    if (strcasecmp(node->getName(), "FreeMbAllowInet") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &freeMbAllowInet) != 0)
+            {
+            strError = "Incorrect FreeMbAllowInet value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "FreeMbAllowInet: %d\n", freeMbAllowInet);
+        }
+
+    if (strcasecmp(node->getName(), "DayFeeIsLastDay") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &dayFeeIsLastDay) != 0)
+            {
+            strError = "Incorrect DayFeeIsLastDay value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "DayFeeIsLastDay: %d\n", dayFeeIsLastDay);
+        }
+
+    if (strcasecmp(node->getName(), "WriteFreeMbTraffCost") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &writeFreeMbTraffCost) != 0)
+            {
+            strError = "Incorrect WriteFreeMbTraffCost value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "WriteFreeMbTraffCost: %d\n", writeFreeMbTraffCost);
+        }
+
+    if (strcasecmp(node->getName(), "ShowFeeInCash") == 0)
+        {
+        if (ParseYesNo(node->getValue(0), &showFeeInCash) != 0)
+            {
+            strError = "Incorrect ShowFeeInCash value: \'" + string(node->getValue(0)) + "\'";
+            return -1;
+            }
+        //printfd(__FILE__, "ShowFeeInCash: %d\n", showFeeInCash);
+        }
+
+    if (strcasecmp(node->getName(), "MonitorDir") == 0)
+        {
+        monitorDir = node->getValue(0);
+        struct stat stat;
+        monitoring = false;
+
+        if (!lstat(monitorDir.c_str(), &stat) && S_ISDIR(stat.st_mode))
+            {
+            monitoring = true;
+            }
+        }
+
+    if (strcasecmp(node->getName(), "DirNames") == 0)
+        {
+        // íÙ ×ÎÕÔÒÉ ÓÅËÃÉÉ DirNames
+        const DOTCONFDocumentNode * child = node->getChildNode();
+        if (child)
+            {
+            const DOTCONFDocumentNode * dirNameNode;
+            for (int i = 0; i < DIR_NUM; i++)
+                {
+                char strDirName[12];
+                sprintf(strDirName, "DirName%d", i);
+                dirNameNode = conf.findNode(strDirName, node);
+                if (dirNameNode && dirNameNode->getValue(0))
+                    {
+                    dirName[i] = dirNameNode->getValue(0);
+                    //printfd(__FILE__, "dirName[%d]: %s\n", i, dirName[i].c_str());
+                    }
+                }
+            }
+        }
+
+    if (strcasecmp(node->getName(), "StoreModule") == 0)
+        {
+        // íÙ ×ÎÕÔÒÉ ÓÅËÃÉÉ StoreModule
+        //printfd(__FILE__, "StoreModule\n");
+
+        if (node->getValue(1))
+            {
+            // StoreModule ÄÏÌÖÅΠÉÍÅÔØ 1 ÁÔÒÉÂÕÔ
+            strError = "Unexpected \'" + string(node->getValue(1)) + "\'.";
+            return -1;
+            }
+
+        if (storeModulesCount)
+            {
+            // äÏÌÖÅΠÂÙÔØ ÔÏÌØËÏ ÏÄÉΠÍÏÄÕÌØ StoreModule!
+            strError = "Should be only one StoreModule.";
+            return -1;
+            }
+        storeModulesCount++;
+
+        //storeModuleSettings.clear(); //TODO To make constructor
+        //printfd(__FILE__, "StoreModule %s\n", node->getValue());
+        storeModuleSettings.moduleName = node->getValue(0);
+        ParseModuleSettings(node, &storeModuleSettings.moduleParams);
+        }
+
+    // þÉÔÁÅÍ ÎÁÓÔÒÏÊËÉ ×ÓÅÈ ÏÓÔÁ×ÛÉÈÓÑ ÍÏÄÕÌÅÊ.
+    if (strcasecmp(node->getName(), "Modules") == 0)
+        {
+        // íÙ ×ÎÕÔÒÉ ÓÅËÃÉÉ Modules
+        if (node->getValue(0))
+            {
+            // Modules ÎÅ ÄÏÌÖÅΠÉÍÅÔØ ÁÔÒÉÂÕÏ×
+            strError = "Unexpected \'" + string(node->getValue(0)) + "\'.";
+            return -1;
+            }
+        const DOTCONFDocumentNode * child = node->getChildNode();
+        while (child)
+            {
+            // íÙ ×ÎÕÔÒÉ ÓÅËÃÉÉ
+            //printfd(__FILE__, "Module \'%s\'\n", child->getValue(0));
+            if (strcasecmp(child->getName(), "Module") != 0)
+                {
+                child = child->getNextNode();
+                continue;
+                }
+            MODULE_SETTINGS modSettings;
+            modSettings.moduleParams.clear();
+            modSettings.moduleName = child->getValue();
+
+            ParseModuleSettings(child, &modSettings.moduleParams);
+
+            modulesSettings.push_back(modSettings);
+
+            child = child->getNextNode();
+            }
+        }
+
+    node = node->getNextNode();
+    }
+
+//sort(modulesSettings.begin(), modulesSettings.end());
+//modulesSettings.erase(unique(modulesSettings.begin(), modulesSettings.end()), modulesSettings.end());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::ParseDetailStatWritePeriod(const string & detailStatPeriodStr)
+{
+if (detailStatPeriodStr == "1")
+    {
+    detailStatWritePeriod = dsPeriod_1;
+    return 0;
+    }
+else if (detailStatPeriodStr == "1/2")
+    {
+    detailStatWritePeriod = dsPeriod_1_2;
+    return 0;
+    }
+else if (detailStatPeriodStr == "1/4")
+    {
+    detailStatWritePeriod = dsPeriod_1_4;
+    return 0;
+    }
+else if (detailStatPeriodStr == "1/6")
+    {
+    detailStatWritePeriod = dsPeriod_1_6;
+    return 0;
+    }
+
+return -1;
+}
+//-----------------------------------------------------------------------------
+int SETTINGS::Reload ()
+{
+return ReadSettings();
+}
+//-----------------------------------------------------------------------------
+const MODULE_SETTINGS & SETTINGS::GetStoreModuleSettings() const
+{
+return storeModuleSettings;
+}
+//-----------------------------------------------------------------------------
+const vector<MODULE_SETTINGS> & SETTINGS::GetModulesSettings() const
+{
+return modulesSettings;
+}
+//-----------------------------------------------------------------------------
+/*int SETTINGS::GetExecutersWaitTimeout() const
+{
+return executersWaitTimeout;
+}*/
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/settings.h b/projects/stargazer/settings.h
new file mode 100644 (file)
index 0000000..a9256cc
--- /dev/null
@@ -0,0 +1,142 @@
+ /*
+ $Revision: 1.27 $
+ $Date: 2010/08/19 13:42:30 $
+ $Author: faust $
+ */
+
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.27 $
+ $Date: 2010/08/19 13:42:30 $
+ */
+
+
+#ifndef settingsh_h
+#define settingsh_h 1
+
+#include <sys/types.h>
+#include <vector>
+#include <dotconfpp.h>
+
+#include "common.h"
+#include "base_settings.h"
+#include "stg_logger.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+enum DETAIL_STAT_PERIOD
+{
+dsPeriod_1,
+dsPeriod_1_2,
+dsPeriod_1_4,
+dsPeriod_1_6,
+};
+//-----------------------------------------------------------------------------
+class SETTINGS
+{
+public:
+    SETTINGS();
+    SETTINGS(const std::string &);
+    SETTINGS(const SETTINGS &);
+    virtual ~SETTINGS();
+    int Reload();
+    int ReadSettings();
+
+    string GetStrError() const;
+
+    int             GetExecMsgKey() const { return stgExecMsgKey; };
+    int             GetExecutersNum() const { return executersNum; };
+    //int             GetExecutersWaitTimeout() const;
+    const string &  GetDirName(int num) const { return dirName[num]; };
+    const string &  GetConfDir() const { return confDir; };
+    const string &  GetScriptDir() const { return scriptDir; };
+    const string &  GetRulesFileName() const { return rules; };
+    const string &  GetLogFileName() const { return logFile; };
+    const string &  GetPIDFileName() const { return pidFile; };
+    int             GetDetailStatWritePeriod() const 
+        { return detailStatWritePeriod; };
+    int             GetStatWritePeriod() const { return statWritePeriod * 60; };
+    int             GetDayFee() const { return dayFee; };
+    bool            GetFullFee() const { return fullFee; };
+    int             GetDayResetTraff() const { return dayResetTraff; };
+    bool            GetSpreadFee() const { return spreadFee; };
+    bool            GetFreeMbAllowInet() const { return freeMbAllowInet; };
+    bool            GetDayFeeIsLastDay() const { return dayFeeIsLastDay; };
+    bool            GetWriteFreeMbTraffCost() const
+        { return writeFreeMbTraffCost; };
+    bool            GetShowFeeInCash() const { return showFeeInCash; };
+    const string  & GetMonitorDir() const { return monitorDir; };
+    bool            GetMonitoring() const { return monitoring; };
+
+    const string &  GetModulesPath() const { return modulesPath; };
+    const MODULE_SETTINGS         & GetStoreModuleSettings() const;
+    const vector<MODULE_SETTINGS> & GetModulesSettings() const;
+
+private:
+
+    int ParseInt(const string & value, int * val);
+    int ParseIntInRange(const string & value, int min, int max, int * val);
+    int ParseYesNo(const string & value, bool * val);
+    int ParseDetailStatWritePeriod(const string & detailStatPeriodStr);
+
+    int ParseModuleSettings(const DOTCONFDocumentNode * dirNameNode, vector<PARAM_VALUE> * params);
+
+    static void ErrorCallback(void * data, const char * buf);
+
+    string      strError;
+    //////////settings
+    string      modulesPath;
+    string      dirName[DIR_NUM];
+    string      confDir;
+    string     scriptDir;
+    string      rules;
+    string      logFile;
+    string      pidFile;
+    string      monitorDir;
+    bool        monitoring;
+    int         detailStatWritePeriod;
+    int         statWritePeriod;
+    int         stgExecMsgKey;
+    int         executersNum;
+    //int         executersWaitTimeout;
+    bool        fullFee;
+    int         dayFee;        // ÄÅÎØ ÓÎÑÔÉÑ ÁÂÏÎÐÌÁÔÙ
+    int         dayResetTraff; // îÁÞÁÌÏ ÕÞÅÔÎÏÇÏ ÐÅÒÉÏÄÁ: ÄÅÎØ ÏÂÎÕÌÅÎÉÑ ÔÒÁÆÉËÁ É ÓÍÅÎÙ ÔÁÒÉÆÁ
+    bool        spreadFee;
+    bool        freeMbAllowInet;
+    bool        dayFeeIsLastDay; // áð ÓÎÉÍÁÅÔÓÑ × ËÏÎÃÅ ÍÅÓÑÃÁ (true) ÉÌÉ × ÎÁÞÁÌÅ (false)
+    bool        writeFreeMbTraffCost; // ðÉÓÁÔØ × ÄÅÔÁÌØÎÕÀ ÓÔÁÔÉÓÔÉËÕ ÓÔÏÉÍÏÓÔØ ÔÒÁÆÉËÁ, ÅÓÌÉ ÅÝÅ ÅÓÔØ ÐÒÅÄÏÐÌÁÞÅÎÎÙÊ ÔÒÁÆÉË
+    bool        showFeeInCash; // ðÏËÁÚÙ×ÁÔØ ÐÏÌØÚÏ×ÁÔÅÌÀ áð ÎÅ ÓÞÅÔÕ É ÐÏÚ×ÏÌÑÔØ ÅÅ ÉÓÐÏÌØÚÏ×ÁÔØ
+
+    vector<MODULE_SETTINGS> modulesSettings;
+    MODULE_SETTINGS         storeModuleSettings;
+
+    STG_LOGGER & logger;
+};
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/projects/stargazer/stargazer.vpj b/projects/stargazer/stargazer.vpj
new file mode 100644 (file)
index 0000000..e41648d
--- /dev/null
@@ -0,0 +1,319 @@
+<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
+<Project
+       Version="10.0"
+       VendorName="SlickEdit"
+       WorkingDir="."
+       VCSProject="CVS:">
+       <Config
+               Name="Debug"
+               Type="gnuc"
+               DebugCallbackName="gdb"
+               OutputFile="%bdstargazer">
+               <Menu>
+                       <Target
+                               Name="Compile"
+                               MenuCaption="&amp;Compile"
+                               OutputExts="*.o"
+                               Dialog="_gnuc_options_form Compile"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ -c %xup -DLINUX -g -o "%bd%n%oe" %i "%f"'/>
+                       </Target>
+                       <Target
+                               Name="Link"
+                               MenuCaption="&amp;Link"
+                               ShowOnMenu="Never"
+                               Dialog="_gnuc_options_form Link"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ %xup -g -o "%o" %f %libs'/>
+                       </Target>
+                       <Target
+                               Name="Build"
+                               MenuCaption="&amp;Build"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveWorkspaceFiles"
+                               Deletable="0">
+                               <Exec CmdLine="make OS=linux"/>
+                       </Target>
+                       <Target
+                               Name="Rebuild"
+                               MenuCaption="&amp;Rebuild"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="Debug"
+                               MenuCaption="&amp;Debug"
+                               Dialog="_gnuc_options_form Run/Debug"
+                               RunFromDir="%rw"
+                               BuildFirst="1"
+                               CaptureOutputWith="ProcessBuffer"
+                               Deletable="0">
+                               <Exec CmdLine='vsdebugio -prog "%o"'/>
+                       </Target>
+                       <Target
+                               Name="Execute"
+                               MenuCaption="E&amp;xecute"
+                               Dialog="_gnuc_options_form Run/Debug"
+                               RunFromDir="%rw"
+                               BuildFirst="1"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveWorkspaceFiles"
+                               Deletable="0">
+                               <Exec CmdLine='"%o"'/>
+                       </Target>
+                       <Target
+                               Name="dash"
+                               MenuCaption="-"
+                               RunFromDir="%rw">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="GNU C Options"
+                               MenuCaption="GNU C &amp;Options..."
+                               ShowOnMenu="HideIfNoCmdLine"
+                               Deletable="0">
+                               <Exec
+                                       CmdLine="gnucoptions"
+                                       Type="Slick-C"/>
+                       </Target>
+               </Menu>
+               <Includes>
+                       <Include Dir="../../include/"/>
+               </Includes>
+       </Config>
+       <Config
+               Name="Release"
+               Type="gnuc"
+               DebugCallbackName="gdb"
+               OutputFile="%bdstargazer">
+               <Menu>
+                       <Target
+                               Name="Compile"
+                               MenuCaption="&amp;Compile"
+                               OutputExts="*.o"
+                               Dialog="_gnuc_options_form Compile"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ -c %xup -DLINUX -o "%bd%n%oe" %i "%f"'/>
+                       </Target>
+                       <Target
+                               Name="Link"
+                               MenuCaption="&amp;Link"
+                               ShowOnMenu="Never"
+                               Dialog="_gnuc_options_form Link"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ %xup -o "%o" %f %libs'/>
+                       </Target>
+                       <Target
+                               Name="Build"
+                               MenuCaption="&amp;Build"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveWorkspaceFiles"
+                               Deletable="0">
+                               <Exec CmdLine="make OS=linux"/>
+                       </Target>
+                       <Target
+                               Name="Rebuild"
+                               MenuCaption="&amp;Rebuild"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="Debug"
+                               MenuCaption="&amp;Debug"
+                               Dialog="_gnuc_options_form Run/Debug"
+                               RunFromDir="%rw"
+                               BuildFirst="1"
+                               CaptureOutputWith="ProcessBuffer"
+                               Deletable="0">
+                               <Exec CmdLine='vsdebugio -prog "%o"'/>
+                       </Target>
+                       <Target
+                               Name="Execute"
+                               MenuCaption="E&amp;xecute"
+                               Dialog="_gnuc_options_form Run/Debug"
+                               RunFromDir="%rw"
+                               BuildFirst="1"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveWorkspaceFiles"
+                               Deletable="0">
+                               <Exec CmdLine='"%o"'/>
+                       </Target>
+                       <Target
+                               Name="dash"
+                               MenuCaption="-"
+                               RunFromDir="%rw">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="GNU C Options"
+                               MenuCaption="GNU C &amp;Options..."
+                               ShowOnMenu="HideIfNoCmdLine"
+                               Deletable="0">
+                               <Exec
+                                       CmdLine="gnucoptions"
+                                       Type="Slick-C"/>
+                       </Target>
+               </Menu>
+               <Includes>
+                       <Include Dir="../../include/"/>
+               </Includes>
+       </Config>
+       <Files>
+               <Folder
+                       Name="Source Files"
+                       Filters="*.c;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl">
+                       <Folder
+                               Name="Plugin Sources"
+                               Filters="">
+                               <Folder
+                                       Name="auth"
+                                       Filters="">
+                                       <F N="plugins/authorization/inetaccess/antiflood.cpp"/>
+                                       <F N="plugins/authorization/ao/ao.cpp"/>
+                                       <F N="plugins/authorization/inetaccess/inetaccess.cpp"/>
+                                       <F N="plugins/authorization/stress/stress.cpp"/>
+                               </Folder>
+                               <Folder
+                                       Name="store"
+                                       Filters="">
+                                       <F N="plugins/store/files/file_store.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_admins.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_corporations.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_messages.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_services.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_tariffs.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_users.cpp"/>
+                                       <F N="plugins/store/firebird/firebird_store_utils.cpp"/>
+                               </Folder>
+                               <Folder
+                                       Name="other"
+                                       Filters="">
+                                       <F N="plugins/other/ping/ping.cpp"/>
+                               </Folder>
+                               <Folder
+                                       Name="configuration"
+                                       Filters="">
+                                       <F N="plugins/configuration/sgconfig/configproto.cpp"/>
+                                       <F N="plugins/configuration/sgconfig/net_configurator.cpp"/>
+                                       <F N="plugins/configuration/sgconfig/parser_admin.cpp"/>
+                                       <F N="plugins/configuration/sgconfig/parser_tariff.cpp"/>
+                                       <F N="plugins/configuration/sgconfig/rsconf.cpp"/>
+                                       <F N="plugins/configuration/sgconfig/stgconfig.cpp"/>
+                                       <F N="plugins/configuration/sgconfig/parser.cpp"/>
+                               </Folder>
+                               <Folder
+                                       Name="capture"
+                                       Filters="">
+                                       <Folder
+                                               Name="debug_cap"
+                                               Filters="">
+                                               <F N="plugins/capture/cap_debug/debug_cap.cpp"/>
+                                       </Folder>
+                                       <Folder
+                                               Name="ipq_cap"
+                                               Filters="">
+                                               <F N="plugins/capture/ipq_linux/ipq_cap.cpp"/>
+                                               <F N="plugins/capture/ipq_linux/libipq.c"/>
+                                       </Folder>
+                                       <Folder
+                                               Name="divert_cap"
+                                               Filters="">
+                                               <F N="plugins/capture/divert_freebsd/divert_cap.cpp"/>
+                                               <F N="plugins/capture/divert_freebsd/divert_cap.h"/>
+                                       </Folder>
+                                       <F N="plugins/capture/ether_freebsd/ether_cap.cpp"/>
+                               </Folder>
+                       </Folder>
+                       <F N="admin.cpp"/>
+                       <F N="admins.cpp"/>
+                       <F N="curr_ip.cpp"/>
+                       <F N="main.cpp"/>
+                       <F N="plugin_runner.cpp"/>
+                       <F N="script_executer.cpp"/>
+                       <F N="settings.cpp"/>
+                       <F N="../../stglibs/stg_logger.lib/stg_logger.cpp"/>
+                       <F N="stg_timer.cpp"/>
+                       <F N="tariff.cpp"/>
+                       <F N="tariffs.cpp"/>
+                       <F N="traffcounter.cpp"/>
+                       <F N="user.cpp"/>
+                       <F N="user_property.cpp"/>
+                       <F N="users.cpp"/>
+               </Folder>
+               <Folder
+                       Name="Header Files"
+                       Filters="*.h;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
+                       <Folder
+                               Name="Plugin Headers"
+                               Filters="">
+                               <F N="plugins/authorization/ao/ao.h"/>
+                               <F N="plugins/configuration/sgconfig/configproto.h"/>
+                               <F N="plugins/capture/cap_debug/debug_cap.h"/>
+                               <F N="plugins/capture/ether_freebsd/ether_cap.h"/>
+                               <F N="plugins/store/files/file_store.h"/>
+                               <F N="plugins/authorization/inetaccess/inetaccess.h"/>
+                               <F N="plugins/other/ping/ping.h"/>
+                               <F N="plugins/authorization/inetaccess/recivecl.h"/>
+                               <F N="plugins/configuration/sgconfig/parser.h"/>
+                               <F N="plugins/authorization/inetaccess/packet.h"/>
+                       </Folder>
+                       <F N="admin.h"/>
+                       <F N="../../include/admin_conf.h"/>
+                       <F N="admins.h"/>
+                       <F N="../../include/notifer.h"/>
+                       <F N="../../stglibs/pinger.lib/pinger.h"/>
+                       <F N="plugin_runner.h"/>
+                       <F N="../../include/resetable.h"/>
+                       <F N="script_executer.h"/>
+                       <F N="settings.h"/>
+                       <F N="../../include/stg_common.h"/>
+                       <F N="../../include/stg_comp_stat.h"/>
+                       <F N="../../include/stg_const.h"/>
+                       <F N="stg_timer.h"/>
+                       <F N="tariff.h"/>
+                       <F N="../../include/tariff_conf.h"/>
+                       <F N="tariffs.h"/>
+                       <F N="traffcounter.h"/>
+                       <F N="user.h"/>
+                       <F N="../../include/user_conf.h"/>
+                       <F N="../../include/user_ips.h"/>
+                       <F N="user_property.h"/>
+                       <F N="../../include/user_stat.h"/>
+                       <F N="../../include/user_traff.h"/>
+                       <F N="users.h"/>
+               </Folder>
+               <Folder
+                       Name="Resource Files"
+                       Filters="*.ico;*.cur;*.dlg"/>
+               <Folder
+                       Name="Bitmaps"
+                       Filters="*.bmp;*.xpm;*.xbm"/>
+               <Folder
+                       Name="Other Files"
+                       Filters="">
+                       <F N="build"/>
+                       <F
+                               N="Makefile"
+                               Type="Makefile"/>
+               </Folder>
+       </Files>
+</Project>
diff --git a/projects/stargazer/stargazer.vpw b/projects/stargazer/stargazer.vpw
new file mode 100644 (file)
index 0000000..4f2962f
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE Workspace SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpw.dtd">
+<Workspace Version="10.0" VendorName="SlickEdit">
+       <Projects>
+               <Project File="../../stglibs/srvconf.lib/servconf.vpj" />
+               <Project File="stargazer.vpj" />
+       </Projects>
+</Workspace>
diff --git a/projects/stargazer/stargazer.vpwhistu b/projects/stargazer/stargazer.vpwhistu
new file mode 100644 (file)
index 0000000..f409a0d
--- /dev/null
@@ -0,0 +1,52 @@
+[Global]
+CurrentProject=stargazer.vpj
+[ProjectDates]
+../../stglibs/srvconf.lib/servconf.vpj=20080818103030000
+stargazer.vpj=20080818104412000
+[ActiveConfig]
+stargazer.vpj=,Debug
+../../stglibs/srvconf.lib/servconf.vpj=,Debug
+[TreeExpansion]
+stargazer.vpj 1 1 1 0 0 1
+[State]
+SCREEN: 1680 1050 0 0 1680 980 0 0 N 0 0 0 0 1353 829
+CWD: plugins/configuration/sgconfig/
+BUFFER: BN="plugins/configuration/sgconfig/parser.cpp"
+BI: MA=1 74 1  TABS=1 5  WWS=1 IWT=0 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=616 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1
+VIEW: LN=.0 CL=1 LE=0 CX=0 CY=0 WI=5 BI=32 HT=0 HN=0 HF=0 HC=4
+WINDOW: 200 200 913 559 0 0 M  WF=0 WT=2 "misc-nil,14,0,1"
+BUFFER: BN="plugins/configuration/sgconfig/parser.cpp"
+VIEW: LN=.8617 CL=34 LE=0 CX=33 CY=19 WI=157 BI=32 HT=0 HN=0 HF=0 HC=4
+FILEHIST: 9
+tariff.h
+../../stglibs/stg_logger.lib/stg_logger.h
+../../stglibs/stg_logger.lib/stg_logger.cpp
+tariff.cpp
+traffcounter.cpp
+../../include/user_conf.h
+../../../../tmp/OLYMP.CPP
+../../../../tmp/olymp.cpp
+plugins/configuration/sgconfig/parser.cpp
+DEBUG: 0 0 0 0 3 0
+printf
+strcpy
+std::*
+[TreeExpansion2]
++ ../../stglibs/srvconf.lib/servconf.vpj
+- stargazer.vpj
+  - Source Files
+    - Plugin Sources
+      - auth
+      + store
+      + other
+      + configuration
+      + capture
+        + debug_cap
+        + ipq_cap
+        + divert_cap
+  - Header Files
+    + Plugin Headers
+  + Resource Files
+  + Bitmaps
+  + Other Files
+scroll:23
diff --git a/projects/stargazer/startstg b/projects/stargazer/startstg
new file mode 100755 (executable)
index 0000000..7a0b3b8
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+LD_LIBRARY_PATH=../../lib ./stargazer /etc/stargazer
+#./stargazer /etc/stargazer.a
+
+if [ $? == 0 ]
+then 
+    echo "Start successfull"
+else
+    echo "Start failed"
+fi
+
+#./stargazer /etc/stargazer
\ No newline at end of file
diff --git a/projects/stargazer/stg_timer.cpp b/projects/stargazer/stg_timer.cpp
new file mode 100644 (file)
index 0000000..79844ba
--- /dev/null
@@ -0,0 +1,120 @@
+#include <unistd.h>
+#include <pthread.h>
+
+#include <cstring>
+
+#include "common.h"
+
+static int nonstop;
+static pthread_t thrStgTimer;
+static bool isTimerRunning = false;
+volatile time_t stgTime;
+
+const int TIME_SPEED = 1;
+/*
+ 1  - 1x  speed
+ 2  - 2x  speed
+ 5  - 5x  speed
+ 10 - 10x speed
+ */
+
+const int START_TIME = 0;
+/*
+ 0 - as is
+ 1 - start before new day (3 min before)   29.11.2005 23:57:00
+ 2 - start before new month (3 min before) 30.11.2005 23:57:00
+ */
+
+//-----------------------------------------------------------------------------
+void * StgTimer(void *)
+{
+#ifdef STG_TIMER_DEBUG
+struct tm lt;
+memset(&lt, 0, sizeof(lt));
+
+lt.tm_year = 2007 - 1900; // 2005
+lt.tm_mon  = 10 - 1;      // Nov
+lt.tm_hour = 23;          // 23 h
+lt.tm_min = 57;           // 50 min
+lt.tm_sec = 0;            // 00 sec
+
+switch (START_TIME)
+    {
+    case 0:
+        stgTime = time(NULL);
+        break;
+
+    case 1:
+        lt.tm_mday = 29;
+        stgTime = mktime(&lt);
+        break;
+
+    case 2:
+        lt.tm_mday = 30;
+        stgTime = mktime(&lt);
+        break;
+    }
+#endif
+
+nonstop = 1;
+isTimerRunning = true;
+while (nonstop)
+    {
+    #ifdef STG_TIMER_DEBUG
+    usleep(1000000 / TIME_SPEED);
+    stgTime++;
+    #else
+    stgTime = time(NULL);
+    usleep(500000);
+    #endif
+    }
+isTimerRunning = false;
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int RunStgTimer()
+{
+static int a = 0;
+isTimerRunning = false;
+
+if (a == 0)
+    if (pthread_create(&thrStgTimer, NULL, StgTimer, NULL))
+        {
+        isTimerRunning = false;
+        return -1;
+        }
+
+a = 1;
+return 0;
+}
+//-----------------------------------------------------------------------------
+void StopStgTimer()
+{
+nonstop = 0;
+pthread_join(thrStgTimer, NULL); // Cleanup thread resources
+printfd(__FILE__, "STG_TIMER stopped\n");
+}
+//-----------------------------------------------------------------------------
+bool IsStgTimerRunning()
+{
+return isTimerRunning;
+}
+//-----------------------------------------------------------------------------
+int stgUsleep(unsigned long t)
+{
+#ifdef STG_TIMER_DEBUG
+return usleep(t / TIME_SPEED);
+#else
+return usleep(t);
+#endif
+}
+//-----------------------------------------------------------------------------
+void WaitTimer()
+{
+    for (int i = 0; i < 5 && !isTimerRunning; i++)
+        stgUsleep(200000);
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/projects/stargazer/stg_timer.h b/projects/stargazer/stg_timer.h
new file mode 100644 (file)
index 0000000..c57008e
--- /dev/null
@@ -0,0 +1,21 @@
+ /*
+ $Revision: 1.9 $
+ $Date: 2010/11/03 10:37:52 $
+ $Author: faust $
+ */
+
+#ifndef STG_TIMER_H
+#define STG_TIMER_H
+
+#include <ctime>
+
+extern volatile const time_t stgTime;
+int RunStgTimer();
+void StopStgTimer();
+void WaitTimer();
+bool IsStgTimerRunning();
+int stgUsleep(unsigned long t);
+
+#endif //STG_TIMER_H
+
+
diff --git a/projects/stargazer/store_loader.cpp b/projects/stargazer/store_loader.cpp
new file mode 100644 (file)
index 0000000..56bd01a
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.6 $
+ $Date: 2010/03/04 12:24:19 $
+ $Author: faust $
+ */
+
+/*
+ *  An implementation of RAII store plugin loader
+ */
+
+#include <dlfcn.h>
+
+#include "store_loader.h"
+#include "common.h"
+
+STORE_LOADER::STORE_LOADER(const SETTINGS & settings)
+    : isLoaded(false),
+      handle(NULL),
+      plugin(NULL),
+      errorStr(),
+      storeSettings(settings.GetStoreModuleSettings()),
+      pluginFileName(settings.GetModulesPath() + "/mod_" + storeSettings.moduleName + ".so")
+{
+}
+
+STORE_LOADER::~STORE_LOADER()
+{
+Unload();
+}
+
+bool STORE_LOADER::Load()
+{
+printfd(__FILE__, "STORE_LOADER::Load()\n");
+if (isLoaded)
+    {
+    return false;
+    }
+
+if (pluginFileName.empty())
+    {
+    errorStr = "Empty store plugin filename";
+    printfd(__FILE__, "STORE_LOADER::Load - %s\n", errorStr.c_str());
+    return true;
+    }
+
+handle = dlopen(pluginFileName.c_str(), RTLD_NOW);
+
+if (!handle)
+    {
+    errorStr = "Error loading plugin '"
+        + pluginFileName + "': '" + dlerror() + "'";
+    printfd(__FILE__, "STORE_LOADER::Load - %s\n", errorStr.c_str());
+    return true;
+    }
+
+isLoaded = true;
+
+BASE_STORE * (*GetStore)();
+GetStore = (BASE_STORE * (*)())dlsym(handle, "GetStore");
+if (!GetStore)
+    {
+    errorStr = "GetStore not found.";
+    printfd(__FILE__, "STORE_LOADER::Load - %s\n", errorStr.c_str());
+    return true;
+    }
+
+plugin = GetStore();
+
+if (!plugin)
+    {
+    errorStr = "NULL store plugin";
+    printfd(__FILE__, "STORE_LOADER::Load - %s\n");
+    return true;
+    }
+
+plugin->SetSettings(storeSettings);
+if (plugin->ParseSettings())
+    {
+    errorStr = plugin->GetStrError();
+    printfd(__FILE__, "Failed to parse settings. Plugin reports: '%s'\n", errorStr.c_str());
+    return true;
+    }
+
+return false;
+}
+
+bool STORE_LOADER::Unload()
+{
+printfd(__FILE__, "STORE_LOADER::Unload()\n");
+if (!isLoaded)
+    {
+    return false;
+    }
+
+if (dlclose(handle))
+    {
+    errorStr = "Failed to unload plugin: '";
+    errorStr += dlerror();
+    errorStr += "'";
+    printfd(__FILE__, "STORE_LOADER::Unload - %s\n", errorStr.c_str());
+    return true;
+    }
+
+isLoaded = false;
+
+return false;
+}
diff --git a/projects/stargazer/store_loader.h b/projects/stargazer/store_loader.h
new file mode 100644 (file)
index 0000000..a506692
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.3 $
+ $Date: 2010/03/04 12:24:19 $
+ $Author: faust $
+ */
+
+/*
+ *  Header file for RAII store plugin loader
+ */
+
+#ifndef __STORE_LOADER_H__
+#define __STORE_LOADER_H__
+
+#include <string>
+
+#include "base_store.h"
+#include "base_settings.h"
+#include "settings.h"
+#include "noncopyable.h"
+
+class STORE_LOADER : private NONCOPYABLE
+{
+public:
+    STORE_LOADER(const SETTINGS & settings);
+    ~STORE_LOADER();
+
+    bool Load();
+    bool Unload();
+
+    BASE_STORE * GetStore() { return plugin; };
+
+    const std::string & GetStrError() const { return errorStr; };
+private:
+    bool isLoaded;
+    void * handle;
+    BASE_STORE * plugin;
+    std::string errorStr;
+    MODULE_SETTINGS storeSettings;
+    std::string pluginFileName;
+};
+
+#endif
diff --git a/projects/stargazer/tariff.cpp b/projects/stargazer/tariff.cpp
new file mode 100644 (file)
index 0000000..088cb53
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *    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: 07.11.2007
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.11 $
+ $Date: 2010/10/07 16:57:21 $
+ $Author: faust $
+ */
+
+#include <ctime>
+#include <algorithm> // std::max
+
+#include "tariff.h"
+#include "stg_timer.h"
+
+//-----------------------------------------------------------------------------
+TARIFF & TARIFF::operator=(const TARIFF_DATA & td)
+{
+tariffData = td;
+return *this;
+}
+//-----------------------------------------------------------------------------
+TARIFF & TARIFF::operator=(const TARIFF & t)
+{
+tariffData = t.tariffData;
+return *this;
+}
+//-----------------------------------------------------------------------------
+double TARIFF::GetPriceWithTraffType(uint64_t up,
+                                     uint64_t down,
+                                     int dir,
+                                     time_t t) const
+{
+return GetPriceWithoutFreeMb(dir, GetTraffByType(up, down) / (1024 * 1024), t);
+}
+//-----------------------------------------------------------------------------
+int64_t TARIFF::GetTraffByType(uint64_t up, uint64_t down) const
+{
+switch (tariffData.tariffConf.traffType)
+    {
+    case TRAFF_UP:
+        return up;
+
+    case TRAFF_DOWN:
+        return down;
+
+    case TRAFF_MAX:
+        return std::max(up, down);
+
+    default:  //TRAFF_UP_DOWN:
+        return up + down;
+    }
+}
+//-----------------------------------------------------------------------------
+int TARIFF::GetThreshold(int dir) const
+{
+    return tariffData.dirPrice[dir].threshold;
+}
+//-----------------------------------------------------------------------------
+void TARIFF::PrintTariff() const
+{
+//printfd(__FILE__, "Traiff name: %s\n", tariffConf.name.c_str());
+//printfd(__FILE__, "Price: %8.3f   %8.3f   \n", dirPrice[0].GetPrice(0, 0), dirPrice[0].GetPrice(1, 0));
+//printfd(__FILE__, "Price: %8.3f   %8.3f   Thr:%d\n", dirPrice[1].GetPrice(0), dirPrice[1].GetPrice(1), dirPrice[1].GetThreshold());
+//printfd(__FILE__, "Price: %8.3f   %8.3f   Thr:%d\n", dirPrice[2].GetPrice(0), dirPrice[2].GetPrice(1), dirPrice[2].GetThreshold());
+//printfd(__FILE__, "Price: %8.3f   %8.3f   Thr:%d\n", dirPrice[3].GetPrice(0), dirPrice[3].GetPrice(1), dirPrice[3].GetThreshold());
+//printfd(__FILE__, "Free: %8.3f\n", tariffConf.free);
+}
+//-----------------------------------------------------------------------------
+void TARIFF::GetDirPrice(int dir, DIRPRICE_DATA * dd) const
+{
+*dd = tariffData.dirPrice[dir];
+}
+//-----------------------------------------------------------------------------
+void TARIFF::GetTariffData(TARIFF_DATA * td) const
+{
+*td = tariffData;
+}
+//-----------------------------------------------------------------------------
+int TARIFF::Interval(int dir, time_t t) const
+{
+// Start of the day (and end of the night) in sec from 00:00:00
+int s1 = tariffData.dirPrice[dir].hDay * 3600 +
+         tariffData.dirPrice[dir].mDay * 60;
+// Start of the night (and end of the day) in sec from 00:00:00
+int s2 = tariffData.dirPrice[dir].hNight * 3600 +
+         tariffData.dirPrice[dir].mNight * 60;
+
+struct tm * lt;
+
+lt = localtime(&t);
+
+// Position of time t in sec from 00:00:00
+// Ignoring seconds due to minute precision
+int lts = lt->tm_hour * 3600 + lt->tm_min * 60;
+
+if (s1 < s2)
+    {
+    // Normal situation (00:00:00 is a night)
+    if (lts > s1 && lts < s2)
+        return TARIFF_DAY;
+    else
+        return TARIFF_NIGHT;
+    }
+else
+    {
+    // Not so common but possible situation (00:00:00 is a day)
+    if (lts < s1 && lts > s2)
+        return TARIFF_NIGHT;
+    else
+        return TARIFF_DAY;
+    }
+}
+//-----------------------------------------------------------------------------
+double TARIFF::GetPriceWithoutFreeMb(int dir, int mb, time_t t) const
+{
+int interval = Interval(dir, t);
+
+/*
+ * 0011 - NB
+ * *01* - NA
+ * 0**1 - DB
+ * **** - DA
+ */
+
+bool nd = tariffData.dirPrice[dir].noDiscount;
+bool sp = tariffData.dirPrice[dir].singlePrice;
+bool th = (interval == TARIFF_NIGHT);
+bool tr = (mb > tariffData.dirPrice[dir].threshold);
+
+if (!nd && !sp && th && tr)
+    return tariffData.dirPrice[dir].priceNightB;
+else if (!nd && tr)
+    return tariffData.dirPrice[dir].priceDayB;
+else if (!sp && th)
+    return tariffData.dirPrice[dir].priceNightA;
+else
+    return tariffData.dirPrice[dir].priceDayA;
+
+/*if (tariffData.dirPrice[dir].noDiscount && tariffData.dirPrice[dir].singlePrice)
+    {
+    return tariffData.dirPrice[dir].priceDayA;
+    }
+else
+    {
+    if (tariffData.dirPrice[dir].noDiscount)
+        {
+        // Without threshold
+        if (interval == TARIFF_DAY)
+            return tariffData.dirPrice[dir].priceDayA;
+        else
+            return tariffData.dirPrice[dir].priceNightA;
+        }
+
+    if (tariffData.dirPrice[dir].singlePrice)
+        {
+        // Without day/night
+        if (mb < tariffData.dirPrice[dir].threshold)
+            return tariffData.dirPrice[dir].priceDayA;
+        else
+            return tariffData.dirPrice[dir].priceDayB;
+        }
+
+    if (mb < tariffData.dirPrice[dir].threshold)
+        {
+        if (interval == TARIFF_DAY)
+            return tariffData.dirPrice[dir].priceDayA;
+        else
+            return tariffData.dirPrice[dir].priceNightA;
+        }
+    else
+        {
+        if (interval == TARIFF_DAY)
+            return tariffData.dirPrice[dir].priceDayB;
+        else
+            return tariffData.dirPrice[dir].priceNightB;
+        }
+    }*/
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/tariff.h b/projects/stargazer/tariff.h
new file mode 100644 (file)
index 0000000..830863e
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *    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: 07.11.2007
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.9 $
+ $Date: 2010/10/07 17:53:39 $
+ $Author: faust $
+ */
+
+#ifndef TARIFF_H
+#define TARIFF_H
+
+#include <string>
+#include <list>
+
+#include "os_int.h"
+#include "tariff_conf.h"
+
+#define TARIFF_DAY     0
+#define TARIFF_NIGHT   1
+
+class TARIFF
+{
+public:
+    TARIFF()
+        : tariffData()
+    {};
+    TARIFF(const std::string & name)
+        : tariffData(name)
+    {};
+    TARIFF(const TARIFF_DATA & td)
+        : tariffData(td)
+    {};
+    TARIFF(const TARIFF & t)
+        : tariffData(t.tariffData)
+    {};
+    ~TARIFF() {};
+
+    double  GetPriceWithTraffType(uint64_t up,
+                                  uint64_t down,
+                                  int dir,
+                                  time_t t) const;
+    double  GetFreeMb() const { return tariffData.tariffConf.free; };
+    void    GetDirPrice(int dir, DIRPRICE_DATA * dd) const;
+    double  GetPassiveCost() const { return tariffData.tariffConf.passiveCost; };
+    double  GetFee() const { return tariffData.tariffConf.fee; };
+    double  GetFree() const { return tariffData.tariffConf.free; };
+
+    void    PrintTariff() const;
+
+    const   std::string & GetName() const { return tariffData.tariffConf.name; };
+    void    SetName(const std::string & name) { tariffData.tariffConf.name = name; };
+
+    int     GetTraffType() const { return tariffData.tariffConf.traffType; };
+    int64_t GetTraffByType(uint64_t up, uint64_t down) const;
+    int     GetThreshold(int dir) const;
+    void    GetTariffData(TARIFF_DATA * td) const;
+
+    TARIFF & operator=(const TARIFF_DATA & td);
+    TARIFF & operator=(const TARIFF & t);
+    bool     operator==(const TARIFF & rhs) const { return GetName() == rhs.GetName(); };
+    bool     operator!=(const TARIFF & rhs) const { return GetName() != rhs.GetName(); };
+
+private:
+    TARIFF_DATA     tariffData;
+
+    double  GetPriceWithoutFreeMb(int dir, int mb, time_t t) const;
+    int     Interval(int dir, time_t t) const;
+};
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/projects/stargazer/tariffs.cpp b/projects/stargazer/tariffs.cpp
new file mode 100644 (file)
index 0000000..1f8a423
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *    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: 07.11.2007
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.9 $
+ $Date: 2010/10/07 18:43:21 $
+ $Author: faust $
+ */
+
+#include <cassert>
+#include <algorithm>
+#include <vector>
+
+#include "tariffs.h"
+#include "stg_locker.h"
+#include "stg_logger.h"
+#include "base_store.h"
+#include "admin.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+TARIFFS::TARIFFS(BASE_STORE * st)
+    : tariffs(),
+      store(st),
+      WriteServLog(GetStgLogger()),
+      strError(),
+      noTariff(NO_TARIFF_NAME)
+{
+pthread_mutex_init(&mutex, NULL);
+ReadTariffs();
+}
+//-----------------------------------------------------------------------------
+TARIFFS::~TARIFFS()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int TARIFFS::ReadTariffs()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+vector<string> tariffsList;
+if (store->GetTariffsList(&tariffsList))
+    {
+    WriteServLog("Cannot get tariffs list.");
+    WriteServLog("%s", store->GetStrError().c_str());
+    }
+
+int tariffsNum = tariffsList.size();
+
+for (int i = 0; i < tariffsNum; i++)
+    {
+    TARIFF_DATA td;
+    if (store->RestoreTariff(&td, tariffsList[i]))
+        {
+        WriteServLog("Cannot read tariff %s.", tariffsList[i].c_str());
+        WriteServLog("%s", store->GetStrError().c_str());
+        return -1;
+        }
+    tariffs.push_back(TARIFF(td));
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TARIFFS::GetTariffsNum() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return tariffs.size();
+}
+//-----------------------------------------------------------------------------
+const TARIFF * TARIFFS::FindByName(const string & name) const
+{
+if (name == NO_TARIFF_NAME)
+    return &noTariff;
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+list<TARIFF>::const_iterator ti;
+ti = find(tariffs.begin(), tariffs.end(), TARIFF(name));
+
+if (ti != tariffs.end())
+    return &(*ti);
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+int TARIFFS::Chg(const TARIFF_DATA & td, const ADMIN & admin)
+{
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->tariffChg)
+    {
+    string s = admin.GetLogStr() + " Change tariff \'"
+               + td.tariffConf.name + "\'. Access denied.";
+    strError = "Access denied.";
+    WriteServLog(s.c_str());
+    return -1;
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+list<TARIFF>::iterator ti;
+ti = find(tariffs.begin(), tariffs.end(), TARIFF(td.tariffConf.name));
+
+if (ti == tariffs.end())
+    {
+    strError = "Tariff \'" + td.tariffConf.name + "\' cannot be changed. Tariff does not exist.";
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+    return -1;
+    }
+
+*ti = td;
+
+if (store->SaveTariff(td, td.tariffConf.name))
+    {
+    string error = "Tariff " + td.tariffConf.name + " writing error. " + store->GetStrError();
+    WriteServLog(error.c_str());
+    return -1;
+    }
+
+WriteServLog("%s Tariff \'%s\' changed.",
+             admin.GetLogStr().c_str(), td.tariffConf.name.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TARIFFS::Del(const string & name, const ADMIN & admin)
+{
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->tariffChg)
+    {
+    string s = admin.GetLogStr() + " Delete tariff \'"
+               + name + "\'. Access denied.";
+    strError = "Access denied.";
+    WriteServLog(s.c_str());
+    return -1;
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+list<TARIFF>::iterator ti;
+ti = find(tariffs.begin(), tariffs.end(), TARIFF(name));
+
+if (ti == tariffs.end())
+    {
+    strError = "Tariff \'" + name + "\' cannot be deleted. Tariff does not exist.";
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+    return -1;
+    }
+
+if (store->DelTariff(name))
+    {
+    WriteServLog("Cannot delete tariff %s.", name.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    return -1;
+    }
+
+tariffs.erase(ti);
+
+WriteServLog("%s Tariff \'%s\' deleted.",
+             admin.GetLogStr().c_str(),
+             name.c_str());
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TARIFFS::Add(const string & name, const ADMIN & admin)
+{
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->tariffChg)
+    {
+    string s = admin.GetLogStr() + " Add tariff \'"
+               + name + "\'. Access denied.";
+    strError = "Access denied.";
+    WriteServLog(s.c_str());
+    return -1;
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+list<TARIFF>::iterator ti;
+ti = find(tariffs.begin(), tariffs.end(), TARIFF(name));
+
+if (ti != tariffs.end())
+    {
+    strError = "Tariff \'" + name + "\' cannot be added. Tariff alredy exist.";
+    WriteServLog("%s %s", admin.GetLogStr().c_str(), strError.c_str());
+    return -1;
+    }
+
+tariffs.push_back(TARIFF(name));
+
+if (store->AddTariff(name) < 0)
+    {
+    strError = "Tariff " + name + " adding error. " + store->GetStrError();
+    WriteServLog(strError.c_str());
+    return -1;
+    }
+
+WriteServLog("%s Tariff \'%s\' added.",
+                 admin.GetLogStr().c_str(), name.c_str());
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void TARIFFS::GetTariffsData(std::list<TARIFF_DATA> * tdl)
+{
+assert(tdl != NULL && "Tariffs data list is not null");
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+std::list<TARIFF>::const_iterator it = tariffs.begin();
+TARIFF_DATA td;
+for (; it != tariffs.end(); ++it)
+    {
+    it->GetTariffData(&td);
+    tdl->push_back(td);
+    }
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/tariffs.h b/projects/stargazer/tariffs.h
new file mode 100644 (file)
index 0000000..f2d76fb
--- /dev/null
@@ -0,0 +1,79 @@
+ /*
+ $Revision: 1.7 $
+ $Date: 2010/10/07 18:43:21 $
+ */
+
+/*
+ *    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: 07.11.2007
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.7 $
+ $Date: 2010/10/07 18:43:21 $
+ $Author: faust $
+ */
+
+#ifndef TARIFFS_H
+#define TARIFFS_H
+
+#include <string>
+#include <list>
+
+#include "tariff.h"
+#include "tariff_conf.h"
+
+#define TARIFF_DAY     0
+#define TARIFF_NIGHT   1
+
+class BASE_STORE;
+class STG_LOGGER;
+class ADMIN;
+
+//-----------------------------------------------------------------------------
+class TARIFFS
+{
+public:
+    TARIFFS(BASE_STORE * store);
+    ~TARIFFS();
+    int     ReadTariffs ();
+    const TARIFF * FindByName(const std::string & name) const;
+    const TARIFF * GetNoTariff() const { return &noTariff; };
+    int     GetTariffsNum() const;
+    int     Del(const std::string & name, const ADMIN & admin);
+    int     Add(const std::string & name, const ADMIN & admin);
+    int     Chg(const TARIFF_DATA & td, const ADMIN & admin);
+
+    void    GetTariffsData(std::list<TARIFF_DATA> * tdl);
+
+    const std::string & GetStrError() const { return strError; };
+private:
+    std::list<TARIFF>   tariffs;
+    BASE_STORE *        store;
+    STG_LOGGER &        WriteServLog;
+    mutable pthread_mutex_t mutex;
+    std::string         strError;
+    TARIFF              noTariff;
+};
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/projects/stargazer/traffcounter.cpp b/projects/stargazer/traffcounter.cpp
new file mode 100644 (file)
index 0000000..5401416
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.58 $
+ $Date: 2010/11/03 11:28:07 $
+ $Author: faust $
+ */
+
+#include <csignal>
+#include <cassert>
+
+#include "traffcounter.h"
+#include "common.h"
+#include "stg_locker.h"
+
+#define FLUSH_TIME  (10)
+#define REMOVE_TIME  (31)
+
+const char protoName[PROTOMAX][8] =
+{"TCP", "UDP", "ICMP", "TCP_UDP", "ALL"};
+
+enum protoNum
+    {
+    tcp = 0, udp, icmp, tcp_udp, all
+    };
+
+//-----------------------------------------------------------------------------
+TRAFFCOUNTER::TRAFFCOUNTER(USERS * u, const TARIFFS *, const string & fn)
+    : WriteServLog(GetStgLogger()),
+      rulesFileName(fn),
+      monitoring(false),
+      users(u),
+      running(false),
+      stopped(true),
+      addUserNotifier(*this),
+      delUserNotifier(*this)
+{
+for (int i = 0; i < DIR_NUM; i++)
+    strprintf(&dirName[i], "DIR%d", i);
+
+dirName[DIR_NUM] = "NULL";
+
+users->AddNotifierUserAdd(&addUserNotifier);
+users->AddNotifierUserDel(&delUserNotifier);
+
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+TRAFFCOUNTER::~TRAFFCOUNTER()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int TRAFFCOUNTER::Start()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (!stopped)
+    return 0;
+
+if (ReadRules())
+    {
+    WriteServLog("TRAFFCOUNTER: Cannot read rules.");
+    return -1;
+    }
+
+printfd(__FILE__, "TRAFFCOUNTER::Start()\n");
+int h = users->OpenSearch();
+user_iter u;
+if (!h)
+    {
+    WriteServLog("TRAFFCOUNTER: Cannot get users.");
+    return -1;
+    }
+
+while (users->SearchNext(h, &u) == 0)
+    {
+    SetUserNotifiers(u);
+    }
+users->CloseSearch(h);
+
+running = true;
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    WriteServLog("TRAFFCOUNTER: Error: Cannot start thread!");
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int TRAFFCOUNTER::Stop()
+{
+if (stopped)
+    return 0;
+
+running = false;
+
+int h = users->OpenSearch();
+if (!h)
+    {
+    WriteServLog("TRAFFCOUNTER: Fatal error: Cannot get users.");
+    return -1;
+    }
+
+user_iter u;
+while (users->SearchNext(h, &u) == 0)
+    {
+    UnSetUserNotifiers(u);
+    }
+users->CloseSearch(h);
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && !stopped; i++)
+    {
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now kill it
+if (!stopped)
+    {
+    printfd(__FILE__, "kill TRAFFCOUNTER thread.\n");
+    if (pthread_kill(thread, SIGINT))
+        {
+        return -1;
+        }
+    printfd(__FILE__, "TRAFFCOUNTER killed\n");
+    }
+printfd(__FILE__, "TRAFFCOUNTER::Stop()\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * TRAFFCOUNTER::Run(void * data)
+{
+TRAFFCOUNTER * tc = static_cast<TRAFFCOUNTER *>(data);
+tc->stopped = false;
+int c = 0;
+
+time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+
+while (tc->running)
+    {
+    usleep(500000);
+    if (!tc->running)
+        {
+        tc->FlushAndRemove();
+        break;
+        }
+
+    if (tc->monitoring && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
+        {
+        string monFile(tc->monitorDir + "/traffcounter_r");
+        printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", tc->monitoring, monFile.c_str());
+        touchTime = stgTime;
+        TouchFile(monFile.c_str());
+        }
+
+    if (++c % FLUSH_TIME == 0)
+        tc->FlushAndRemove();
+    }
+
+tc->stopped = true;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::Process(const RAW_PACKET & rawPacket)
+{
+if (!running)
+    return;
+
+static time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+
+if (monitoring && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
+    {
+    static string monFile = monitorDir + "/traffcounter_p";
+    printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", monitoring, monFile.c_str());
+    touchTime = stgTime;
+    TouchFile(monFile.c_str());
+    }
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+//printfd(__FILE__, "TRAFFCOUNTER::Process()\n");
+//TODO replace find with lower_bound.
+
+// Searching a new packet in a tree.
+pp_iter pi = packets.find(rawPacket);
+
+// Packet found - update length and time
+if (pi != packets.end())
+    {
+    pi->second.lenU += rawPacket.GetLen();
+    pi->second.lenD += rawPacket.GetLen();
+    pi->second.updateTime = stgTime;
+    /*printfd(__FILE__, "=============================\n");
+    printfd(__FILE__, "Packet found!\n");
+    printfd(__FILE__, "Version=%d\n", rawPacket.GetIPVersion());
+    printfd(__FILE__, "HeaderLen=%d\n", rawPacket.GetHeaderLen());
+    printfd(__FILE__, "PacketLen=%d\n", rawPacket.GetLen());
+    printfd(__FILE__, "SIP=%s\n", inet_ntostring(rawPacket.GetSrcIP()).c_str());
+    printfd(__FILE__, "DIP=%s\n", inet_ntostring(rawPacket.GetDstIP()).c_str());
+    printfd(__FILE__, "src port=%d\n", rawPacket.GetSrcPort());
+    printfd(__FILE__, "pst port=%d\n", rawPacket.GetDstPort());
+    printfd(__FILE__, "len=%d\n", rawPacket.GetLen());
+    printfd(__FILE__, "proto=%d\n", rawPacket.GetProto());
+    printfd(__FILE__, "PacketDirU=%d\n", pi->second.dirU);
+    printfd(__FILE__, "PacketDirD=%d\n", pi->second.dirD);
+    printfd(__FILE__, "=============================\n");*/
+    return;
+    }
+
+PACKET_EXTRA_DATA ed;
+
+// Packet not found - add new packet
+
+ed.updateTime = stgTime;
+ed.flushTime = stgTime;
+
+/*
+ userU is that whose user_ip == packet_ip_src
+ userD is that whose user_ip == packet_ip_dst
+ */
+
+uint32_t ipU = rawPacket.GetSrcIP();
+uint32_t ipD = rawPacket.GetDstIP();
+
+// Searching users with such IP
+if (users->FindByIPIdx(ipU, &ed.userU) == 0)
+    {
+    ed.userUPresent = true;
+    }
+
+if (users->FindByIPIdx(ipD, &ed.userD) == 0)
+    {
+    ed.userDPresent = true;
+    }
+
+if (ed.userUPresent ||
+    ed.userDPresent)
+    {
+    DeterminateDir(rawPacket, &ed.dirU, &ed.dirD);
+
+    ed.lenD = ed.lenU = rawPacket.GetLen();
+
+    //TODO use result of lower_bound to inserting new record
+
+    // Adding packet to a tree.
+    pair<pp_iter, bool> insertResult = packets.insert(pair<RAW_PACKET,
+                                                      PACKET_EXTRA_DATA>(rawPacket, ed));
+    pp_iter newPacket = insertResult.first;
+
+    // Adding packet reference to an IP index.
+    ip2packets.insert(pair<uint32_t, pp_iter>(ipU, newPacket));
+    ip2packets.insert(pair<uint32_t, pp_iter>(ipD, newPacket));
+    }
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::FlushAndRemove()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+int oldPacketsSize = packets.size();
+int oldIp2packetsSize = ip2packets.size();
+
+pp_iter pi;
+pi = packets.begin();
+std::map<RAW_PACKET, PACKET_EXTRA_DATA> newPackets;
+std::multimap<uint32_t, pp_iter> newIP2Packets;
+while (pi != packets.end())
+    {
+    //Flushing
+    if (stgTime - pi->second.flushTime > FLUSH_TIME)
+        {
+        if (pi->second.userUPresent)
+            {
+            //printfd(__FILE__, "+++ Flushing U user %s (%s:%d) of length %d\n", pi->second.userU->GetLogin().c_str(), inet_ntostring(pi->first.GetSrcIP()).c_str(), pi->first.GetSrcPort(), pi->second.lenU);
+
+            // Add stat
+            if (pi->second.dirU < DIR_NUM)
+                {
+                #ifdef TRAFF_STAT_WITH_PORTS
+                pi->second.userU->AddTraffStatU(pi->second.dirU,
+                                                pi->first.GetDstIP(),
+                                                pi->first.GetDstPort(),
+                                                pi->second.lenU);
+                #else
+                pi->second.userU->AddTraffStatU(pi->second.dirU,
+                                                pi->first.GetDstIP(),
+                                                pi->second.lenU);
+                #endif
+                }
+
+            pi->second.lenU = 0;
+            pi->second.flushTime = stgTime;
+            }
+
+        if (pi->second.userDPresent)
+            {
+            //printfd(__FILE__, "+++ Flushing D user %s (%s:%d) of length %d\n", pi->second.userD->GetLogin().c_str(), inet_ntostring(pi->first.GetDstIP()).c_str(), pi->first.GetDstPort(), pi->second.lenD);
+
+            // Add stat
+            if (pi->second.dirD < DIR_NUM)
+                {
+                #ifdef TRAFF_STAT_WITH_PORTS
+                pi->second.userD->AddTraffStatD(pi->second.dirD,
+                                                pi->first.GetSrcIP(),
+                                                pi->first.GetSrcPort(),
+                                                pi->second.lenD);
+                #else
+                pi->second.userD->AddTraffStatD(pi->second.dirD,
+                                                pi->first.GetSrcIP(),
+                                                pi->second.lenD);
+                #endif
+                }
+
+            pi->second.lenD = 0;
+            pi->second.flushTime = stgTime;
+            }
+        }
+
+    /*//Removing
+    if (stgTime - pi->second.updateTime > REMOVE_TIME)
+        {
+        // Remove packet and references from ip2packets index
+        //printfd(__FILE__, "+++ Removing +++\n");
+        pair<ip2p_iter, ip2p_iter> be(
+                ip2packets.equal_range(pi->first.GetSrcIP()));
+        while (be.first != be.second)
+            {
+            // Have a reference to a packet?
+            if (be.first->second == pi)
+                {
+                ip2packets.erase(be.first++);
+                //printfd(__FILE__, "Remove U from ip2packets %s\n", inet_ntostring(pi->first.GetSrcIP()).c_str());
+                }
+            else
+                {
+                ++be.first;
+                }
+            }
+
+        //printfd(__FILE__, "-------------------\n");
+        be = ip2packets.equal_range(pi->first.GetDstIP());
+        while (be.first != be.second)
+            {
+            // Have a reference to a packet?
+            if (be.first->second == pi)
+                {
+                ip2packets.erase(be.first++);
+                //printfd(__FILE__, "Remove D from ip2packets %s\n", inet_ntostring(pi->first.GetDstIP()).c_str());
+                }
+            else
+                {
+                ++be.first;
+                }
+            }
+        //printfd(__FILE__, "Remove packet\n");
+        packets.erase(pi++);
+        }
+    else
+        {
+        ++pi;
+        }*/
+    if (stgTime - pi->second.updateTime < REMOVE_TIME)
+        {
+        pair<pp_iter, bool> res = newPackets.insert(*pi);
+        if (res.second)
+            {
+            newIP2Packets.insert(make_pair(pi->first.GetSrcIP(), res.first));
+            newIP2Packets.insert(make_pair(pi->first.GetDstIP(), res.first));
+            }
+        }
+    ++pi;
+    }
+swap(packets, newPackets);
+swap(ip2packets, newIP2Packets);
+printfd(__FILE__, "FlushAndRemove() packets: %d(rem %d) ip2packets: %d(rem %d)\n",
+        packets.size(),
+        oldPacketsSize - packets.size(),
+        ip2packets.size(),
+        oldIp2packetsSize - ip2packets.size());
+
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::AddUser(user_iter user)
+{
+printfd(__FILE__, "AddUser: %s\n", user->GetLogin().c_str());
+uint32_t uip = user->GetCurrIP();
+pair<ip2p_iter, ip2p_iter> pi;
+
+STG_LOCKER(&mutex, __FILE__, __LINE__);
+// Find all packets with IP belongs to this user
+pi = ip2packets.equal_range(uip);
+
+while (pi.first != pi.second)
+    {
+    if (pi.first->second->first.GetSrcIP() == uip)
+        {
+        assert((!pi.first->second->second.userUPresent || 
+                 pi.first->second->second.userU == user) &&
+               "U user present but it's not current user");
+
+        pi.first->second->second.lenU = 0;
+        pi.first->second->second.userU = user;
+        pi.first->second->second.userUPresent = true;
+        }
+
+    if (pi.first->second->first.GetDstIP() == uip)
+        {
+        assert((!pi.first->second->second.userDPresent || 
+                 pi.first->second->second.userD == user) &&
+               "D user present but it's not current user");
+
+        pi.first->second->second.lenD = 0;
+        pi.first->second->second.userD = user;
+        pi.first->second->second.userDPresent = true;
+        }
+
+    ++pi.first;
+    }
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::DelUser(uint32_t uip)
+{
+printfd(__FILE__, "DelUser: %s \n", inet_ntostring(uip).c_str());
+pair<ip2p_iter, ip2p_iter> pi;
+
+STG_LOCKER(&mutex, __FILE__, __LINE__);
+pi = ip2packets.equal_range(uip);
+
+while (pi.first != pi.second)
+    {
+    if (pi.first->second->first.GetSrcIP() == uip)
+        {
+        if (pi.first->second->second.dirU < DIR_NUM && pi.first->second->second.userUPresent)
+            {
+            #ifdef TRAFF_STAT_WITH_PORTS
+            pi.first->second->second.userU->AddTraffStatU(pi.first->second->second.dirU,
+                                                          pi.first->second->first.GetDstIP(),
+                                                          pi.first->second->first.GetDstPort(),
+                                                          pi.first->second->second.lenU);
+            #else
+            pi.first->second->second.userU->AddTraffStatU(pi.first->second->second.dirU,
+                                                          pi.first->second->first.GetDstIP(),
+                                                          pi.first->second->second.lenU);
+            #endif
+            }
+        pi.first->second->second.userUPresent = false;
+        }
+
+    if (pi.first->second->first.GetDstIP() == uip)
+        {
+        if (pi.first->second->second.dirD < DIR_NUM && pi.first->second->second.userDPresent)
+            {
+            #ifdef TRAFF_STAT_WITH_PORTS
+            pi.first->second->second.userD->AddTraffStatD(pi.first->second->second.dirD,
+                                                          pi.first->second->first.GetSrcIP(),
+                                                          pi.first->second->first.GetSrcPort(),
+                                                          pi.first->second->second.lenD);
+            #else
+            pi.first->second->second.userD->AddTraffStatD(pi.first->second->second.dirD,
+                                                          pi.first->second->first.GetSrcIP(),
+                                                          pi.first->second->second.lenD);
+            #endif
+            }
+
+        pi.first->second->second.userDPresent = false;
+        }
+
+    ++pi.first;
+    }
+
+ip2packets.erase(pi.first, pi.second);
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::SetUserNotifiers(user_iter user)
+{
+// Adding user. Adding notifiers to user.
+TRF_IP_BEFORE ipBNotifier(*this, user);
+ipBeforeNotifiers.push_front(ipBNotifier);
+user->AddCurrIPBeforeNotifier(&(*ipBeforeNotifiers.begin()));
+
+TRF_IP_AFTER ipANotifier(*this, user);
+ipAfterNotifiers.push_front(ipANotifier);
+user->AddCurrIPAfterNotifier(&(*ipAfterNotifiers.begin()));
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::UnSetUserNotifiers(user_iter user)
+{
+// Removing user. Removing notifiers from user.
+list<TRF_IP_BEFORE>::iterator bi;
+list<TRF_IP_AFTER>::iterator ai;
+
+bi = ipBeforeNotifiers.begin();
+while (bi != ipBeforeNotifiers.end())
+    {
+    if (user->GetLogin() == bi->GetUser()->GetLogin())
+        {
+        user->DelCurrIPBeforeNotifier(&(*bi));
+        ipBeforeNotifiers.erase(bi);
+        break;
+        }
+    ++bi;
+    }
+
+ai = ipAfterNotifiers.begin();
+while (ai != ipAfterNotifiers.end())
+    {
+    if (user->GetLogin() == ai->GetUser()->GetLogin())
+        {
+        user->DelCurrIPAfterNotifier(&(*ai));
+        ipAfterNotifiers.erase(ai);
+        break;
+        }
+    ++ai;
+    }
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::DeterminateDir(const RAW_PACKET & packet,
+                                 int * dirU, // Direction for incoming packet
+                                 int * dirD) const // Direction for outgoing packet
+{
+bool addrMatchU;
+bool portMatchU;
+bool addrMatchD;
+bool portMatchD;
+bool foundU = false; // Was rule for U found ?
+bool foundD = false; // Was rule for D found ?
+//printfd(__FILE__, "foundU=%d, foundD=%d\n", foundU, foundD);
+
+enum { ICMP_RPOTO = 1, TCP_PROTO = 6, UDP_PROTO = 17 };
+
+list<RULE>::const_iterator ln;
+ln = rules.begin();
+
+while (ln != rules.end())
+    {
+    if (!foundU)
+        {
+        addrMatchU = false;
+        portMatchU = false;
+
+        switch (ln->proto)
+            {
+            case all:
+                portMatchU = true;
+                break;
+
+            case icmp:
+                portMatchU = (packet.GetProto() == ICMP_RPOTO);
+                break;
+
+            case tcp_udp:
+                if (packet.GetProto() == TCP_PROTO || packet.GetProto() == UDP_PROTO)
+                    portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
+                break;
+
+            case tcp:
+                if (packet.GetProto() == TCP_PROTO)
+                    portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
+                break;
+
+            case udp:
+                if (packet.GetProto() == UDP_PROTO)
+                    portMatchU = (packet.GetDstPort() >= ln->port1) && (packet.GetDstPort() <= ln->port2);
+                break;
+
+            default:
+                printfd(__FILE__, "Error! Incorrect rule!\n");
+                break;
+            }
+
+        addrMatchU = (packet.GetDstIP() & ln->mask) == ln->ip;
+
+        if (!foundU && addrMatchU && portMatchU)
+            {
+            foundU = true;
+            *dirU = ln->dir;
+            //printfd(__FILE__, "Up rule ok! %d\n", ln->dir);
+            //PrintRule(ln->rule);
+            }
+
+        } //if (!foundU)
+
+    if (!foundD)
+        {
+        addrMatchD = false;
+        portMatchD = false;
+
+        switch (ln->proto)
+            {
+            case all:
+                portMatchD = true;
+                break;
+
+            case icmp:
+                portMatchD = (packet.GetProto() == ICMP_RPOTO);
+                break;
+
+            case tcp_udp:
+                if (packet.GetProto() == TCP_PROTO || packet.GetProto() == UDP_PROTO)
+                    portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
+                break;
+
+            case tcp:
+                if (packet.GetProto() == TCP_PROTO)
+                    portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
+                break;
+
+            case udp:
+                if (packet.GetProto() == UDP_PROTO)
+                    portMatchD = (packet.GetSrcPort() >= ln->port1) && (packet.GetSrcPort() <= ln->port2);
+                break;
+
+            default:
+                printfd(__FILE__, "Error! Incorrect rule!\n");
+                break;
+            }
+
+        addrMatchD = (packet.GetSrcIP() & ln->mask) == ln->ip;
+
+        if (!foundD && addrMatchD && portMatchD)
+            {
+            foundD = true;
+            *dirD = ln->dir;
+            //printfd(__FILE__, "Down rule ok! %d\n", ln->dir);
+            //PrintRule(ln->rule);
+            }
+        } //if (!foundD)
+
+    ++ln;
+    }   //while (ln != rules.end())
+
+if (!foundU)
+    *dirU = DIR_NUM;
+
+if (!foundD)
+    *dirD = DIR_NUM;
+
+return;
+};
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::SetRulesFile(const string & fn)
+{
+rulesFileName = fn;
+}
+//-----------------------------------------------------------------------------
+bool TRAFFCOUNTER::ReadRules(bool test)
+{
+//printfd(__FILE__, "TRAFFCOUNTER::ReadRules()\n");
+
+RULE rul;
+FILE * f;
+char str[1024];
+char tp[100];   // protocol
+char ta[100];   // address
+char td[100];   // target direction
+int r;
+int lineNumber = 0;
+f = fopen(rulesFileName.c_str(), "rt");
+
+if (!f)
+    {
+    WriteServLog("File %s cannot be oppened.", rulesFileName.c_str());
+    return true;
+    }
+
+while (fgets(str, 1023, f))
+    {
+    lineNumber++;
+    if (str[strspn(str," \t")] == '#' || str[strspn(str," \t")] == '\n')
+        {
+        continue;
+        }
+
+    r = sscanf(str,"%s %s %s", tp, ta, td);
+    if (r != 3)
+        {
+        WriteServLog("Error in file %s. There must be 3 parameters. Line %d.", rulesFileName.c_str(), lineNumber);
+        return true;
+        }
+
+    rul.proto = 0xff;
+    rul.dir = 0xff;
+
+    for (int i = 0; i < PROTOMAX; i++)
+        {
+        if (strcasecmp(tp, protoName[i]) == 0)
+            rul.proto = i;
+        }
+
+    for (int i = 0; i < DIR_NUM + 1; i++)
+        {
+        if (td == dirName[i])
+            rul.dir = i;
+        }
+
+    if (rul.dir == 0xff || rul.proto == 0xff)
+        {
+        WriteServLog("Error in file %s. Line %d.",
+                     rulesFileName.c_str(), lineNumber);
+        return true;
+        }
+
+    if (ParseAddress(ta, &rul) != 0)
+        {
+        WriteServLog("Error in file %s. Error in adress. Line %d.",
+                     rulesFileName.c_str(), lineNumber);
+        return true;
+        }
+    if (!test)
+        rules.push_back(rul);
+    //PrintRule(rul);
+    }
+
+fclose(f);
+
+// Adding lastest rule: ALL 0.0.0.0/0 NULL
+rul.dir = DIR_NUM; //NULL
+rul.ip = 0;  //0.0.0.0
+rul.mask = 0;
+rul.port1 = 0;
+rul.port2 = 65535;
+rul.proto = all;
+
+if (!test)
+    rules.push_back(rul);
+
+//PrintRule(rul);
+
+return false;
+}
+//-----------------------------------------------------------------------------
+int TRAFFCOUNTER::Reload()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (ReadRules(true))
+    {
+    WriteServLog("TRAFFCOUNTER: Cannot reload rules. Errors found.");
+    return -1;
+    }
+
+FreeRules();
+ReadRules();
+WriteServLog("TRAFFCOUNTER: Reload rules successfull.");
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool TRAFFCOUNTER::ParseAddress(const char * ta, RULE * rule) const
+{
+char addr[50], mask[20], port1[20], port2[20], ports[40];
+
+int len = strlen(ta);
+char n = 0;
+int i, p;
+memset(addr, 0, sizeof(addr));
+for (i = 0; i < len; i++)
+    {
+    if (ta[i] == '/' || ta[i] == ':')
+        {
+        addr[i] = 0;
+        n = ta[i];
+        break;
+        }
+    addr[i] = ta[i];
+    n = 0;
+    }
+addr[i + 1] = 0;
+p = i + 1;
+
+if (n == '/')
+    {
+    // mask
+    for (; i < len; i++)
+        {
+        if (ta[i] == ':')
+            {
+            mask[i - p] = 0;
+            n = ':';
+            break;
+            }
+        mask[i - p] = ta[i];
+        }
+    mask[i - p] = 0;
+    }
+else
+    {
+    strcpy(mask, "32");
+    }
+
+p = i + 1;
+i++;
+
+if (n == ':')
+    {
+    // port
+    if (!(rule->proto == tcp || rule->proto == udp || rule->proto == tcp_udp))
+        {
+        WriteServLog("No ports specified for this protocol.");
+        return true;
+        }
+
+    for (; i < len; i++)
+        ports[i - p] = ta[i];
+
+    ports[i - p] = 0;
+    }
+else
+    {
+    strcpy(ports, "0-65535");
+    }
+
+char *sss;
+char pts[100];
+strcpy(pts, ports);
+
+if ((sss = strchr(ports, '-')) != NULL)
+    {
+    strncpy(port1, ports, int(sss-ports));
+    port1[int(sss - ports)] = 0;
+    strcpy(port2, sss + 1);
+    }
+else
+    {
+    strcpy(port1, ports);
+    strcpy(port2, ports);
+    }
+
+// Convert strings to mask, ports and IP
+int prt1, prt2, msk;
+unsigned ip;
+char *res;
+
+msk = strtol(mask, &res, 10);
+if (*res != 0)
+    return true;
+
+prt1 = strtol(port1, &res, 10);
+if (*res != 0)
+    return true;
+
+prt2 = strtol(port2, &res, 10);
+if (*res != 0)
+    return true;
+
+int r = inet_aton(addr, (struct in_addr*)&ip);
+if (r == 0)
+    return true;
+
+rule->ip = ip;
+rule->mask = CalcMask(msk);
+//msk = 1;
+//printfd(__FILE__, "msk=%d mask=%08X   mask=%08X\n", msk, rule->mask, (0xFFffFFff << (32 - msk)));
+
+if ((ip & rule->mask) != ip)
+    {
+    WriteServLog("Address does'n match mask.");
+    return true;
+    }
+
+rule->port1 = prt1;
+rule->port2 = prt2;
+
+return false;
+}
+//-----------------------------------------------------------------------------
+uint32_t TRAFFCOUNTER::CalcMask(uint32_t msk) const
+{
+if (msk >= 32) return 0xFFffFFff;
+if (msk == 0) return 0;
+return htonl(0xFFffFFff << (32 - msk));
+}
+//---------------------------------------------------------------------------
+void TRAFFCOUNTER::FreeRules()
+{
+rules.clear();
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::PrintRule(RULE rule) const
+{
+printf("%15s   ", inet_ntostring(rule.ip).c_str());
+printf("mask=%08X ", rule.mask);
+printf("port1=%5d ", rule.port1);
+printf("port2=%5d ", rule.port2);
+switch (rule.proto)
+    {
+    case 0:
+        printf("TCP     ");
+        break;
+    case 1:
+        printf("UDP     ");
+        break;
+    case 2:
+        printf("ICMP    ");
+        break;
+    case 3:
+        printf("TCP_UDP ");
+        break;
+    case 4:
+        printf("ALL     ");
+        break;
+    }
+printf("dir=%d \n", rule.dir);
+return;
+}
+//-----------------------------------------------------------------------------
+void TRAFFCOUNTER::SetMonitorDir(const string & monitorDir)
+{
+TRAFFCOUNTER::monitorDir = monitorDir;
+monitoring = (monitorDir != "");
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/traffcounter.h b/projects/stargazer/traffcounter.h
new file mode 100644 (file)
index 0000000..7ea4dc6
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.23 $
+ $Date: 2010/04/22 12:57:46 $
+ $Author: faust $
+ */
+
+
+#ifndef TRAFFCOUNTER_H
+#define TRAFFCOUNTER_H
+
+#include <pthread.h>
+#include <ctime>
+#include <list>
+#include <map>
+#include <string>
+
+#include "os_int.h"
+#include "stg_logger.h"
+#include "raw_ip_packet.h"
+#include "users.h"
+#include "actions.h"
+#include "noncopyable.h"
+#include "eventloop.h"
+
+#define PROTOMAX    (5)
+
+//-----------------------------------------------------------------------------
+struct RULE
+{
+uint32_t    ip;             // IP
+uint32_t    mask;           // Network mask
+uint16_t    port1;          // Min port
+uint16_t    port2;          // Max port
+uint8_t     proto;          // Protocol
+uint32_t    dir;            // Direction
+};
+//-----------------------------------------------------------------------------
+struct PACKET_EXTRA_DATA
+{
+PACKET_EXTRA_DATA()
+    : flushTime(0),
+      updateTime(0),
+      userU(),
+      userUPresent(false),
+      userD(),
+      userDPresent(false),
+      dirU(DIR_NUM),
+      dirD(DIR_NUM),
+      lenU(0),
+      lenD(0)
+{};
+
+PACKET_EXTRA_DATA(const PACKET_EXTRA_DATA & pp)
+    : flushTime(pp.flushTime),
+      updateTime(pp.updateTime),
+      userU(pp.userU),
+      userUPresent(pp.userUPresent),
+      userD(pp.userD),
+      userDPresent(pp.userDPresent),
+      dirU(pp.dirU),
+      dirD(pp.dirD),
+      lenU(pp.lenU),
+      lenD(pp.lenD)
+{};
+
+time_t      flushTime;          // Last flush time
+time_t      updateTime;         // Last update time
+user_iter   userU;              // Uploader
+bool        userUPresent;       // Uploader is registered user
+user_iter   userD;              // Downloader
+bool        userDPresent;       // Downloader is registered user
+int         dirU;               // Upload direction
+int         dirD;               // Download direction
+uint32_t    lenU;               // Upload length
+uint32_t    lenD;               // Download length
+};
+//-----------------------------------------------------------------------------
+class TRAFFCOUNTER;
+//-----------------------------------------------------------------------------
+class TRF_IP_BEFORE: public PROPERTY_NOTIFIER_BASE<uint32_t>
+{
+public:
+                    TRF_IP_BEFORE(TRAFFCOUNTER & t, user_iter u)
+                        : PROPERTY_NOTIFIER_BASE<uint32_t>(),
+                          traffCnt(t),
+                          user(u)
+                    {};
+    void            Notify(const uint32_t & oldValue, const uint32_t & newValue);
+    void            SetUser(user_iter u) { user = u; }
+    user_iter       GetUser() { return user; }
+
+private:
+    TRAFFCOUNTER &  traffCnt;
+    user_iter       user;
+};
+//-----------------------------------------------------------------------------
+class TRF_IP_AFTER: public PROPERTY_NOTIFIER_BASE<uint32_t>
+{
+public:
+                    TRF_IP_AFTER(TRAFFCOUNTER & t, user_iter u)
+                        : PROPERTY_NOTIFIER_BASE<uint32_t>(),
+                          traffCnt(t),
+                          user(u)
+                    {};
+    void            Notify(const uint32_t & oldValue, const uint32_t & newValue);
+    void            SetUser(user_iter u) { user = u; }
+    user_iter       GetUser() { return user; }
+private:
+    TRAFFCOUNTER &  traffCnt;
+    user_iter       user;
+};
+//-----------------------------------------------------------------------------
+class ADD_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+{
+public:
+            ADD_USER_NONIFIER(TRAFFCOUNTER & t) :
+                NOTIFIER_BASE<user_iter>(),
+                traffCnt(t) {};
+    virtual ~ADD_USER_NONIFIER(){};
+    void    Notify(const user_iter & user);
+private:
+    TRAFFCOUNTER & traffCnt;
+};
+//-----------------------------------------------------------------------------
+class DEL_USER_NONIFIER: public NOTIFIER_BASE<user_iter>
+{
+public:
+            DEL_USER_NONIFIER(TRAFFCOUNTER & t) :
+                NOTIFIER_BASE<user_iter>(),
+                traffCnt(t) {};
+    virtual ~DEL_USER_NONIFIER(){};
+    void    Notify(const user_iter & user);
+private:
+    TRAFFCOUNTER & traffCnt;
+};
+//-----------------------------------------------------------------------------
+class TRAFFCOUNTER : private NONCOPYABLE
+{
+friend class ADD_USER_NONIFIER;
+friend class DEL_USER_NONIFIER;
+friend class TRF_IP_BEFORE;
+friend class TRF_IP_AFTER;
+public:
+    TRAFFCOUNTER(USERS * users, const TARIFFS * tariffs, const std::string & rulesFileName);
+    ~TRAFFCOUNTER();
+
+    void        SetRulesFile(const std::string & rulesFileName);
+
+    int         Reload();
+    int         Start();
+    int         Stop();
+
+    void        Process(const RAW_PACKET & rawPacket);
+    void        SetMonitorDir(const std::string & monitorDir);
+
+private:
+    bool        ParseAddress(const char * ta, RULE * rule) const;
+    uint32_t    CalcMask(uint32_t msk) const;
+    void        FreeRules();
+    void        PrintRule(RULE rule) const;
+    bool        ReadRules(bool test = false);
+
+    static void * Run(void * data);
+
+    void        DeterminateDir(const RAW_PACKET & packet,
+                               int * dirU, // Direction for upload
+                               int * dirD) const; // Direction for download
+
+    void        FlushAndRemove();
+
+    void        AddUser(user_iter user);
+    void        DelUser(uint32_t uip);
+    void        SetUserNotifiers(user_iter user);
+    void        UnSetUserNotifiers(user_iter user);
+
+    std::list<RULE>  rules;
+    typedef std::list<RULE>::iterator rule_iter;
+
+    std::map<RAW_PACKET, PACKET_EXTRA_DATA> packets; // Packets tree
+    typedef std::map<RAW_PACKET, PACKET_EXTRA_DATA>::iterator pp_iter;
+
+    std::multimap<uint32_t, pp_iter> ip2packets; // IP-to-Packet index
+
+    typedef std::multimap<uint32_t, pp_iter>::iterator ip2p_iter;
+    typedef std::multimap<uint32_t, pp_iter>::const_iterator ip2p_citer;
+
+    std::string dirName[DIR_NUM + 1];
+
+    STG_LOGGER & WriteServLog;
+    std::string rulesFileName;
+
+    std::string monitorDir;
+    bool        monitoring;
+
+    USERS *     users;
+
+    bool        running;
+    bool        stopped;
+    pthread_mutex_t         mutex;
+    pthread_t               thread;
+
+    std::list<TRF_IP_BEFORE>     ipBeforeNotifiers;
+    std::list<TRF_IP_AFTER>      ipAfterNotifiers;
+
+    ADD_USER_NONIFIER       addUserNotifier;
+    DEL_USER_NONIFIER       delUserNotifier;
+};
+//-----------------------------------------------------------------------------
+inline
+void TRF_IP_BEFORE::Notify(const uint32_t & oldValue, const uint32_t &)
+{
+// User changes his address. Remove old IP
+if (!oldValue)
+    return;
+
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TRAFFCOUNTER::DelUser, oldValue);
+}
+//-----------------------------------------------------------------------------
+inline
+void TRF_IP_AFTER::Notify(const uint32_t &, const uint32_t & newValue)
+{
+// User changes his address. Add new IP
+if (!newValue)
+    return;
+
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TRAFFCOUNTER::AddUser, user);
+}
+//-----------------------------------------------------------------------------
+inline
+void ADD_USER_NONIFIER::Notify(const user_iter & user)
+{
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TRAFFCOUNTER::SetUserNotifiers, user);
+}
+//-----------------------------------------------------------------------------
+inline
+void DEL_USER_NONIFIER::Notify(const user_iter & user)
+{
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TRAFFCOUNTER::UnSetUserNotifiers, user);
+EVENT_LOOP_SINGLETON::GetInstance().Enqueue(traffCnt, &TRAFFCOUNTER::DelUser, user->GetCurrIP());
+}
+//-----------------------------------------------------------------------------
+#endif //TRAFFCOUNTER_H
diff --git a/projects/stargazer/user.cpp b/projects/stargazer/user.cpp
new file mode 100644 (file)
index 0000000..6c32860
--- /dev/null
@@ -0,0 +1,1376 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.101 $
+ $Date: 2010/11/03 10:50:03 $
+ $Author: faust $
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <pthread.h>
+#include <unistd.h> // access
+
+#include <cassert>
+
+#include "user.h"
+#include "common.h"
+#include "settings.h"
+#include "script_executer.h"
+#include "tariff.h"
+#include "tariffs.h"
+#include "admin.h"
+
+USER::USER(const SETTINGS * s,
+           const BASE_STORE * st,
+           const TARIFFS * t,
+           const ADMIN & a,
+           const map<uint32_t, user_iter> * ipIdx)
+    : property(s),
+      WriteServLog(GetStgLogger()),
+      login(),
+      id(0),
+      __connected(0),
+      connected(__connected),
+      userIDGenerator(),
+      __currIP(0),
+      currIP(__currIP),
+      lastIPForDisconnect(0),
+      pingTime(0),
+      sysAdmin(a),
+      store(st),
+      tariffs(t),
+      tariff(tariffs->GetNoTariff()),
+      cash(property.cash),
+      up(property.up),
+      down(property.down),
+      lastCashAdd(property.lastCashAdd),
+      passiveTime(property.passiveTime),
+      lastCashAddTime(property.lastCashAddTime),
+      freeMb(property.freeMb),
+      lastActivityTime(property.lastActivityTime),
+      password(property.password),
+      passive(property.passive),
+      disabled(property.disabled),
+      disabledDetailStat(property.disabledDetailStat),
+      alwaysOnline(property.alwaysOnline),
+      tariffName(property.tariffName),
+      nextTariff(property.nextTariff),
+      address(property.address),
+      note(property.note),
+      group(property.group),
+      email(property.email),
+      phone(property.phone),
+      realName(property.realName),
+      credit(property.credit),
+      creditExpire(property.creditExpire),
+      ips(property.ips),
+      userdata0(property.userdata0),
+      userdata1(property.userdata1),
+      userdata2(property.userdata2),
+      userdata3(property.userdata3),
+      userdata4(property.userdata4),
+      userdata5(property.userdata5),
+      userdata6(property.userdata6),
+      userdata7(property.userdata7),
+      userdata8(property.userdata8),
+      userdata9(property.userdata9),
+      passiveNotifier(this),
+      tariffNotifier(this),
+      cashNotifier(this),
+      ipNotifier(this)
+{
+settings = s;
+ipIndex = ipIdx;
+
+password = "*_EMPTY_PASSWORD_*";
+tariffName = NO_TARIFF_NAME;
+connected = 0;
+traffStatInUse = 0;
+traffStat = &traffStatInternal[0];
+tariff = tariffs->GetNoTariff();
+ips = StrToIPS("*");
+deleted = false;
+lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
+lastWriteDeatiledStat = stgTime;
+lastSwapDeatiledStat = stgTime;
+
+property.tariffName.AddBeforeNotifier(&tariffNotifier);
+property.passive.AddBeforeNotifier(&passiveNotifier);
+property.cash.AddBeforeNotifier(&cashNotifier);
+currIP.AddAfterNotifier(&ipNotifier);
+
+lastScanMessages = 0;
+
+writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+USER::USER(const USER & u)
+    : property(u.settings),
+      WriteServLog(GetStgLogger()),
+      login(u.login),
+      id(u.id),
+      __connected(u.__connected),
+      connected(__connected),
+      __currIP(u.__currIP),
+      currIP(__currIP),
+      lastIPForDisconnect(0),
+      pingTime(u.pingTime),
+      sysAdmin(u.sysAdmin),
+      store(u.store),
+      tariffs(u.tariffs),
+      tariff(u.tariff),
+      cash(property.cash),
+      up(property.up),
+      down(property.down),
+      lastCashAdd(property.lastCashAdd),
+      passiveTime(property.passiveTime),
+      lastCashAddTime(property.lastCashAddTime),
+      freeMb(property.freeMb),
+      lastActivityTime(property.lastActivityTime),
+      password(property.password),
+      passive(property.passive),
+      disabled(property.disabled),
+      disabledDetailStat(property.disabledDetailStat),
+      alwaysOnline(property.alwaysOnline),
+      tariffName(property.tariffName),
+      nextTariff(property.nextTariff),
+      address(property.address),
+      note(property.note),
+      group(property.group),
+      email(property.email),
+      phone(property.phone),
+      realName(property.realName),
+      credit(property.credit),
+      creditExpire(property.creditExpire),
+      ips(property.ips),
+      userdata0(property.userdata0),
+      userdata1(property.userdata1),
+      userdata2(property.userdata2),
+      userdata3(property.userdata3),
+      userdata4(property.userdata4),
+      userdata5(property.userdata5),
+      userdata6(property.userdata6),
+      userdata7(property.userdata7),
+      userdata8(property.userdata8),
+      userdata9(property.userdata9),
+      passiveNotifier(this),
+      tariffNotifier(this),
+      cashNotifier(this),
+      ipNotifier(this)
+{
+if (&u == this)
+    return;
+
+connected = 0;
+traffStatInUse = 0;
+
+ipIndex = u.ipIndex;
+
+deleted = u.deleted;
+traffStat = &traffStatInternal[traffStatInUse % 2];
+traffStatToWrite = &traffStatInternal[(traffStatInUse +1) % 2];
+
+lastWriteStat = u.lastWriteStat;
+lastWriteDeatiledStat = u.lastWriteDeatiledStat;
+lastSwapDeatiledStat = u.lastSwapDeatiledStat;
+
+settings = u.settings;
+
+property.tariffName.AddBeforeNotifier(&tariffNotifier);
+property.passive.AddBeforeNotifier(&passiveNotifier);
+property.cash.AddBeforeNotifier(&cashNotifier);
+currIP.AddAfterNotifier(&ipNotifier);
+
+lastScanMessages = 0;
+
+writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
+
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+USER::~USER()
+{
+property.passive.DelBeforeNotifier(&passiveNotifier);
+property.tariffName.DelBeforeNotifier(&tariffNotifier);
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+void USER::SetLogin(string const & l)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+assert(login.empty() && "Login is already set");
+login = l;
+id = userIDGenerator.GetNextID();
+}
+//-----------------------------------------------------------------------------
+int USER::ReadConf()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+USER_CONF uc;
+
+if (store->RestoreUserConf(&uc, login))
+    {
+    WriteServLog("Cannot read conf for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
+    printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+password = uc.password;
+passive = uc.passive;
+disabled = uc.disabled;
+disabledDetailStat = uc.disabledDetailStat;
+alwaysOnline = uc.alwaysOnline;
+tariffName = uc.tariffName;
+address = uc.address;
+phone = uc.phone;
+email = uc.email;
+note = uc.note;
+realName = uc.realName;
+group = uc.group;
+credit = uc.credit;
+nextTariff = uc.nextTariff;
+userdata0 = uc.userdata[0];
+userdata1 = uc.userdata[1];
+userdata2 = uc.userdata[2];
+userdata3 = uc.userdata[3];
+userdata4 = uc.userdata[4];
+userdata5 = uc.userdata[5];
+userdata6 = uc.userdata[6];
+userdata7 = uc.userdata[7];
+userdata8 = uc.userdata[8];
+userdata9 = uc.userdata[9];
+
+creditExpire = uc.creditExpire;
+ips = uc.ips;
+
+tariff = tariffs->FindByName(tariffName);
+if (tariff == NULL)
+    {
+    WriteServLog("Cannot read user %s. Tariff %s not exist.",
+                 login.c_str(), property.tariffName.Get().c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::ReadStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+USER_STAT us;
+
+if (store->RestoreUserStat(&us, login))
+    {
+    WriteServLog("Cannot read stat for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
+    printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+up = us.up;
+down = us.down;
+cash = us.cash;
+freeMb = us.freeMb;
+lastCashAdd = us.lastCashAdd;
+lastCashAddTime = us.lastCashAddTime;
+passiveTime = us.passiveTime;
+lastActivityTime = us.lastActivityTime;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::WriteConf()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+USER_CONF uc;
+
+uc.password = password;
+uc.passive = passive;
+uc.disabled = disabled;
+uc.disabledDetailStat = disabledDetailStat;
+uc.alwaysOnline = alwaysOnline;
+uc.tariffName = tariffName;
+uc.address = address;
+uc.phone = phone;
+uc.email = email;
+uc.note = note;
+uc.realName = realName;
+uc.group = group;
+uc.credit = credit;
+uc.nextTariff = nextTariff;
+uc.userdata[0] = userdata0;
+uc.userdata[1] = userdata1;
+uc.userdata[2] = userdata2;
+uc.userdata[3] = userdata3;
+uc.userdata[4] = userdata4;
+uc.userdata[5] = userdata5;
+uc.userdata[6] = userdata6;
+uc.userdata[7] = userdata7;
+uc.userdata[8] = userdata8;
+uc.userdata[9] = userdata9;
+
+uc.creditExpire = creditExpire;
+uc.ips = ips;
+
+printfd(__FILE__, "USER::WriteConf()\n");
+
+if (store->SaveUserConf(uc, login))
+    {
+    WriteServLog("Cannot write conf for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
+    printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::WriteStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+USER_STAT us;
+
+us.up = up;
+us.down = down;
+us.cash = cash;
+us.freeMb = freeMb;
+us.lastCashAdd = lastCashAdd;
+us.lastCashAddTime = lastCashAddTime;
+us.passiveTime = passiveTime;
+us.lastActivityTime = lastActivityTime;
+
+printfd(__FILE__, "USER::WriteStat()\n");
+
+if (store->SaveUserStat(us, login))
+    {
+    WriteServLog("Cannot write stat for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
+    printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+lastWriteStat = stgTime;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::WriteMonthStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+USER_STAT us;
+struct tm * t1;
+time_t tt = stgTime - 3600;
+t1 = localtime(&tt);
+
+us.up = up;
+us.down = down;
+us.cash = cash;
+us.freeMb = freeMb;
+us.lastCashAdd = lastCashAdd;
+us.lastCashAddTime = lastCashAddTime;
+us.passiveTime = passiveTime;
+us.lastActivityTime = lastActivityTime;
+
+if (store->SaveMonthStat(us, t1->tm_mon, t1->tm_year, login))
+    {
+    WriteServLog("Cannot write month stat for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
+    printfd(__FILE__, "%s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::Authorize(uint32_t ip, const string &, uint32_t dirs, const BASE_AUTH * auth)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+/*
+ *  Authorize user. It only means that user will be authorized. Nothing more.
+ *  User can be connected or disconnected while authorized.
+ *  Example: user is authorized but disconnected due to 0 money or blocking
+ */
+
+/*
+ * Prevent double authorization by identical authorizers
+ */
+if (authorizedBy.find(auth) != authorizedBy.end())
+    return 0;
+
+if (!ip)
+    return -1;
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    enabledDirs[i] = dirs & (1 << i);
+    }
+
+if (authorizedBy.size())
+    {
+    if (currIP != ip)
+        {
+        //  We are already authorized, but with different IP address
+        errorStr = "User " + login + " alredy authorized with IP address " + inet_ntostring(ip);
+        return -1;
+        }
+
+    map<uint32_t, user_iter>::const_iterator ci = ipIndex->find(ip);
+    if (ci != ipIndex->end())
+        {
+        //  Address is already present in IP-index
+        //  If it's not our IP - throw an error
+        if (&(*ci->second) != this)
+            {
+            errorStr = "IP address " + inet_ntostring(ip) + " alredy in use";
+            return -1;
+            }
+        }
+    }
+else
+    {
+    if (ipIndex->find(ip) != ipIndex->end())
+        {
+        //  Address is already present in IP-index
+        errorStr = "IP address " + inet_ntostring(ip) + " alredy in use";
+        return -1;
+        }
+
+    if (ips.ConstData().IsIPInIPS(ip))
+        {
+        currIP = ip;
+        lastIPForDisconnect = currIP;
+        }
+    else
+        {
+        printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
+        errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
+        return -1;
+        }
+    }
+
+authorizedBy.insert(auth);
+
+ScanMessage();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void USER::Unauthorize(const BASE_AUTH * auth)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+/*
+ *  Authorizer tries to unauthorize user, that was not authorized by it
+ */
+if (!authorizedBy.erase(auth))
+    return;
+
+if (authorizedBy.empty())
+    {
+    lastIPForDisconnect = currIP;
+    currIP = 0; // DelUser in traffcounter
+    return;
+    }
+}
+//-----------------------------------------------------------------------------
+bool USER::IsAuthorizedBy(const BASE_AUTH * auth) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+//  Is this user authorized by specified authorizer?
+return authorizedBy.find(auth) != authorizedBy.end();
+}
+//-----------------------------------------------------------------------------
+void USER::Connect(bool fakeConnect)
+{
+/*
+ *  Connect user to Internet. This function is differ from Authorize() !!!
+ */
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (!fakeConnect)
+    {
+    string scriptOnConnect = settings->GetScriptDir() + "/OnConnect";
+
+    if (access(scriptOnConnect.c_str(), X_OK) == 0)
+        {
+        char dirsStr[DIR_NUM + 1];
+        dirsStr[DIR_NUM] = 0;
+        for (int i = 0; i < DIR_NUM; i++)
+            {
+            dirsStr[i] = enabledDirs[i] ? '1' : '0';
+            }
+
+        string scriptOnConnectParams;
+        strprintf(&scriptOnConnectParams,
+                "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
+                scriptOnConnect.c_str(),
+                login.c_str(),
+                inet_ntostring(currIP).c_str(),
+                (double)cash,
+                id,
+                dirsStr);
+
+        ScriptExec(scriptOnConnectParams);
+        }
+    else
+        {
+        WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
+        }
+
+    connected = true;
+    }
+
+if (store->WriteUserConnect(login, currIP))
+    {
+    WriteServLog("Cannot write connect for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    }
+
+if (!fakeConnect)
+    lastIPForDisconnect = currIP;
+
+//printfd(__FILE__, "Connect. user name \'%s\' ip=%s\n", login.c_str(), inet_ntostring(currIP).c_str());
+/*if (settings->GetLogUserConnectDisconnect())
+    WriteServLog("User \'%s\', %s: Connect.", login.c_str(), inet_ntostring(currIP).c_str());*/
+}
+//-----------------------------------------------------------------------------
+void USER::Disconnect(bool fakeDisconnect, const std::string & reason)
+{
+/*
+ *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
+ */
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (!lastIPForDisconnect)
+    {
+    printfd(__FILE__, "lastIPForDisconnect\n");
+    return;
+    }
+
+if (!fakeDisconnect)
+    {
+    string scriptOnDisonnect = settings->GetScriptDir() + "/OnDisconnect";
+
+    if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
+        {
+        char dirsStr[DIR_NUM + 1];
+        dirsStr[DIR_NUM] = 0;
+        for (int i = 0; i < DIR_NUM; i++)
+            {
+            dirsStr[i] = enabledDirs[i] ? '1' : '0';
+            }
+
+        string scriptOnDisonnectParams;
+        strprintf(&scriptOnDisonnectParams,
+                "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
+                scriptOnDisonnect.c_str(),
+                login.c_str(),
+                inet_ntostring(lastIPForDisconnect).c_str(),
+                (double)cash,
+                id,
+                dirsStr);
+
+        ScriptExec(scriptOnDisonnectParams);
+        }
+    else
+        {
+        WriteServLog("Script OnDisconnect cannot be executed. File not found.");
+        }
+
+    connected = false;
+    }
+
+if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, cash, freeMb, reason))
+    {
+    WriteServLog("Cannot write disconnect for user %s.", login.c_str());
+    WriteServLog("%s", store->GetStrError().c_str());
+    }
+
+//printfd(__FILE__, "Disconnect. User name \'%s\' ip=%s reason: '%s'\n", login.c_str(), inet_ntostring(lastIPForDisconnect).c_str(), reason.c_str());
+/*if (settings->GetLogUserConnectDisconnect())
+    WriteServLog("User \'%s\', %s: Disconnect.", login.c_str(), inet_ntostring(lastIPForDisconnect).c_str());*/
+
+if (!fakeDisconnect)
+    lastIPForDisconnect = 0;
+
+DIR_TRAFF zeroSesssion;
+
+sessionUpload = zeroSesssion;
+sessionDownload = zeroSesssion;
+}
+//-----------------------------------------------------------------------------
+void USER::PrintUser() const
+{
+//return;
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+cout << "============================================================" << endl;
+cout << "id=" << id << endl;
+cout << "login=" << login << endl;
+cout << "password=" << password << endl;
+cout << "passive=" << passive << endl;
+cout << "disabled=" << disabled << endl;
+cout << "disabledDetailStat=" << disabledDetailStat << endl;
+cout << "alwaysOnline=" << alwaysOnline << endl;
+cout << "tariffName=" << tariffName << endl;
+cout << "address=" << address << endl;
+cout << "phone=" << phone << endl;
+cout << "email=" << email << endl;
+cout << "note=" << note << endl;
+cout << "realName=" <<realName << endl;
+cout << "group=" << group << endl;
+cout << "credit=" << credit << endl;
+cout << "nextTariff=" << nextTariff << endl;
+cout << "userdata0" << userdata0 << endl;
+cout << "userdata1" << userdata1 << endl;
+cout << "creditExpire=" << creditExpire << endl;
+cout << "ips=" << ips << endl;
+cout << "------------------------" << endl;
+cout << "up=" << up << endl;
+cout << "down=" << down << endl;
+cout << "cash=" << cash << endl;
+cout << "freeMb=" << freeMb << endl;
+cout << "lastCashAdd=" << lastCashAdd << endl;
+cout << "lastCashAddTime=" << lastCashAddTime << endl;
+cout << "passiveTime=" << passiveTime << endl;
+cout << "lastActivityTime=" << lastActivityTime << endl;
+cout << "============================================================" << endl;
+}
+//-----------------------------------------------------------------------------
+void USER::Run()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (stgTime - lastWriteStat > settings->GetStatWritePeriod())
+    {
+    printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
+    WriteStat();
+    }
+if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
+    {
+    WriteServLog("User: %s. Credit expired.", login.c_str());
+    credit = 0;
+    creditExpire = 0;
+    WriteConf();
+    }
+
+if (passive.ConstData()
+    && (stgTime % 30 == 0)
+    && (passiveTime.ModificationTime() != stgTime))
+    {
+    passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
+    printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
+    }
+
+if (!authorizedBy.empty())
+    {
+    if (connected)
+        {
+        lastActivityTime = *const_cast<time_t *>(&stgTime);
+        }
+    if (!connected && IsInetable())
+        {
+        Connect();
+        }
+    if (connected && !IsInetable())
+        {
+        if (disabled)
+            Disconnect(false, "disabled");
+        else if (passive)
+            Disconnect(false, "passive");
+        else
+            Disconnect(false, "no cash");
+        }
+
+    if (stgTime - lastScanMessages > 10)
+        {
+        ScanMessage();
+        lastScanMessages = stgTime;
+        }
+    }
+else
+    {
+    if (connected)
+        {
+        Disconnect(false, "not authorized");
+        }
+    }
+
+}
+//-----------------------------------------------------------------------------
+void USER::UpdatePingTime(time_t t)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+//printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
+if (t)
+    pingTime = t;
+else
+    pingTime = stgTime;
+}
+//-----------------------------------------------------------------------------
+bool USER::IsInetable()
+{
+//STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (disabled || passive)
+    return false;
+
+if (settings->GetFreeMbAllowInet())
+    {
+    if (freeMb >= 0)
+        return true;
+    }
+
+if (settings->GetShowFeeInCash())
+    {
+    return (cash >= -credit);
+    }
+
+return (cash - tariff->GetFee() >= -credit);
+}
+//-----------------------------------------------------------------------------
+string USER::GetEnabledDirs()
+{
+//STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+string dirs = "";
+for(int i = 0; i < DIR_NUM; i++)
+    dirs += enabledDirs[i] ? "1" : "0";
+return dirs;
+}
+//-----------------------------------------------------------------------------
+#ifdef TRAFF_STAT_WITH_PORTS
+void USER::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
+#else
+void USER::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
+#endif
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (!connected)
+    return;
+
+double cost = 0;
+DIR_TRAFF dt(up);
+
+int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
+int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
+
+dt[dir] += len;
+
+int tt = tariff->GetTraffType();
+if (tt == TRAFF_UP ||
+    tt == TRAFF_UP_DOWN ||
+    // Check NEW traff data
+    (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
+    {
+    double dc = 0;
+    if (traff < threshold &&
+        traff + len >= threshold)
+        {
+        // cash = partBeforeThreshold * priceBeforeThreshold +
+        //        partAfterThreshold * priceAfterThreshold
+        int64_t before = threshold - traff; // Chunk part before threshold
+        int64_t after = len - before; // Chunk part after threshold
+        dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
+                                           down.ConstData()[dir],
+                                           dir,
+                                           stgTime) * before +
+             tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
+                                           down.ConstData()[dir],
+                                           dir,
+                                           stgTime) * after;
+        }
+    else
+        {
+        dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
+                                           down.ConstData()[dir],
+                                           dir,
+                                           stgTime) * len;
+        }
+
+    if (freeMb.ConstData() <= 0) // FreeMb is exhausted
+        cost = dc;
+    else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
+        cost = dc - freeMb.ConstData();
+
+    // Direct access to internal data structures via friend-specifier
+    property.stat.freeMb -= dc;
+    property.stat.cash -= cost;
+    cash.ModifyTime();
+    freeMb.ModifyTime();
+    }
+
+up = dt;
+sessionUpload[dir] += len;
+
+//Add detailed stat
+
+if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
+    cost = 0;
+
+#ifdef TRAFF_STAT_WITH_PORTS
+IP_DIR_PAIR idp(ip, dir, port);
+#else
+IP_DIR_PAIR idp(ip, dir);
+#endif
+
+map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
+lb = traffStat->lower_bound(idp);
+if (lb == traffStat->end())
+    {
+    traffStat->insert(lb,
+                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
+                                                   STAT_NODE(len, 0, cost)));
+    }
+else
+    if (lb->first.dir == dir && lb->first.ip == ip)
+        {
+        lb->second.cash += cost;
+        lb->second.up += len;
+        }
+    else
+        {
+        traffStat->insert(lb,
+                          pair<IP_DIR_PAIR, STAT_NODE>(idp,
+                                                       STAT_NODE(len, 0, cost)));
+        }
+}
+//-----------------------------------------------------------------------------
+#ifdef TRAFF_STAT_WITH_PORTS
+void USER::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
+#else
+void USER::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
+#endif
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (!connected)
+    return;
+
+double cost = 0;
+DIR_TRAFF dt(down);
+
+int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
+int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
+
+dt[dir] += len;
+
+int tt = tariff->GetTraffType();
+if (tt == TRAFF_DOWN ||
+    tt == TRAFF_UP_DOWN ||
+    // Check NEW traff data
+    (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
+    {
+    double dc = 0;
+    if (traff < threshold &&
+        traff + len >= threshold)
+        {
+        // cash = partBeforeThreshold * priceBeforeThreshold +
+        //        partAfterThreshold * priceAfterThreshold
+        int64_t before = threshold - traff; // Chunk part before threshold
+        int64_t after = len - before; // Chunk part after threshold
+        dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
+                                           down.ConstData()[dir], // Traff before chunk
+                                           dir,
+                                           stgTime) * before +
+             tariff->GetPriceWithTraffType(up.ConstData()[dir],
+                                           dt[dir], // Traff after chunk
+                                           dir,
+                                           stgTime) * after;
+        }
+    else
+        {
+        dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
+                                           down.ConstData()[dir],
+                                           dir,
+                                           stgTime) * len;
+        }
+
+    if (freeMb.ConstData() <= 0) // FreeMb is exhausted
+        cost = dc;
+    else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
+        cost = dc - freeMb.ConstData();
+
+    property.stat.freeMb -= dc;
+    property.stat.cash -= cost;
+    cash.ModifyTime();
+    freeMb.ModifyTime();
+    }
+
+down = dt;
+sessionDownload[dir] += len;
+
+//Add detailed stat
+
+if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
+    cost = 0;
+
+#ifdef TRAFF_STAT_WITH_PORTS
+IP_DIR_PAIR idp(ip, dir, port);
+#else
+IP_DIR_PAIR idp(ip, dir);
+#endif
+
+map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
+lb = traffStat->lower_bound(idp);
+if (lb == traffStat->end())
+    {
+    traffStat->insert(lb,
+                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
+                                                   STAT_NODE(0, len, cost)));
+    }
+else
+    if (lb->first.dir == dir && lb->first.ip == ip)
+        {
+        lb->second.cash += cost;
+        lb->second.down += len;
+        }
+    else
+        {
+        traffStat->insert(lb,
+                          pair<IP_DIR_PAIR, STAT_NODE>(idp,
+                                                       STAT_NODE(0, len, cost)));
+        }
+}
+//-----------------------------------------------------------------------------
+void USER::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+currIP.AddBeforeNotifier(n);
+}
+//-----------------------------------------------------------------------------
+void USER::DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+currIP.DelBeforeNotifier(n);
+}
+//-----------------------------------------------------------------------------
+void USER::AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+currIP.AddAfterNotifier(n);
+}
+//-----------------------------------------------------------------------------
+void USER::DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+currIP.DelAfterNotifier(n);
+}
+//-----------------------------------------------------------------------------
+void USER::OnAdd()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+string scriptOnAdd = settings->GetScriptDir() + "/OnUserAdd";
+
+if (access(scriptOnAdd.c_str(), X_OK) == 0)
+    {
+    string scriptOnAddParams;
+    strprintf(&scriptOnAddParams,
+            "%s \"%s\"",
+            scriptOnAdd.c_str(),
+            login.c_str());
+
+    ScriptExec(scriptOnAddParams);
+    }
+else
+    {
+    WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
+    }
+}
+//-----------------------------------------------------------------------------
+void USER::OnDelete()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+string scriptOnDel = settings->GetScriptDir() + "/OnUserDel";
+
+if (access(scriptOnDel.c_str(), X_OK) == 0)
+    {
+    string scriptOnDelParams;
+    strprintf(&scriptOnDelParams,
+            "%s \"%s\"",
+            scriptOnDel.c_str(),
+            login.c_str());
+
+    ScriptExec(scriptOnDelParams);
+    }
+else
+    {
+    WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
+    }
+
+Run();
+}
+//-----------------------------------------------------------------------------
+void USER::ResetDetailStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+traffStatToWrite->erase(traffStatToWrite->begin(), traffStatToWrite->end());
+}
+//-----------------------------------------------------------------------------
+int USER::WriteDetailStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+printfd(__FILE__, "USER::WriteDetailedStat(): size = %d\n", traffStatToWrite->size());
+
+if (traffStatToWrite->size() && !disabledDetailStat)
+    {
+    if (store->WriteDetailedStat(traffStatToWrite, lastWriteDeatiledStat, login))
+        {
+        WriteServLog("Cannot write detail stat for user %s.", login.c_str());
+        WriteServLog("%s", store->GetStrError().c_str());
+        }
+    }
+lastWriteDeatiledStat = lastSwapDeatiledStat;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::SwapDetailStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+lastSwapDeatiledStat = stgTime;
+traffStatToWrite = &traffStatInternal[traffStatInUse % 2];
+traffStat = &traffStatInternal[++traffStatInUse % 2];
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+double USER::GetPassiveTimePart() const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+static int daysInMonth[12] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+struct tm * tms;
+time_t t = stgTime;
+tms = localtime(&t);
+
+time_t secMonth = daysInMonth[(tms->tm_mon + 11) % 12] * 24 * 3600; // Previous month
+
+if (tms->tm_year % 4 == 0 && tms->tm_mon == 1)
+    {
+    // Leap year
+    secMonth += 24 * 3600;
+    }
+
+int dt = secMonth - passiveTime;
+
+if (dt < 0)
+    dt = 0;
+
+return double(dt) / (secMonth);
+}
+//-----------------------------------------------------------------------------
+void USER::SetPassiveTimeAsNewUser()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+time_t t;
+struct tm * tm;
+t = stgTime;
+tm = localtime(&t);
+int daysCurrMon = DaysInCurrentMonth();
+double pt = (tm->tm_mday - 1) / (double)daysCurrMon;
+
+passiveTime = (time_t)(pt * 24 * 3600 * daysCurrMon);
+}
+//-----------------------------------------------------------------------------
+void USER::MidnightResetSessionStat()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (connected)
+    {
+    Disconnect(true, "fake");
+    Connect(true);
+    }
+}
+//-----------------------------------------------------------------------------
+void USER::ProcessNewMonth()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+//  Reset traff
+if (connected)
+    {
+    Disconnect(true, "fake");
+    }
+DIR_TRAFF zeroTarff;
+
+WriteMonthStat();
+
+up = zeroTarff;
+down = zeroTarff;
+
+if (connected)
+    {
+    Connect(true);
+    }
+
+//  Set new tariff
+if (nextTariff.ConstData() != "")
+    {
+    const TARIFF * nt;
+    nt = tariffs->FindByName(nextTariff);
+    if (nt == NULL)
+        {
+        WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
+                     login.c_str(), property.tariffName.Get().c_str());
+        }
+    else
+        {
+        property.tariffName.Set(nextTariff, sysAdmin, login, store);
+        tariff = nt;
+        }
+    ResetNextTariff();
+    WriteConf();
+    }
+}
+//-----------------------------------------------------------------------------
+void USER::ProcessDayFeeSpread()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (passive.ConstData())
+    return;
+
+double f = tariff->GetFee() / DaysInCurrentMonth();
+
+if (f == 0.0)
+    return;
+
+double c = cash;
+property.cash.Set(c - f, sysAdmin, login, store, "Subscriber fee charge");
+ResetPassiveTime();
+}
+//-----------------------------------------------------------------------------
+void USER::ProcessDayFee()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+double passiveTimePart = 1.0;
+if (!settings->GetFullFee())
+    {
+    passiveTimePart = GetPassiveTimePart();
+    }
+else
+    {
+    if (passive.ConstData())
+        {
+        printfd(__FILE__, "Don't charge fee `cause we are passive\n");
+        return;
+        }
+    }
+double f = tariff->GetFee() * passiveTimePart;
+
+ResetPassiveTime();
+
+if (f == 0.0)
+    return;
+
+double c = cash;
+printfd(__FILE__, "login: %8s   Fee=%f PassiveTimePart=%f fee=%f\n",
+        login.c_str(),
+        tariff->GetFee(),
+        passiveTimePart,
+        f);
+property.cash.Set(c - f, sysAdmin, login, store, "Subscriber fee charge");
+}
+//-----------------------------------------------------------------------------
+void USER::SetPrepaidTraff()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
+}
+//-----------------------------------------------------------------------------
+int USER::AddMessage(STG_MSG * msg)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (SendMessage(*msg) == 0)
+    {
+    if (msg->header.repeat > 0)
+        {
+        msg->header.repeat--;
+        #ifndef DEBUG
+        //TODO: gcc v. 4.x generate ICE on x86_64
+        msg->header.lastSendTime = time(NULL);
+        #else
+        msg->header.lastSendTime = stgTime;
+        #endif
+        if (store->AddMessage(msg, login))
+            {
+            errorStr = store->GetStrError();
+            STG_LOGGER & WriteServLog = GetStgLogger();
+            WriteServLog("Error adding message %s", errorStr.c_str());
+            WriteServLog("%s", store->GetStrError().c_str());
+            return -1;
+            }
+        }
+    }
+else
+    {
+    if (store->AddMessage(msg, login))
+        {
+        errorStr = store->GetStrError();
+        STG_LOGGER & WriteServLog = GetStgLogger();
+        WriteServLog("Error adding message %s", errorStr.c_str());
+        WriteServLog("%s", store->GetStrError().c_str());
+        return -1;
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USER::SendMessage(const STG_MSG & msg)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (authorizedBy.empty())
+    {
+    return -1;
+    }
+
+int ret = -1;
+set<const BASE_AUTH*>::iterator it;
+
+it = authorizedBy.begin();
+while (it != authorizedBy.end())
+    {
+    if ((*it)->SendMessage(msg, currIP) == 0)
+        ret = 0;
+    ++it;
+    }
+return ret;
+}
+//-----------------------------------------------------------------------------
+int USER::ScanMessage()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+vector<STG_MSG_HDR> hdrsList;
+
+if (store->GetMessageHdrs(&hdrsList, login))
+    {
+    printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+for (unsigned i = 0; i < hdrsList.size(); i++)
+    {
+
+    if (hdrsList[i].lastSendTime + hdrsList[i].repeatPeriod * 60 < (unsigned)stgTime)
+        {
+        STG_MSG msg;
+        if (store->GetMessage(hdrsList[i].id, &msg, login) == 0)
+            {
+            if (SendMessage(msg) == 0)
+                {
+                msg.header.repeat--;
+                if (msg.header.repeat < 0)
+                    {
+                    printfd(__FILE__, "DelMessage\n");
+                    store->DelMessage(hdrsList[i].id, login);
+                    }
+                else
+                    {
+                    #ifndef DEBUG
+                    //TODO: gcc v. 4.x generate ICE on x86_64
+                    msg.header.lastSendTime = time(NULL);
+                    #else
+                    msg.header.lastSendTime = stgTime;
+                    #endif
+                    if (store->EditMessage(msg, login))
+                        {
+                        printfd(__FILE__, "EditMessage Error %s\n", store->GetStrError().c_str());
+                        }
+                    }
+                }
+            }
+        else
+            {
+            WriteServLog("Cannot get message for user %s.", login.c_str());
+            WriteServLog("%s", store->GetStrError().c_str());
+            }
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
+{
+if (newPassive && !oldPassive)
+    user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
+                            user->sysAdmin,
+                            user->login,
+                            user->store,
+                            "Freeze");
+}
+//-----------------------------------------------------------------------------
+void CHG_TARIFF_NOTIFIER::Notify(const string &, const string & newTariff)
+{
+user->tariff = user->tariffs->FindByName(newTariff);
+}
+//-----------------------------------------------------------------------------
+void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
+{
+user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
+user->lastCashAdd = newCash - oldCash;
+}
+//-----------------------------------------------------------------------------
+void CHG_IP_NOTIFIER::Notify(const uint32_t & from, const uint32_t & to)
+{
+    printfd(__FILE__, "Change IP from %s to %s\n", inet_ntostring(from).c_str(), inet_ntostring(to).c_str());
+    if (from != 0)
+        user->Disconnect(false, "Change IP");
+    if (to != 0)
+        user->Connect(false);
+}
+//-----------------------------------------------------------------------------
diff --git a/projects/stargazer/user.h b/projects/stargazer/user.h
new file mode 100644 (file)
index 0000000..7a9896b
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.48 $
+ $Date: 2010/11/03 10:50:03 $
+ $Author: faust $
+ */
+
+#ifndef USER_H
+#define USER_H
+
+#include <ctime>
+#include <list>
+#include <string>
+#include <map>
+#include <set>
+
+#include "os_int.h"
+#include "stg_const.h"
+#include "user_stat.h"
+#include "user_conf.h"
+#include "user_ips.h"
+#include "user_property.h"
+#include "base_auth.h"
+#include "stg_message.h"
+#include "noncopyable.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+class USER;
+class TARIFF;
+class TARIFFS;
+class ADMIN;
+typedef list<USER>::iterator user_iter;
+typedef list<USER>::const_iterator const_user_iter;
+//-----------------------------------------------------------------------------
+class USER_ID_GENERATOR
+{
+friend class USER;
+private:
+    USER_ID_GENERATOR() {}
+    int GetNextID() { static int id = 0; return id++; }
+};
+//-----------------------------------------------------------------------------
+class CHG_PASSIVE_NOTIFIER : public PROPERTY_NOTIFIER_BASE<int>,
+                             private NONCOPYABLE
+{
+public:
+    CHG_PASSIVE_NOTIFIER(USER * u) : user(u) {}
+    void Notify(const int & oldPassive, const int & newPassive);
+
+private:
+    USER * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_TARIFF_NOTIFIER : public PROPERTY_NOTIFIER_BASE<string>,
+                            private NONCOPYABLE
+{
+public:
+    CHG_TARIFF_NOTIFIER(USER * u) : user(u) {}
+    void Notify(const string & oldTariff, const string & newTariff);
+
+private:
+    USER * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_CASH_NOTIFIER : public PROPERTY_NOTIFIER_BASE<double>,
+                          private NONCOPYABLE
+{
+public:
+    CHG_CASH_NOTIFIER(USER * u) : user(u) {}
+    void Notify(const double & oldCash, const double & newCash);
+
+private:
+    USER * user;
+};
+//-----------------------------------------------------------------------------
+class CHG_IP_NOTIFIER : public PROPERTY_NOTIFIER_BASE<uint32_t>,
+                        private NONCOPYABLE
+{
+public:
+    CHG_IP_NOTIFIER(USER * u) : user(u) {}
+    void Notify(const uint32_t & oldCash, const uint32_t & newCash);
+
+private:
+    USER * user;
+};
+//-----------------------------------------------------------------------------
+class USER
+{
+friend class CHG_PASSIVE_NOTIFIER;
+friend class CHG_TARIFF_NOTIFIER;
+friend class CHG_CASH_NOTIFIER;
+friend class CHG_IP_NOTIFIER;
+public:
+    USER(const SETTINGS * settings,
+         const BASE_STORE * store,
+         const TARIFFS * tariffs,
+         const ADMIN & sysAdmin,
+         const map<uint32_t, user_iter> * ipIndex);
+    USER(const USER & u);
+    ~USER();
+
+    int             ReadConf();
+    int             ReadStat();
+    int             WriteConf();
+    int             WriteStat();
+    int             WriteMonthStat();
+
+    string const &  GetLogin() const { return login; }
+    void            SetLogin(string const & l);
+
+    uint32_t        GetCurrIP() const { return currIP; }
+    time_t          GetCurrIPModificationTime() const { return currIP.ModificationTime(); }
+
+    void            AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> *);
+    void            DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> *);
+
+    void            AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> *);
+    void            DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> *);
+
+    int             GetID() const { return id; }
+
+    double          GetPassiveTimePart() const;
+    void            ResetPassiveTime() { passiveTime = 0; }
+    void            SetPassiveTimeAsNewUser();
+
+    void            ResetDetailStat();
+    int             SwapDetailStat();
+    int             WriteDetailStat();
+
+    const TARIFF *  GetTariff() const { return tariff; }
+    void            ResetNextTariff() { nextTariff = ""; }
+
+    #ifdef TRAFF_STAT_WITH_PORTS
+    void            AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len);
+    void            AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len);
+    #else
+    void            AddTraffStatU(int dir, uint32_t ip, uint32_t len);
+    void            AddTraffStatD(int dir, uint32_t ip, uint32_t len);
+    #endif
+
+    const DIR_TRAFF & GetSessionUpload() const { return sessionUpload; }
+    const DIR_TRAFF & GetSessionDownload() const { return sessionDownload; }
+
+    bool            GetConnected() const { return connected; }
+    time_t          GetConnectedModificationTime() const { return connected.ModificationTime(); }
+    int             GetAuthorized() const { return authorizedBy.size(); }
+    int             Authorize(uint32_t ip, const string & iface, uint32_t enabledDirs, const BASE_AUTH * auth);
+    void            Unauthorize(const BASE_AUTH * auth);
+    bool            IsAuthorizedBy(const BASE_AUTH * auth) const;
+    void            OnAdd();
+    void            OnDelete();
+
+    int             AddMessage(STG_MSG * msg);
+
+    void            UpdatePingTime(time_t t = 0);
+    time_t          GetPingTime() const { return pingTime; }
+
+    void            PrintUser() const;
+    void            Run();
+
+    const string &  GetStrError() const { return errorStr; }
+
+    USER_PROPERTIES property;
+
+    void            SetDeleted() { deleted = true; }
+    bool            GetDeleted() const { return deleted; }
+
+    time_t          GetLastWriteStatTime() const { return lastWriteStat; }
+
+    void            MidnightResetSessionStat();
+    void            ProcessDayFee();
+    void            SetPrepaidTraff();
+    void            ProcessDayFeeSpread();
+    void            ProcessNewMonth();
+
+    bool            IsInetable();
+    string          GetEnabledDirs();
+
+private:
+    STG_LOGGER &    WriteServLog;
+
+    void            Connect(bool fakeConnect = false);
+    void            Disconnect(bool fakeDisconnect, const std::string & reason);
+    int             SaveMonthStat(int month, int year);
+
+    int             SendMessage(const STG_MSG & msg);
+    int             RemoveMessage(uint64_t) { return 0; }
+    int             ScanMessage();
+    time_t          lastScanMessages;
+
+    string          login;
+    int             id;
+    bool            __connected;
+    USER_PROPERTY<bool> connected;
+
+    bool            enabledDirs[DIR_NUM];
+
+    USER_ID_GENERATOR userIDGenerator;
+
+    uint32_t        __currIP; // ôÅËÕÝÉÊ ÁÄÒÅÓ ÐÏÌØÚÏ×ÁÔÅÌÑ
+    USER_PROPERTY<uint32_t> currIP;
+
+    /*
+    ë ÔÏÍÕ ÍÏÍÅÎÔÕ ËÁË ÍÙ ÕÖÅ ÎÅ Á×ÔÏÒÉÚÏ×ÁÎÉÙ, ÎÏ ÅÝÅ ÎÅ ×ÙÐÏÌÎÅΠDisconnect,
+    currIP ÕÖÅ ÓÂÒÏÛÅÎ. ðÏÓÌÅÄÎÅÅ ÚÎÁÞÅÎÉÅ currIP ÓÏÈÒÁÎÑÅÍ × lastIPForDisconnect
+    */
+    uint32_t        lastIPForDisconnect;
+
+    time_t          pingTime;
+
+    const ADMIN     sysAdmin;
+    const BASE_STORE * store;
+
+    const TARIFFS * tariffs;
+    const TARIFF *  tariff;
+
+    map<IP_DIR_PAIR, STAT_NODE>     traffStatInternal[2];
+    map<IP_DIR_PAIR, STAT_NODE> *   traffStat;
+    map<IP_DIR_PAIR, STAT_NODE> *   traffStatToWrite;
+    int                             traffStatInUse;
+
+    const SETTINGS * settings;
+
+    set<const BASE_AUTH *> authorizedBy;
+
+    const map<uint32_t, user_iter> * ipIndex;
+
+    bool            deleted;
+
+    time_t          lastWriteStat;           // ÷ÒÅÍÑ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ ÓÔÁÔÉÓÔÉËÉ
+    time_t          lastWriteDeatiledStat;   // ÷ÒÅÍÑ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ ÄÅÔÁÌØÎÏÊ ÓÔÁÔÉÓÔÉËÉ
+    time_t          lastSwapDeatiledStat;    // ÷ÒÅÍÑ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ ÄÅÔÁÌØÎÏÊ ÓÔÁÔÉÓÔÉËÉ
+
+    bool            writeFreeMbTraffCost;
+
+    // Properties
+    USER_PROPERTY<double>         & cash;
+    USER_PROPERTY<DIR_TRAFF>      & up;
+    USER_PROPERTY<DIR_TRAFF>      & down;
+    USER_PROPERTY<double>         & lastCashAdd;
+    USER_PROPERTY<time_t>         & passiveTime;
+    USER_PROPERTY<time_t>         & lastCashAddTime;
+    USER_PROPERTY<double>         & freeMb;
+    USER_PROPERTY<time_t>         & lastActivityTime;
+    USER_PROPERTY<string>         & password;
+    USER_PROPERTY<int>            & passive;
+    USER_PROPERTY<int>            & disabled;
+    USER_PROPERTY<int>            & disabledDetailStat;
+    USER_PROPERTY<int>            & alwaysOnline;
+    USER_PROPERTY<string>         & tariffName;
+    USER_PROPERTY<string>         & nextTariff;
+    USER_PROPERTY<string>         & address;
+    USER_PROPERTY<string>         & note;
+    USER_PROPERTY<string>         & group;
+    USER_PROPERTY<string>         & email;
+    USER_PROPERTY<string>         & phone;
+    USER_PROPERTY<string>         & realName;
+    USER_PROPERTY<double>         & credit;
+    USER_PROPERTY<time_t>         & creditExpire;
+    USER_PROPERTY<USER_IPS>       & ips;
+    USER_PROPERTY<string>         & userdata0;
+    USER_PROPERTY<string>         & userdata1;
+    USER_PROPERTY<string>         & userdata2;
+    USER_PROPERTY<string>         & userdata3;
+    USER_PROPERTY<string>         & userdata4;
+    USER_PROPERTY<string>         & userdata5;
+    USER_PROPERTY<string>         & userdata6;
+    USER_PROPERTY<string>         & userdata7;
+    USER_PROPERTY<string>         & userdata8;
+    USER_PROPERTY<string>         & userdata9;
+
+    // End properties
+
+    DIR_TRAFF                sessionUpload;
+    DIR_TRAFF                sessionDownload;
+
+    CHG_PASSIVE_NOTIFIER     passiveNotifier;
+    CHG_TARIFF_NOTIFIER      tariffNotifier;
+    CHG_CASH_NOTIFIER        cashNotifier;
+    CHG_IP_NOTIFIER          ipNotifier;
+
+    mutable pthread_mutex_t  mutex;
+
+    string                   errorStr;
+};
+//-----------------------------------------------------------------------------
+
+#endif //USER_H
diff --git a/projects/stargazer/user_property.cpp b/projects/stargazer/user_property.cpp
new file mode 100644 (file)
index 0000000..c1e202d
--- /dev/null
@@ -0,0 +1,46 @@
+#include "user_property.h"
+
+//-----------------------------------------------------------------------------
+USER_PROPERTIES::USER_PROPERTIES(const SETTINGS * s)
+:
+cash            (stat.cash,             "cash",             false, true, GetStgLogger(), s),
+up              (stat.up,               "upload",           false, true, GetStgLogger(), s),
+down            (stat.down,             "download",         false, true, GetStgLogger(), s),
+lastCashAdd     (stat.lastCashAdd,      "lastCashAdd",      false, true, GetStgLogger(), s),
+passiveTime     (stat.passiveTime,      "passiveTime",      false, true, GetStgLogger(), s),
+lastCashAddTime (stat.lastCashAddTime,  "lastCashAddTime",  false, true, GetStgLogger(), s),
+freeMb          (stat.freeMb,           "freeMb",           false, true, GetStgLogger(), s),
+lastActivityTime(stat.lastActivityTime, "lastActivityTime", false, true, GetStgLogger(), s),
+
+
+password    (conf.password,     "password",     true,  false, GetStgLogger(), s),
+passive     (conf.passive,      "passive",      false, false, GetStgLogger(), s),
+disabled    (conf.disabled,     "disabled",     false, false, GetStgLogger(), s),
+disabledDetailStat(conf.disabledDetailStat,"DisabledDetailStat",false,false,GetStgLogger(), s),
+alwaysOnline(conf.alwaysOnline, "alwaysOnline", false, false, GetStgLogger(), s),
+tariffName  (conf.tariffName,   "tariff",       false, false, GetStgLogger(), s),
+nextTariff  (conf.nextTariff,   "new tariff",   false, false, GetStgLogger(), s),
+address     (conf.address,      "address",      false, false, GetStgLogger(), s),
+note        (conf.note,         "note",         false, false, GetStgLogger(), s),
+group       (conf.group,        "group",        false, false, GetStgLogger(), s),
+email       (conf.email,        "email",        false, false, GetStgLogger(), s),
+phone       (conf.phone,        "phone",        false, false, GetStgLogger(), s),
+realName    (conf.realName,     "realName",     false, false, GetStgLogger(), s),
+credit      (conf.credit,       "credit",       false, false, GetStgLogger(), s),
+creditExpire(conf.creditExpire, "creditExpire", false, false, GetStgLogger(), s),
+ips         (conf.ips,          "IP",           false, false, GetStgLogger(), s),
+userdata0   (conf.userdata[0],  "userdata0",    false, false, GetStgLogger(), s),
+userdata1   (conf.userdata[1],  "userdata1",    false, false, GetStgLogger(), s),
+userdata2   (conf.userdata[2],  "userdata2",    false, false, GetStgLogger(), s),
+userdata3   (conf.userdata[3],  "userdata3",    false, false, GetStgLogger(), s),
+userdata4   (conf.userdata[4],  "userdata4",    false, false, GetStgLogger(), s),
+userdata5   (conf.userdata[5],  "userdata5",    false, false, GetStgLogger(), s),
+userdata6   (conf.userdata[6],  "userdata6",    false, false, GetStgLogger(), s),
+userdata7   (conf.userdata[7],  "userdata7",    false, false, GetStgLogger(), s),
+userdata8   (conf.userdata[8],  "userdata8",    false, false, GetStgLogger(), s),
+userdata9   (conf.userdata[9],  "userdata9",    false, false, GetStgLogger(), s)
+{
+
+}
+//-----------------------------------------------------------------------------
+
diff --git a/projects/stargazer/user_property.h b/projects/stargazer/user_property.h
new file mode 100644 (file)
index 0000000..5a8856d
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+$Revision: 1.44 $
+$Date: 2010/09/13 05:54:43 $
+$Author: faust $
+*/
+
+
+#ifndef USER_PROPERTY_H
+#define USER_PROPERTY_H
+
+#include <ctime>
+#include <string>
+#include <set>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+
+#include "base_store.h"
+#include "stg_logger.h"
+#include "admin.h"
+#include "settings.h"
+#include "notifer.h"
+#include "stg_logger.h"
+#include "stg_locker.h"
+#include "script_executer.h"
+
+using namespace std;
+
+extern const volatile time_t stgTime;
+
+//-----------------------------------------------------------------------------
+template<typename varT>
+class USER_PROPERTY
+    {
+public:
+    USER_PROPERTY(varT& val);
+    USER_PROPERTY<varT>& operator= (const varT&);
+    USER_PROPERTY<varT>& operator-= (const varT&);
+    virtual ~USER_PROPERTY();
+
+    const varT * operator&() const throw();
+    const varT& ConstData() const throw();
+
+    operator const varT&() const throw()
+    {
+        return value;
+    }
+
+    //bool    IsEmpty() const throw();
+
+    void    AddBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
+    void    DelBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
+
+    void    AddAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
+    void    DelAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
+
+    time_t  ModificationTime() const throw();
+    void    ModifyTime() throw();
+
+protected:
+    varT  & value;
+    time_t  modificationTime;
+    //typedef set<PROPERTY_NOTIFIER_BASE<varT> *>::iterator notifier_iter_t;
+    mutable set<PROPERTY_NOTIFIER_BASE<varT> *> beforeNotifiers;
+    mutable set<PROPERTY_NOTIFIER_BASE<varT> *> afterNotifiers;
+    mutable pthread_mutex_t mutex;
+    };
+//-----------------------------------------------------------------------------
+template<typename varT>
+class USER_PROPERTY_LOGGED: public USER_PROPERTY<varT>
+    {
+public:
+    USER_PROPERTY_LOGGED(varT& val,
+                         const string n,
+                         bool isPassword,
+                         bool isStat,
+                         STG_LOGGER & logger,
+                         const SETTINGS * s);
+    virtual ~USER_PROPERTY_LOGGED();
+
+    //operator const varT&() const throw();;
+    USER_PROPERTY_LOGGED<varT> * GetPointer() throw();
+    const varT & Get() const;
+    const string & GetName() const;
+    bool Set(const varT & val,
+             const ADMIN & admin,
+             const string & login,
+             const BASE_STORE * store,
+             const string & msg = "");
+protected:
+    void WriteAccessDenied(const string & login,
+                           const ADMIN  & admin,
+                           const string & parameter);
+
+    void WriteSuccessChange(const string     & login,
+                            const ADMIN      & admin,
+                            const string     & parameter,
+                            const string     & oldValue,
+                            const string     & newValue,
+                            const string     & msg,
+                            const BASE_STORE * store);
+
+    void OnChange(const string & login,
+                  const string & paramName,
+                  const string & oldValue,
+                  const string & newValue,
+                  const ADMIN  & admin);
+
+    string          name;       // parameter name. needed for logging
+    bool            isPassword; // is parameter password. when true, it will be logged as *******
+    bool            isStat;     // is parameter a stat data or conf data?
+    mutable pthread_mutex_t mutex;
+    STG_LOGGER &    stgLogger;  // server's logger
+    const SETTINGS * settings;
+    };
+//-----------------------------------------------------------------------------
+class USER_PROPERTIES
+    {
+    friend class USER;
+/*
+ В этом месте важен порядок следования приватной и открытой частей.
+ Это связано с тем, что часть которая находится в публичной секции
+ по сути является завуалированной ссылкой на закрытую часть. Т.о. нам нужно
+ чтобы конструкторы из закрытой части вызвались раньше открытой. Поэтомому в
+ начале идет закрытая секция
+ * */
+
+private:
+    USER_STAT stat;
+    USER_CONF conf;
+
+public:
+    USER_PROPERTIES(const SETTINGS * settings);
+    USER_PROPERTY_LOGGED<double>            cash;
+    USER_PROPERTY_LOGGED<DIR_TRAFF>         up;
+    USER_PROPERTY_LOGGED<DIR_TRAFF>         down;
+    USER_PROPERTY_LOGGED<double>            lastCashAdd;
+    USER_PROPERTY_LOGGED<time_t>            passiveTime;
+    USER_PROPERTY_LOGGED<time_t>            lastCashAddTime;
+    USER_PROPERTY_LOGGED<double>            freeMb;
+    USER_PROPERTY_LOGGED<time_t>            lastActivityTime;
+
+    USER_PROPERTY_LOGGED<string>            password;
+    USER_PROPERTY_LOGGED<int>               passive;
+    USER_PROPERTY_LOGGED<int>               disabled;
+    USER_PROPERTY_LOGGED<int>               disabledDetailStat;
+    USER_PROPERTY_LOGGED<int>               alwaysOnline;
+    USER_PROPERTY_LOGGED<string>            tariffName;
+    USER_PROPERTY_LOGGED<string>            nextTariff;
+    USER_PROPERTY_LOGGED<string>            address;
+    USER_PROPERTY_LOGGED<string>            note;
+    USER_PROPERTY_LOGGED<string>            group;
+    USER_PROPERTY_LOGGED<string>            email;
+    USER_PROPERTY_LOGGED<string>            phone;
+    USER_PROPERTY_LOGGED<string>            realName;
+    USER_PROPERTY_LOGGED<double>            credit;
+    USER_PROPERTY_LOGGED<time_t>            creditExpire;
+    USER_PROPERTY_LOGGED<USER_IPS>          ips;
+    USER_PROPERTY_LOGGED<string>            userdata0;
+    USER_PROPERTY_LOGGED<string>            userdata1;
+    USER_PROPERTY_LOGGED<string>            userdata2;
+    USER_PROPERTY_LOGGED<string>            userdata3;
+    USER_PROPERTY_LOGGED<string>            userdata4;
+    USER_PROPERTY_LOGGED<string>            userdata5;
+    USER_PROPERTY_LOGGED<string>            userdata6;
+    USER_PROPERTY_LOGGED<string>            userdata7;
+    USER_PROPERTY_LOGGED<string>            userdata8;
+    USER_PROPERTY_LOGGED<string>            userdata9;
+    };
+
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY<varT>::USER_PROPERTY(varT& val)
+:
+value(val)
+{
+pthread_mutex_init(&mutex, NULL);
+modificationTime = stgTime;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY<varT>::~USER_PROPERTY()
+{
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY<varT>::ModifyTime() throw()
+{
+    modificationTime = stgTime;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY<varT>& USER_PROPERTY<varT>::operator= (const varT& newValue)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+
+/*
+TODO
+if (value == newValue)
+    return *this;*/
+
+typename set<PROPERTY_NOTIFIER_BASE<varT> *>::iterator ni;
+
+//printf("USER_PROPERTY<varT>::operator= (const varT& rhs)\n");
+
+varT oldVal = value;
+
+ni = beforeNotifiers.begin();
+while (ni != beforeNotifiers.end())
+    (*ni++)->Notify(oldVal, newValue);
+
+value = newValue;
+modificationTime = stgTime;
+
+ni = afterNotifiers.begin();
+while (ni != afterNotifiers.end())
+    (*ni++)->Notify(oldVal, newValue);
+
+return *this;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY<varT>& USER_PROPERTY<varT>::operator-= (const varT& delta)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+
+typename set<PROPERTY_NOTIFIER_BASE<varT> *>::iterator ni;
+
+varT oldVal = value;
+
+ni = beforeNotifiers.begin();
+while (ni != beforeNotifiers.end())
+    (*ni++)->Notify(oldVal, oldVal - delta);
+
+value -= delta;
+modificationTime = stgTime;
+
+ni = afterNotifiers.begin();
+while (ni != afterNotifiers.end())
+    (*ni++)->Notify(oldVal, value);
+
+return *this;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+const varT * USER_PROPERTY<varT>::operator&() const throw()
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return &value;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+const varT& USER_PROPERTY<varT>::ConstData() const throw()
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return value;
+}
+//-----------------------------------------------------------------------------
+/*template <typename varT>
+bool USER_PROPERTY<varT>::IsEmpty() const throw()
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return !is_set;
+}*/
+//-----------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY<varT>::AddBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+beforeNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY<varT>::DelBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+beforeNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY<varT>::AddAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+afterNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY<varT>::DelAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+afterNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+time_t USER_PROPERTY<varT>::ModificationTime() const throw()
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return modificationTime;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY_LOGGED<varT>::USER_PROPERTY_LOGGED(
+                                                varT& val,
+                                                string n,
+                                                bool isPass,
+                                                bool isSt,
+                                                STG_LOGGER & logger,
+                                                const SETTINGS * s)
+
+:USER_PROPERTY<varT>(val),
+stgLogger(logger)
+{
+pthread_mutex_init(&mutex, NULL);
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+USER_PROPERTY<varT>::value = val;
+isPassword = isPass;
+isStat = isSt;
+name = n;
+settings = s;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY_LOGGED<varT>::~USER_PROPERTY_LOGGED()
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+USER_PROPERTY_LOGGED<varT> * USER_PROPERTY_LOGGED<varT>::GetPointer() throw()
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return this;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+const varT & USER_PROPERTY_LOGGED<varT>::Get() const
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return USER_PROPERTY<varT>::value;
+};
+//-------------------------------------------------------------------------
+template <typename varT>
+const string & USER_PROPERTY_LOGGED<varT>::GetName() const
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+return name;
+};
+//-------------------------------------------------------------------------
+template <typename varT>
+bool USER_PROPERTY_LOGGED<varT>::Set(const varT & val,
+                                     const ADMIN & admin,
+                                     const string & login,
+                                     const BASE_STORE * store,
+                                     const string & msg)
+{
+STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+
+//cout << "USER_PROPERTY_LOGGED " << val << endl;
+//value = val;
+//modificationTime = stgTime;
+
+const PRIV * priv = admin.GetPriv();
+string adm_login = admin.GetLogin();
+string adm_ip = admin.GetAdminIPStr();
+
+if ((priv->userConf && !isStat) || (priv->userStat && isStat) || (priv->userPasswd && isPassword) || (priv->userCash && name == "cash"))
+    {
+    stringstream oldVal;
+    stringstream newVal;
+
+    oldVal.flags(oldVal.flags() | ios::fixed);
+    newVal.flags(newVal.flags() | ios::fixed);
+
+    oldVal << USER_PROPERTY<varT>::value;
+    newVal << val;
+
+    OnChange(login, name, oldVal.str(), newVal.str(), admin);
+
+    if (isPassword)
+        {
+        WriteSuccessChange(login, admin, name, "******", "******", msg, store);
+        }
+    else
+        {
+        WriteSuccessChange(login, admin, name, oldVal.str(), newVal.str(), msg, store);
+        }
+    USER_PROPERTY<varT>::operator =(val);
+    return true;
+    }
+else
+    {
+    WriteAccessDenied(login, admin, name);
+    return false;
+    }
+return true;
+}
+//-------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY_LOGGED<varT>::WriteAccessDenied(const string & login,
+                                                   const ADMIN  & admin,
+                                                   const string & parameter)
+{
+stgLogger("%s Change user \'%s.\' Parameter \'%s\'. Access denied.",
+          admin.GetLogStr().c_str(), login.c_str(), parameter.c_str());
+}
+//-------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY_LOGGED<varT>::WriteSuccessChange(const string & login,
+                                                    const ADMIN      & admin,
+                                                    const string     & parameter,
+                                                    const string     & oldValue,
+                                                    const string     & newValue,
+                                                    const string     & msg,
+                                                    const BASE_STORE * store)
+{
+stgLogger("%s User \'%s\': \'%s\' parameter changed from \'%s\' to \'%s\'. %s",
+          admin.GetLogStr().c_str(),
+          login.c_str(),
+          parameter.c_str(),
+          oldValue.c_str(),
+          newValue.c_str(),
+          msg.c_str());
+
+
+/*char userLogMsg[2048];
+sprintf(userLogMsg, "\'%s\' parameter changed from \'%s\' to \'%s\'. %s",
+         parameter.c_str(), oldValue.c_str(),
+         newValue.c_str(),  msg.c_str());*/
+store->WriteUserChgLog(login, admin.GetLogin(), admin.GetAdminIP(), parameter, oldValue, newValue, msg);
+//store->WriteLogString(userLogMsg, login);
+}
+//-------------------------------------------------------------------------
+template <typename varT>
+void USER_PROPERTY_LOGGED<varT>::OnChange(const string & login,
+                                          const string & paramName,
+                                          const string & oldValue,
+                                          const string & newValue,
+                                          const ADMIN  &)
+{
+string str1;
+
+str1 = settings->GetConfDir() + "/OnChange";
+
+if (access(str1.c_str(), X_OK) == 0)
+    {
+    string str2("\"" + str1 + "\" \"" + login + "\" \"" + paramName + "\" \"" + oldValue + "\" \"" + newValue + "\"");
+    ScriptExec(str2);
+    }
+else
+    {
+    stgLogger("Script OnChange cannot be executed. File %s not found.", str1.c_str());
+    }
+}
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+template<typename varT>
+stringstream & operator<< (stringstream & s, const USER_PROPERTY<varT> & v)
+{
+s << v.ConstData();
+return s;
+}
+//-----------------------------------------------------------------------------
+template<typename varT>
+ostream & operator<< (ostream & o, const USER_PROPERTY<varT> & v)
+{
+return o << v.ConstData();
+}
+//-----------------------------------------------------------------------------
+
+
+#endif // USER_PROPERTY_H
+
diff --git a/projects/stargazer/users.cpp b/projects/stargazer/users.cpp
new file mode 100644 (file)
index 0000000..1b710ba
--- /dev/null
@@ -0,0 +1,768 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.61 $
+ $Date: 2010/09/13 05:56:42 $
+ $Author: faust $
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <pthread.h>
+#include <csignal>
+#include <cassert>
+#include <algorithm>
+#include <utility>
+#include <string>
+#include <vector>
+
+#include "settings.h"
+#include "users.h"
+#include "user.h"
+#include "common.h"
+#include "stg_timer.h"
+
+using namespace std;
+
+extern const volatile time_t stgTime;
+
+//#define USERS_DEBUG 1
+
+//-----------------------------------------------------------------------------
+USERS::USERS(SETTINGS * s, BASE_STORE * st, TARIFFS * t, const ADMIN & sa)
+    : users(),
+      usersToDelete(),
+      userIPNotifiersBefore(),
+      userIPNotifiersAfter(),
+      ipIndex(),
+      loginIndex(),
+      settings(s),
+      tariffs(t),
+      store(st),
+      sysAdmin(sa),
+      WriteServLog(GetStgLogger()),
+      nonstop(false),
+      isRunning(false),
+      mutex(),
+      thread(),
+      handle(0),
+      searchDescriptors(),
+      onAddNotifiers(),
+      onDelNotifiers()
+{
+pthread_mutexattr_t attr;
+pthread_mutexattr_init(&attr);
+pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+pthread_mutex_init(&mutex, &attr);
+}
+//-----------------------------------------------------------------------------
+USERS::~USERS()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int USERS::FindByNameNonLock(const string & login, user_iter * user) const
+{
+map<string, user_iter>::const_iterator iter;
+iter = loginIndex.find(login);
+if (iter != loginIndex.end())
+    {
+    if (user)
+        *user = iter->second;
+    return 0;
+    }
+return -1;
+}
+//-----------------------------------------------------------------------------
+int USERS::FindByName(const string & login, user_iter * user) const
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return FindByNameNonLock(login, user);
+}
+//-----------------------------------------------------------------------------
+bool USERS::TariffInUse(const string & tariffName)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+list<USER>::iterator iter;
+iter = users.begin();
+while (iter != users.end())
+    {
+    if (iter->property.tariffName.Get() == tariffName)
+        return true;
+    ++iter;
+    }
+return false;
+}
+//-----------------------------------------------------------------------------
+int USERS::Add(const string & login, const ADMIN & admin)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+const PRIV * priv = admin.GetPriv();
+
+if (!priv->userAddDel)
+    {
+    WriteServLog("%s tried to add user \'%s\'. Access denied.",
+         admin.GetLogStr().c_str(), login.c_str());
+    /*errorStr = "Admin \'" + admin.GetLogin() +
+               "\': tried to add user \'" + ud->login + "\'. Access denied.";*/
+    return -1;
+    }
+
+//////
+if (store->AddUser(login))
+    {
+    //TODO
+    //WriteServLog("Admin \'%s\': tried to add user \'%s\'. Access denied.",
+    //     admin.GetLogin().c_str(), ud->login.c_str());
+    return -1;
+    }
+//////
+
+USER u(settings, store, tariffs, sysAdmin, &ipIndex);
+
+struct tm * tms;
+time_t t = stgTime;
+
+tms = localtime(&t);
+
+tms->tm_hour = 0;
+tms->tm_min = 0;
+tms->tm_sec = 0;
+
+if (settings->GetDayResetTraff() > tms->tm_mday)
+    tms->tm_mon -= 1;
+
+tms->tm_mday = settings->GetDayResetTraff();
+
+u.SetLogin(login);
+
+u.SetPassiveTimeAsNewUser();
+
+u.WriteConf();
+u.WriteStat();
+
+WriteServLog("%s User \'%s\' added.",
+         admin.GetLogStr().c_str(), login.c_str());
+
+u.OnAdd();
+
+users.push_front(u);
+
+AddUserIntoIndexes(users.begin());
+SetUserNotifiers(users.begin());
+
+// õ×ÅÄÏÍÌÑÅÍ ×ÓÅÈ ÖÅÌÁÀÝÉÈ, ÞÔÏ ÄÏÂÁ×ÌÅΠÎÏ×ÙÊ ÐÏÌØÚÏ×ÁÔÅÌØ
+set<NOTIFIER_BASE<user_iter> *>::iterator ni = onAddNotifiers.begin();
+while (ni != onAddNotifiers.end())
+    {
+    (*ni)->Notify(users.begin());
+    ++ni;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void USERS::Del(const string & login, const ADMIN & admin)
+{
+const PRIV * priv = admin.GetPriv();
+user_iter u;
+
+if (!priv->userAddDel)
+    {
+    WriteServLog("%s tried to remove user \'%s\'. Access denied.",
+         admin.GetLogStr().c_str(), login.c_str());
+    return;
+    }
+
+
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+    if (FindByNameNonLock(login, &u))
+        {
+        WriteServLog("%s tried to delete user \'%s\': not found.",
+                     admin.GetLogStr().c_str(),
+                     login.c_str());
+        return;
+        }
+    }
+
+set<NOTIFIER_BASE<user_iter> *>::iterator ni = onDelNotifiers.begin();
+while (ni != onDelNotifiers.end())
+    {
+    (*ni)->Notify(u);
+    ++ni;
+    }
+
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+    u->OnDelete();
+    u->SetDeleted();
+
+    USER_TO_DEL utd;
+    utd.iter = u;
+    utd.delTime = stgTime;
+    usersToDelete.push_back(utd);
+
+    UnSetUserNotifiers(u);
+    DelUserFromIndexes(u);
+
+    WriteServLog("%s User \'%s\' deleted.",
+             admin.GetLogStr().c_str(), login.c_str());
+
+    }
+}
+//-----------------------------------------------------------------------------
+int USERS::ReadUsers()
+{
+vector<string> usersList;
+usersList.clear();
+if (store->GetUsersList(&usersList) < 0)
+    {
+    WriteServLog(store->GetStrError().c_str());
+    exit(1);
+    }
+
+user_iter ui;
+
+for (unsigned int i = 0; i < usersList.size(); i++)
+    {
+    USER u(settings, store, tariffs, sysAdmin, &ipIndex);
+
+    u.SetLogin(usersList[i]);
+    users.push_front(u);
+    ui = users.begin();
+
+    AddUserIntoIndexes(ui);
+    SetUserNotifiers(ui);
+
+    if (ui->ReadConf() < 0)
+        return -1;
+
+    if (ui->ReadStat() < 0)
+        return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void * USERS::Run(void * d)
+{
+printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
+USERS * us = (USERS*) d;
+
+struct tm * t;
+time_t tt = stgTime;
+t = localtime(&tt);
+
+int min = t->tm_min;
+int day = t->tm_mday;
+
+printfd(__FILE__,"Day = %d Min = %d\n", day, min);
+
+time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
+string monFile = us->settings->GetMonitorDir() + "/users_r";
+printfd(__FILE__, "Monitor=%d file USERS %s\n", us->settings->GetMonitoring(), monFile.c_str());
+
+us->isRunning = true;
+while (us->nonstop)
+    {
+    //printfd(__FILE__,"New Minute. old = %02d current = %02d\n", min, t->tm_min);
+    //printfd(__FILE__,"New Day.    old = %2d current = %2d\n", day, t->tm_mday);
+
+    for_each(us->users.begin(), us->users.end(), mem_fun_ref(&USER::Run));
+
+    tt = stgTime;
+    t = localtime(&tt);
+
+    if (min != t->tm_min)
+        {
+        printfd(__FILE__,"Sec = %d\n", stgTime);
+        printfd(__FILE__,"New Minute. old = %d current = %d\n", min, t->tm_min);
+        min = t->tm_min;
+
+        us->NewMinute(t);
+        }
+
+    t = localtime(&tt);
+    if (day != t->tm_mday)
+        {
+        printfd(__FILE__,"Sec = %d\n", stgTime);
+        printfd(__FILE__,"New Day. old = %d current = %d\n", day, t->tm_mday);
+        day = t->tm_mday;
+        us->NewDay(t);
+        }
+
+    if (us->settings->GetMonitoring() && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
+        {
+        //printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", tc->monitoring, monFile.c_str());
+        touchTime = stgTime;
+        TouchFile(monFile.c_str());
+        }
+
+    stgUsleep(100000);
+    } //while (us->nonstop)
+
+user_iter ui = us->users.begin();
+while (ui != us->users.end())
+    {
+    us->UnSetUserNotifiers(ui);
+    us->DelUserFromIndexes(ui);
+    ui++;
+    }
+
+list<USER_TO_DEL>::iterator iter;
+iter = us->usersToDelete.begin();
+while (iter != us->usersToDelete.end())
+    {
+    iter->delTime -= 2 * userDeleteDelayTime;
+    ++iter;
+    }
+us->RealDelUser();
+
+us->isRunning = false;
+
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void USERS::NewMinute(const struct tm * t)
+{
+int usersCnt = 0;
+list<USER>::iterator usr;
+
+//Write traff, reset session traff. Fake disconnect-connect
+if (t->tm_hour == 23 && t->tm_min == 59)
+    {
+    printfd(__FILE__,"MidnightResetSessionStat\n");
+    for_each(users.begin(), users.end(), mem_fun_ref(&USER::MidnightResetSessionStat));
+    }
+
+if (TimeToWriteDetailStat(t))
+    {
+    //printfd(__FILE__, "USER::WriteInetStat\n");
+    for_each(users.begin(), users.end(), mem_fun_ref(&USER::SwapDetailStat));
+    usersCnt = 0;
+
+    // ðÉÛÅÍ ÀÚÅÒÏ× ÞÁÓÔÑÍÉ. ÷ ÐÅÒÅÒÙ×ÁÈ ×ÙÚÙ×ÁÅÍ USER::Run
+    usr = users.begin();
+    while (usr != users.end())
+        {
+        usersCnt++;
+        usr->WriteDetailStat();
+        usr++;
+        if (usersCnt % 10 == 0)
+            for_each(users.begin(), users.end(), mem_fun_ref(&USER::Run));
+        }
+
+    for_each(users.begin(), users.end(), mem_fun_ref(&USER::ResetDetailStat));
+    }
+
+RealDelUser();
+}
+//-----------------------------------------------------------------------------
+void USERS::NewDay(const struct tm * t)
+{
+struct tm * t1;
+time_t tt = stgTime;
+t1 = localtime(&tt);
+int dayFee = settings->GetDayFee();
+
+if (dayFee == 0)
+    dayFee = DaysInCurrentMonth();
+
+printfd(__FILE__, "DayFee = %d\n", dayFee);
+printfd(__FILE__, "Today = %d DayResetTraff = %d\n", t1->tm_mday, settings->GetDayResetTraff());
+printfd(__FILE__, "DayFeeIsLastDay = %d\n", settings->GetDayFeeIsLastDay());
+
+if (!settings->GetDayFeeIsLastDay())
+    {
+    printfd(__FILE__, "DayResetTraff - 1 -\n");
+    DayResetTraff(t1);
+    //printfd(__FILE__, "DayResetTraff - 1 - 1 -\n");
+    }
+
+if (settings->GetSpreadFee())
+    {
+    printfd(__FILE__, "Spread DayFee\n");
+    for_each(users.begin(), users.end(), mem_fun_ref(&USER::ProcessDayFeeSpread));
+    }
+else
+    {
+    if (t->tm_mday == dayFee)
+        {
+        printfd(__FILE__, "DayFee\n");
+        for_each(users.begin(), users.end(), mem_fun_ref(&USER::ProcessDayFee));
+        }
+    }
+
+if (settings->GetDayFeeIsLastDay())
+    {
+    printfd(__FILE__, "DayResetTraff - 2 -\n");
+    DayResetTraff(t1);
+    }
+}
+//-----------------------------------------------------------------------------
+void USERS::DayResetTraff(const struct tm * t1)
+{
+int dayResetTraff = settings->GetDayResetTraff();
+if (dayResetTraff == 0)
+    dayResetTraff = DaysInCurrentMonth();
+if (t1->tm_mday == dayResetTraff)
+    {
+    printfd(__FILE__, "ResetTraff\n");
+    for_each(users.begin(), users.end(), mem_fun_ref(&USER::ProcessNewMonth));
+    for_each(users.begin(), users.end(), mem_fun_ref(&USER::SetPrepaidTraff));
+    }
+}
+//-----------------------------------------------------------------------------
+int USERS::Start()
+{
+if (ReadUsers())
+    {
+    WriteServLog("USERS: Error: Cannot read users!");
+    return -1;
+    }
+
+nonstop = true;
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    WriteServLog("USERS: Error: Cannot start thread!");
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USERS::Stop()
+{
+printfd(__FILE__, "USERS::Stop()\n");
+
+if (!isRunning)
+    {
+    //printfd(__FILE__, "Alredy stopped\n");
+    return 0;
+    }
+
+nonstop = false;
+
+//5 seconds to thread stops itself
+unsigned i;
+for (i = 0; i < 25 * (users.size() / 50 + 1); i++)
+    {
+    if (!isRunning)
+        break;
+
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now kill it
+if (isRunning)
+    {
+    printfd(__FILE__, "kill USERS thread.\n");
+    //TODO pthread_cancel()
+    if (pthread_kill(thread, SIGINT))
+        {
+        //errorStr = "Cannot kill USERS thread.";
+        //printfd(__FILE__, "Cannot kill USERS thread.\n");
+        //return 0;
+        }
+    printfd(__FILE__, "USERS killed\n");
+    }
+
+printfd(__FILE__, "Before USERS::Run()\n");
+for_each(users.begin(), users.end(), mem_fun_ref(&USER::Run));
+for_each(users.begin(), users.end(), mem_fun_ref(&USER::SwapDetailStat));
+for_each(users.begin(), users.end(), mem_fun_ref(&USER::WriteDetailStat));
+for_each(users.begin(), users.end(), mem_fun_ref(&USER::WriteStat));
+for_each(users.begin(), users.end(), mem_fun_ref(&USER::WriteConf));
+
+printfd(__FILE__, "USERS::Stop()\n");
+return 0;
+}
+//-----------------------------------------------------------------------------
+void USERS::RealDelUser()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+printfd(__FILE__, "RealDelUser() users to del: %d\n", usersToDelete.size());
+
+list<USER_TO_DEL>::iterator iter;
+iter = usersToDelete.begin();
+while (iter != usersToDelete.end())
+    {
+    printfd(__FILE__, "RealDelUser() user=%s\n", iter->iter->GetLogin().c_str());
+    if (iter->delTime + userDeleteDelayTime < stgTime)
+        {
+        printfd(__FILE__, "RealDelUser() user=%s removed from DB\n", iter->iter->GetLogin().c_str());
+        if (store->DelUser(iter->iter->GetLogin()))
+            {
+            WriteServLog("Error removing user \'%s\' from database.", iter->iter->GetLogin().c_str());
+            }
+        users.erase(iter->iter);
+        usersToDelete.erase(iter++);
+        }
+    else
+        {
+        ++iter;
+        }
+    }
+return;
+}
+//-----------------------------------------------------------------------------
+int USERS::GetUserNum()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+return users.size();
+}
+//-----------------------------------------------------------------------------
+void USERS::AddToIPIdx(user_iter user)
+{
+printfd(__FILE__, "USERS: Add IP Idx\n");
+uint32_t ip = user->GetCurrIP();
+//assert(ip && "User has non-null ip");
+if (!ip)
+    return; // User has disconnected
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+const map<uint32_t, user_iter>::iterator it(
+        ipIndex.lower_bound(ip)
+);
+
+assert((it == ipIndex.end() || it->first != ip) && "User is not in index");
+
+ipIndex.insert(it, std::make_pair(ip, user));
+}
+//-----------------------------------------------------------------------------
+void USERS::DelFromIPIdx(uint32_t ip)
+{
+printfd(__FILE__, "USERS: Del IP Idx\n");
+assert(ip && "User has non-null ip");
+
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+const map<uint32_t, user_iter>::iterator it(
+        ipIndex.find(ip)
+);
+
+//assert(it != ipIndex.end() && "User is in index");
+if (it == ipIndex.end())
+    return; // User has not been added
+
+ipIndex.erase(it);
+}
+//-----------------------------------------------------------------------------
+int USERS::FindByIPIdx(uint32_t ip, user_iter * usr)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+map<uint32_t, user_iter>::iterator it;
+it = ipIndex.find(ip);
+
+if (it == ipIndex.end())
+    {
+    //printfd(__FILE__, "User NOT found in IP_Index!!!\n");
+    return -1;
+    }
+*usr = it->second;
+//printfd(__FILE__, "User found in IP_Index\n");
+return 0;
+}
+//-----------------------------------------------------------------------------
+void USERS::AddNotifierUserAdd(NOTIFIER_BASE<user_iter> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+onAddNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+void USERS::DelNotifierUserAdd(NOTIFIER_BASE<user_iter> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+//printfd(__FILE__, "DelNotifierUserAdd\n");
+onAddNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+void USERS::AddNotifierUserDel(NOTIFIER_BASE<user_iter> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+onDelNotifiers.insert(n);
+}
+//-----------------------------------------------------------------------------
+void USERS::DelNotifierUserDel(NOTIFIER_BASE<user_iter> * n)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+onDelNotifiers.erase(n);
+}
+//-----------------------------------------------------------------------------
+int USERS::OpenSearch()
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+handle++;
+searchDescriptors[handle] = users.begin();
+return handle;
+}
+//-----------------------------------------------------------------------------
+int USERS::SearchNext(int h, user_iter * u)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+if (searchDescriptors.find(h) == searchDescriptors.end())
+    {
+    WriteServLog("USERS. Incorrect search handle.");
+    return -1;
+    }
+
+if (searchDescriptors[h] == users.end())
+    return -1;
+
+while (searchDescriptors[h]->GetDeleted())
+    {
+    ++searchDescriptors[h];
+    if (searchDescriptors[h] == users.end())
+        {
+        return -1;
+        }
+    }
+
+*u = searchDescriptors[h];
+
+++searchDescriptors[h];
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int USERS::CloseSearch(int h)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (searchDescriptors.find(h) != searchDescriptors.end())
+    {
+    searchDescriptors.erase(searchDescriptors.find(h));
+    return 0;
+    }
+
+WriteServLog("USERS. Incorrect search handle.");
+return -1;
+}
+//-----------------------------------------------------------------------------
+void USERS::SetUserNotifiers(user_iter user)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+PROPERTY_NOTIFER_IP_BEFORE nb(*this, user);
+PROPERTY_NOTIFER_IP_AFTER  na(*this, user);
+
+userIPNotifiersBefore.push_front(nb);
+userIPNotifiersAfter.push_front(na);
+
+user->AddCurrIPBeforeNotifier(&(*userIPNotifiersBefore.begin()));
+user->AddCurrIPAfterNotifier(&(*userIPNotifiersAfter.begin()));
+}
+//-----------------------------------------------------------------------------
+void USERS::UnSetUserNotifiers(user_iter user)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+list<PROPERTY_NOTIFER_IP_BEFORE>::iterator  bi;
+list<PROPERTY_NOTIFER_IP_AFTER>::iterator   ai;
+
+bi = userIPNotifiersBefore.begin();
+while (bi != userIPNotifiersBefore.end())
+    {
+    if (bi->GetUser() == user)
+        {
+        bi->GetUser()->DelCurrIPBeforeNotifier(&(*bi));
+        userIPNotifiersBefore.erase(bi);
+        //printfd(__FILE__, "Notifier Before removed. User %s\n", bi->GetUser()->GetLogin().c_str());
+        break;
+        }
+    bi++;
+    }
+
+ai = userIPNotifiersAfter.begin();
+while (ai != userIPNotifiersAfter.end())
+    {
+    if (ai->GetUser() == user)
+        {
+        ai->GetUser()->DelCurrIPAfterNotifier(&(*ai));
+        userIPNotifiersAfter.erase(ai);
+        //printfd(__FILE__, "Notifier After removed. User %s\n", ai->GetUser()->GetLogin().c_str());
+        break;
+        }
+    ai++;
+    }
+}
+//-----------------------------------------------------------------------------
+void USERS::AddUserIntoIndexes(user_iter user)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+loginIndex.insert(pair<string, user_iter>(user->GetLogin(), user));
+}
+//-----------------------------------------------------------------------------
+void USERS::DelUserFromIndexes(user_iter user)
+{
+STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+loginIndex.erase(user->GetLogin());
+}
+//-----------------------------------------------------------------------------
+bool USERS::TimeToWriteDetailStat(const struct tm * t)
+{
+int statTime = settings->GetDetailStatWritePeriod();
+
+switch (statTime)
+    {
+    case dsPeriod_1:
+        if (t->tm_min == 0)
+            return true;
+        break;
+    case dsPeriod_1_2:
+        if (t->tm_min % 30 == 0)
+            return true;
+        break;
+    case dsPeriod_1_4:
+        if (t->tm_min % 15 == 0)
+            return true;
+        break;
+    case dsPeriod_1_6:
+        if (t->tm_min % 10 == 0)
+            return true;
+        break;
+    }
+return false;
+}
+//-----------------------------------------------------------------------------
+/*int USERS::SendMessage(const string & login,
+                       time_t sndTtime,
+                       time_t showTime,
+                       char type,
+                       const string & text) const
+{
+return 0;
+}*/
+//-----------------------------------------------------------------------------
+
+
+
diff --git a/projects/stargazer/users.h b/projects/stargazer/users.h
new file mode 100644 (file)
index 0000000..e882dcc
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+$Revision: 1.31 $
+$Date: 2010/10/07 20:04:48 $
+$Author: faust $
+*/
+
+
+#ifndef USERS_H
+#define USERS_H
+
+#include <pthread.h>
+#include <ctime>
+#include <string>
+#include <map>
+#include <list>
+#include <set>
+
+#include "os_int.h"
+
+#include "settings.h"
+#include "user.h"
+#include "tariffs.h"
+#include "stg_logger.h"
+#include "notifer.h"
+#include "actions.h"
+#include "noncopyable.h"
+#include "eventloop.h"
+
+const int userDeleteDelayTime = 120;
+
+using namespace std;
+class USERS;
+//-----------------------------------------------------------------------------
+class PROPERTY_NOTIFER_IP_BEFORE: public PROPERTY_NOTIFIER_BASE<uint32_t>
+{
+public:
+    PROPERTY_NOTIFER_IP_BEFORE(USERS & us, user_iter u) : users(us), user(u) {};
+    void        Notify(const uint32_t & oldValue, const uint32_t & newValue);
+    user_iter   GetUser() { return user; };
+private:
+    USERS &     users;
+    user_iter   user;
+};
+//-----------------------------------------------------------------------------
+class PROPERTY_NOTIFER_IP_AFTER: public PROPERTY_NOTIFIER_BASE<uint32_t>
+{
+public:
+    PROPERTY_NOTIFER_IP_AFTER(USERS & us, user_iter u) : users(us), user(u) {};
+    void        Notify(const uint32_t & oldValue, const uint32_t & newValue);
+    user_iter   GetUser() { return user; };
+private:
+    USERS &     users;
+    user_iter   user;
+};
+//-----------------------------------------------------------------------------
+struct USER_TO_DEL
+{
+USER_TO_DEL()
+    : iter(),
+      delTime(0)
+{};
+
+list<USER>::iterator iter;
+time_t  delTime;
+};
+//-----------------------------------------------------------------------------
+class USERS : private NONCOPYABLE
+    {
+    friend class PROPERTY_NOTIFER_IP_BEFORE;
+    friend class PROPERTY_NOTIFER_IP_AFTER;
+
+public:
+    USERS(SETTINGS * s, BASE_STORE * store, TARIFFS * tariffs, const ADMIN & sysAdmin);
+    ~USERS();
+
+    int             FindByName(const string & login, user_iter * user) const;
+    int             FindByID(int id, user_iter * user);
+
+    bool            TariffInUse(const string & tariffName);
+
+    void            AddNotifierUserAdd(NOTIFIER_BASE<user_iter> *);
+    void            DelNotifierUserAdd(NOTIFIER_BASE<user_iter> *);
+
+    void            AddNotifierUserDel(NOTIFIER_BASE<user_iter> *);
+    void            DelNotifierUserDel(NOTIFIER_BASE<user_iter> *);
+
+    int             Add(const string & login, const ADMIN & admin);
+    void            Del(const string & login, const ADMIN & admin);
+
+    int             ReadUsers();
+    int             GetUserNum();
+
+    int             FindByIPIdx(uint32_t ip, user_iter * user);
+
+    int             OpenSearch();
+    int             SearchNext(int handler, user_iter * u);
+    int             CloseSearch(int handler);
+
+    int             Start();
+    int             Stop();
+
+    int             SendMessage(const string & login, time_t sndTtime, time_t showTime, char type, const string & text) const;
+
+private:
+    void            AddToIPIdx(user_iter);
+    void            DelFromIPIdx(uint32_t ip);
+
+    int             FindByNameNonLock(const string & login, user_iter * user) const;
+    int             FindByIDNonLock(int id, user_iter * user);
+
+    void            RealDelUser();
+    void            ProcessActions();
+
+    void            SetUserNotifiers(user_iter user);
+    void            UnSetUserNotifiers(user_iter user);
+
+    void            AddUserIntoIndexes(user_iter user);
+    void            DelUserFromIndexes(user_iter user);
+
+    static void *   Run(void *);
+    void            NewMinute(const struct tm * t);
+    void            NewDay(const struct tm * t);
+    void            DayResetTraff(const struct tm * t);
+
+    bool            TimeToWriteDetailStat(const struct tm * t);
+
+    list<USER>          users;
+    list<USER_TO_DEL>   usersToDelete;
+    list<PROPERTY_NOTIFER_IP_BEFORE> userIPNotifiersBefore;
+    list<PROPERTY_NOTIFER_IP_AFTER>  userIPNotifiersAfter;
+
+    map<uint32_t, user_iter> ipIndex;
+    map<string,   user_iter> loginIndex;
+
+    SETTINGS *          settings;
+    TARIFFS *           tariffs;
+    BASE_STORE *        store;
+    const ADMIN         sysAdmin;
+    STG_LOGGER &        WriteServLog;
+
+    bool                nonstop;
+    bool                isRunning;
+
+    mutable pthread_mutex_t mutex;
+    pthread_t               thread;
+    mutable unsigned int    handle;
+
+    mutable map<int, user_iter> searchDescriptors;
+
+    set <NOTIFIER_BASE<user_iter>*> onAddNotifiers;
+    set <NOTIFIER_BASE<user_iter>*> onDelNotifiers;
+    };
+//-----------------------------------------------------------------------------
+inline
+void PROPERTY_NOTIFER_IP_BEFORE::Notify(const uint32_t & oldValue,
+                                        const uint32_t &)
+{
+if (!oldValue)
+    return;
+
+//EVENT_LOOP_SINGLETON::GetInstance().Enqueue(users, &USERS::DelFromIPIdx, oldValue);
+// Using explicit call to assure that index is valid, because fast reconnect with delayed call can result in authorization error
+users.DelFromIPIdx(oldValue);
+}
+//-----------------------------------------------------------------------------
+inline
+void PROPERTY_NOTIFER_IP_AFTER::Notify(const uint32_t &,
+                                       const uint32_t & newValue)
+{
+if (!newValue)
+    return;
+
+//EVENT_LOOP_SINGLETON::GetInstance().Enqueue(users, &USERS::AddToIPIdx, user);
+// Using explicit call to assure that index is valid, because fast reconnect with delayed call can result in authorization error
+users.AddToIPIdx(user);
+}
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/projects/traffcounter/Makefile b/projects/traffcounter/Makefile
new file mode 100644 (file)
index 0000000..09abeb7
--- /dev/null
@@ -0,0 +1,48 @@
+include make.conf
+
+CFLAGS += -g3 -W -Wall -pedantic
+CFLAGS += $(DEFINES) -D_BSD_SOURCE
+
+CXXFLAGS += $(CFLAGS)
+
+SOURCES=logger.cpp lock.cpp traffcounter.cpp rules.cpp utils.cpp
+RULES_TESTER_SOURCES=logger.cpp rules.cpp utils.cpp rules_tester.cpp
+RULES_FINDER_TESTER_SOURCES=logger.cpp lock.cpp rules.cpp rules_finder.cpp utils.cpp rf_tester.cpp
+TC_TESTER_SOURCES=logger.cpp rules.cpp rules_finder.cpp utils.cpp traffcounter.cpp lock.cpp tc_tester.cpp
+LIBS=-lpthread
+PROG=st_core
+
+.PHONY: all tests clean
+
+#all: $(PROG)
+all: tests
+
+$(PROG): $(subst .cpp,.o,$(SOURCES))
+       $(CXX) $^ $(LDFLAGS) $(LIBS) -o $@
+
+tests: rules_tester rf_tester tc_tester
+
+rules_tester: $(subst .cpp,.o,$(RULES_TESTER_SOURCES))
+       $(CXX) $^ $(LDFLAGS) -o $@
+
+rf_tester: $(subst .cpp,.o,$(RULES_FINDER_TESTER_SOURCES))
+       $(CXX) $^ $(LDFLAGS) -o $@
+
+tc_tester: $(subst .cpp,.o,$(TC_TESTER_SOURCES))
+       $(CXX) $^ $(LDFLAGS) $(LIBS) -o $@
+
+clean:
+       rm -f $(PROG) *.o *d rules_tester rf_tester tc_tester gmon.out
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+endif
+
+%.d: %.cpp
+       @$(CC) -MM $(CFLAGS) $< > $@.$$$$; \
+           sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+           rm -f $@.$$$$
diff --git a/projects/traffcounter/capturer_tc_iface.h b/projects/traffcounter/capturer_tc_iface.h
new file mode 100644 (file)
index 0000000..0b51dfc
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __CAPTURER_TC_IFACE_H__
+#define __CAPTURER_TC_IFACE_H__
+
+#ifdef HAVE_STDINT
+    #include <stdint.h>
+#else
+    #ifdef HAVE_INTTYPES
+        #include <inttypes.h>
+    #else
+        #error "You need either stdint.h or inttypes.h to compile this!"
+    #endif
+#endif
+
+namespace STG
+{
+
+    class ICAPTURER_TC
+    {
+    public:
+        virtual ~ICAPTURER_TC() {};
+        virtual void AddPacket(const iphdr &, uint16_t, uint16_t) = 0;
+    };
+
+}
+
+#endif
diff --git a/projects/traffcounter/configure b/projects/traffcounter/configure
new file mode 100755 (executable)
index 0000000..ab7d3f2
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+echo -n "checking os type... "
+OS=`uname`
+echo $OS
+
+echo -n "checking stdint.h... "
+if [ -f /usr/include/stdint.h ]
+then
+    DEFINES="$DEFINES -DHAVE_STDINT"
+    echo "ok"
+else
+    echo "fail"
+
+    echo -n "checking inttypes.h... "
+    if [ -f /usr/include/inttypes.h ]
+    then
+       DEFINES="$DEFINES -DHAVE_INTTYPES"
+       echo "ok"
+    else
+       echo "fail"
+       echo "You need either stdint.h or inttypes.h to compile this"
+       exit 1
+    fi
+fi
+
+if [ "$OS"=="Linux" ]
+then
+    DEFINES="$DEFINES -DLINUX"
+    echo -n "checking gmake... "
+    gmake --version > /dev/null 2> /dev/null
+    if [ $? -eq 0 ]
+    then
+       MAKE="gmake"
+       echo "ok"
+    else
+       echo "fail"
+       echo -n "checking make... "
+       make --version > /dev/null 2> /dev/null
+       if [ $? -eq 0 ]
+       then
+           echo "ok"
+           MAKE="make"
+       else
+           echo "fail"
+           echo "You need a GNU Make to compile this"
+           exit 1
+       fi
+    fi
+else
+    if [ "$OS"=="FreeBSD" ]
+    then
+       DEFINES="$DEFINES -DFREEBSD"
+       echo -n "checking gmake... "
+       gmake --version > /dev/null 2> /dev/null
+       if [ $? -eq 0 ]
+       then
+           echo "ok"
+           MAKE="gmake"
+       else
+           echo "fail"
+           echo "You need a GNU Make to use this"
+           exit 1
+       fi
+    else
+       echo "This version of software is only compatible with Linux and FreeBSD"
+       exit 1
+    fi
+fi
+
+echo "Configuration successfull. Details:"
+echo -e "\tOS: $OS"
+echo -e "\tGNU Make utility: $MAKE"
+echo -e "\nType $MAKE and $MAKE install now"
+
+rm -f make.conf
+echo "OS = $OS" >> make.conf
+echo "DEFINES = $DEFINES" >> make.conf
diff --git a/projects/traffcounter/lock.cpp b/projects/traffcounter/lock.cpp
new file mode 100644 (file)
index 0000000..5a16671
--- /dev/null
@@ -0,0 +1,17 @@
+#include <cerrno>
+
+#include <pthread.h>
+
+#include "lock.h"
+
+
+SCOPED_LOCK::SCOPED_LOCK(pthread_mutex_t & mtx)
+    : mutex(mtx)
+{
+pthread_mutex_lock(&mutex);
+}
+
+SCOPED_LOCK::~SCOPED_LOCK()
+{
+pthread_mutex_unlock(&mutex);
+}
diff --git a/projects/traffcounter/lock.h b/projects/traffcounter/lock.h
new file mode 100644 (file)
index 0000000..4a89c29
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __SCOPED_LOCK_H__
+#define __SCOPED_LOCK_H__
+
+#include <pthread.h>
+
+class SCOPED_LOCK
+{
+public:
+    SCOPED_LOCK(pthread_mutex_t & mtx);
+    ~SCOPED_LOCK();
+private:
+    pthread_mutex_t & mutex;
+
+    SCOPED_LOCK(const SCOPED_LOCK & lock) : mutex(lock.mutex) {};
+};
+
+#endif
diff --git a/projects/traffcounter/logger.cpp b/projects/traffcounter/logger.cpp
new file mode 100644 (file)
index 0000000..0352d05
--- /dev/null
@@ -0,0 +1,31 @@
+#include <string>
+#include <sstream>
+
+#include <ctime>
+
+#include "logger.h"
+
+using namespace std;
+
+STGLogger::~STGLogger()
+{
+}
+
+ostream & STGLogger::operator <<(const string & val)
+{
+    LogDate();
+    out << " " << val;
+    return out;
+}
+
+void STGLogger::LogDate()
+{
+    time_t t(time(NULL));
+    struct tm * tt = localtime(&t);
+    out << "[" << tt->tm_year + 1900 << "-";
+    out << (tt->tm_mon + 1 < 10 ? "0" : "") << tt->tm_mon + 1 << "-";
+    out << (tt->tm_mday < 10 ? "0" : "") << tt->tm_mday << " ";
+    out << (tt->tm_hour < 10 ? "0" : "") << tt->tm_hour << ":";
+    out << (tt->tm_min < 10 ? "0" : "") << tt->tm_min << ":";
+    out << (tt->tm_sec < 10 ? "0" : "") << tt->tm_sec << "]";
+}
diff --git a/projects/traffcounter/logger.h b/projects/traffcounter/logger.h
new file mode 100644 (file)
index 0000000..85c17be
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __LOGGER_H__
+#define __LOGGER_H__
+
+#include <iostream>
+#include <string>
+
+#define LOG_IT (log << __FILE__ << ":" << __LINE__ << " ")
+
+class STGLogger {
+public:
+    STGLogger() : out(std::cout) {};
+    STGLogger(std::ostream & stream) : out(stream) {};
+    ~STGLogger();
+
+    std::ostream &operator <<(const std::string & val);
+private:
+    void LogDate();
+    std::ostream & out;
+};
+
+extern STGLogger log;
+
+#endif
diff --git a/projects/traffcounter/rf_tester.cpp b/projects/traffcounter/rf_tester.cpp
new file mode 100644 (file)
index 0000000..6e20a24
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *  Network:
+ *   - server: 192.168.0.1
+ *   - user A: 192.168.0.2
+ *   - user B: 192.168.0.3
+ *
+ *  External resources:
+ *   - host 1: 216.239.59.104
+ *   - host 2: 72.14.221.104
+ *   - host 3: 66.249.93.104
+ *   - host 4: 195.5.61.68
+ *   
+ *  Directions:
+ *   - Local: ALL 192.168.0.0/24
+ *   - DNS: TCP_UDP 195.5.61.68/32:53
+ *   - FTP: TCP 129.22.8.159/32:20-21
+ *   - World: ALL 0.0.0.0/0
+ *
+ */
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include <arpa/inet.h>
+
+#include "rules.h"
+#include "rules_finder.h"
+#include "logger.h"
+
+using namespace std;
+using namespace STG;
+
+STGLogger log;
+
+RULE MakeRule(const std::string & ip,
+              const std::string & mask,
+              uint16_t port1,
+              uint16_t port2,
+              int proto,
+              int dir)
+{
+    RULE rule;
+
+    rule.ip = inet_addr(ip.c_str());
+    rule.mask = inet_addr(mask.c_str());
+    rule.port1 = port1;
+    rule.port2 = port2;
+    rule.proto = proto;
+    rule.dir = dir;
+
+    return rule;
+}
+
+RULES PrepareRules()
+{
+    RULES rules;
+    RULE local(MakeRule("192.168.0.0",
+                        "255.255.255.0",
+                        0,
+                        65535,
+                        -1,
+                        0));
+    RULE dns(MakeRule("195.5.61.68",
+                      "255.255.255.255",
+                      53,
+                      53,
+                      -1,
+                      1));
+    RULE ftp(MakeRule("129.22.8.159",
+                      "255.255.255.255",
+                      20,
+                      21,
+                      -1,
+                      2));
+    RULE world(MakeRule("0.0.0.0",
+                        "0.0.0.0",
+                        0,
+                        65535,
+                        -1,
+                        3));
+
+    rules.push_back(local);
+
+    rules.push_back(dns);
+
+    rules.push_back(ftp);
+
+    rules.push_back(world);
+
+    return rules;
+}
+
+PENDING_PACKET MakePacket(const std::string & from,
+                          const std::string & to,
+                          uint16_t sport,
+                          uint16_t dport,
+                          int proto,
+                          PENDING_PACKET::DIRECTION direction,
+                          int length)
+{
+    iphdr hdr;
+
+    hdr.ihl = 5;
+    hdr.version = 4;
+    hdr.tos = 0;
+    hdr.tot_len = length;
+    hdr.id = 0;
+    hdr.frag_off = 50;
+    hdr.ttl = 64;
+    hdr.protocol = proto;
+    hdr.check = 0;
+    hdr.saddr = inet_addr(from.c_str());
+    hdr.daddr = inet_addr(to.c_str());
+
+    PENDING_PACKET packet(hdr, sport, dport);
+
+    packet.direction = direction;
+
+    return packet;
+}
+
+struct TEST_INFO {
+    int  wantedDir;
+    int  actualDir; // Parser error status
+    bool stdException; // Parser throws an std execption
+    bool otherException; // Parser throws another exception
+    bool result;
+};
+
+struct RF_TESTER : public std::unary_function<std::pair<PENDING_PACKET, int>, void>
+{
+public:
+    RF_TESTER(RULES_FINDER & r)
+        : rf(r),
+          testLog(),
+          result(true)
+        {
+        };
+    ~RF_TESTER()
+        {
+        PrintLog();
+        if (result)
+            exit(EXIT_SUCCESS);
+        exit(EXIT_FAILURE);
+        }
+    void operator()(const std::pair<PENDING_PACKET, int> & entry)
+        {
+        TEST_INFO info;
+        info.wantedDir = entry.second;
+        info.actualDir = -1;
+        info.stdException = false;
+        info.otherException = false;
+        info.result = true;
+        try
+            {
+            info.actualDir = rf.GetDir(entry.first);
+            }
+        catch (std::exception & ex)
+            {
+            info.stdException = true;
+            info.result = false;
+            }
+        catch (...)
+            {
+            info.otherException = true;
+            info.result = false;
+            }
+        info.result &= (info.actualDir == info.wantedDir);
+        result &= info.result;
+        testLog.push_back(info);
+        };
+
+    void PrintLog()
+        {
+        int testNumber = 1;
+        std::cout << "RF_TESTER results:\n";
+        std::cout << "-----------------------------------------------------------------\n";
+        std::vector<TEST_INFO>::const_iterator it;
+        for (it = testLog.begin(); it != testLog.end(); ++it)
+            {
+            std::cout << "Test no.: " << testNumber++ << "\t"
+                      << "Correct dir: " << it->wantedDir << "\t"
+                      << "Actual dir:" << it->actualDir << "\t"
+                      << "STD exceptions: " << it->stdException << "\t"
+                      << "Other exceptions: " << it->otherException << "\t"
+                      << "Result: " << it->result << "\n";
+            }
+        std::cout << "-----------------------------------------------------------------\n";
+        std::cout << "Final result: " << (result ? "passed" : "failed") << std::endl;
+        }
+
+    bool Result() const { return result; };
+private:
+    RULES_FINDER & rf;
+    std::vector<TEST_INFO> testLog;
+    bool result;
+};
+
+int main()
+{
+    RULES rules(PrepareRules());
+    RULES_FINDER rf;
+
+    rf.SetRules(rules);
+
+    std::list<std::pair<PENDING_PACKET, int> > tests;
+
+    // Local, SSH
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "192.168.0.1", 3214, 22, 6, PENDING_PACKET::OUTGOING, 0), 0));
+    tests.push_back(make_pair(MakePacket("192.168.0.1", "192.168.0.2", 22, 3214, 6, PENDING_PACKET::OUTGOING, 0), 0));
+    // Local, SSH, incorrect direction detection
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "192.168.0.1", 3214, 22, 6, PENDING_PACKET::INCOMING, 0), 0));
+    tests.push_back(make_pair(MakePacket("192.168.0.1", "192.168.0.2", 22, 3214, 6, PENDING_PACKET::INCOMING, 0), 0));
+    // Local, FTP
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "192.168.0.1", 3214, 20, 6, PENDING_PACKET::OUTGOING, 0), 0));
+    tests.push_back(make_pair(MakePacket("192.168.0.1", "192.168.0.2", 21, 3214, 6, PENDING_PACKET::OUTGOING, 0), 0));
+    // Local, DNS
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "192.168.0.1", 3214, 53, 6, PENDING_PACKET::OUTGOING, 0), 0));
+    tests.push_back(make_pair(MakePacket("192.168.0.1", "192.168.0.2", 53, 3214, 6, PENDING_PACKET::OUTGOING, 0), 0));
+    // Known DNS, DNS
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "195.5.61.68", 3210, 53, 6, PENDING_PACKET::OUTGOING, 0), 1));
+    tests.push_back(make_pair(MakePacket("195.5.61.68", "192.168.0.2", 53, 3210, 6, PENDING_PACKET::INCOMING, 0), 1));
+    // Known DNS, invalid ports
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "195.5.61.68", 3210, 54, 6, PENDING_PACKET::OUTGOING, 0), 3));
+    tests.push_back(make_pair(MakePacket("195.5.61.68", "192.168.0.2", 20, 3210, 6, PENDING_PACKET::INCOMING, 0), 3));
+    // Known FTP, FTP
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "129.22.8.159", 3241, 20, 6, PENDING_PACKET::OUTGOING, 0), 2));
+    tests.push_back(make_pair(MakePacket("129.22.8.159", "192.168.0.2", 21, 3241, 6, PENDING_PACKET::INCOMING, 0), 2));
+    // Known FTP, invalid ports
+    tests.push_back(make_pair(MakePacket("192.168.0.2", "129.22.8.159", 3241, 53, 6, PENDING_PACKET::OUTGOING, 0), 3));
+    tests.push_back(make_pair(MakePacket("129.22.8.159", "192.168.0.2", 22, 3241, 6, PENDING_PACKET::INCOMING, 0), 3));
+
+    std::for_each(tests.begin(),
+                 tests.end(),
+                 RF_TESTER(rf));
+
+    return EXIT_SUCCESS;
+}
diff --git a/projects/traffcounter/rules b/projects/traffcounter/rules
new file mode 100644 (file)
index 0000000..ad3cb88
--- /dev/null
@@ -0,0 +1,1427 @@
+ALL 62.16.0.0/19 DIR0   
+ALL 62.64.64.0/18 DIR0
+ALL 62.72.160.0/19 DIR0
+ALL 62.80.160.0/19 DIR0
+ALL 62.149.0.0/19 DIR0
+ALL 62.176.0.0/21 DIR0
+ALL 62.182.80.0/21 DIR0
+ALL 62.182.120.0/21 DIR0
+ALL 62.182.152.0/21 DIR0
+ALL 62.182.160.0/21 DIR0
+ALL 62.205.128.0/19 DIR0
+ALL 62.216.32.0/21 DIR0
+ALL 62.221.32.0/22 DIR0
+ALL 62.221.37.0/24 DIR0
+ALL 62.221.38.0/23 DIR0
+ALL 62.221.40.0/21 DIR0
+ALL 62.221.48.0/20 DIR0
+ALL 62.221.64.0/19 DIR0
+ALL 62.244.0.0/18 DIR0
+ALL 64.18.0.0/20 DIR0
+ALL 64.233.160.0/19 DIR0
+ALL 66.102.0.0/20 DIR0
+ALL 66.249.64.0/19 DIR0
+ALL 72.14.192.0/18 DIR0
+ALL 74.125.0.0/16 DIR0
+ALL 77.47.128.0/17 DIR0
+ALL 77.52.0.0/16 DIR0
+ALL 77.73.88.0/21 DIR0
+ALL 77.75.144.0/21 DIR0
+ALL 77.75.156.0/24 DIR0
+ALL 77.87.32.0/21 DIR0
+ALL 77.87.144.0/20 DIR0
+ALL 77.87.192.0/21 DIR0
+ALL 77.88.0.0/18 DIR0
+ALL 77.88.192.0/18 DIR0
+ALL 77.90.192.0/18 DIR0
+ALL 77.91.128.0/18 DIR0
+ALL 77.93.32.0/20 DIR0
+ALL 77.93.48.0/22 DIR0
+ALL 77.94.160.0/19 DIR0
+ALL 77.95.16.0/21 DIR0
+ALL 77.109.0.0/18 DIR0
+ALL 77.120.32.0/20 DIR0
+ALL 77.120.48.0/22 DIR0
+ALL 77.120.56.0/21 DIR0
+ALL 77.120.64.0/18 DIR0
+ALL 77.120.128.0/18 DIR0
+ALL 77.120.192.0/19 DIR0
+ALL 77.120.224.0/20 DIR0
+ALL 77.120.240.0/22 DIR0
+ALL 77.121.0.0/16 DIR0
+ALL 77.122.0.0/15 DIR0
+ALL 77.222.128.0/19 DIR0
+ALL 77.235.96.0/19 DIR0
+ALL 77.239.160.0/21 DIR0
+ALL 77.239.168.0/24 DIR0
+ALL 77.239.170.0/23 DIR0
+ALL 77.239.172.0/22 DIR0
+ALL 77.239.176.0/20 DIR0
+ALL 77.242.160.0/20 DIR0
+ALL 77.244.32.0/21 DIR0
+ALL 77.244.40.0/22 DIR0
+ALL 77.244.44.0/23 DIR0
+ALL 77.247.16.0/20 DIR0
+ALL 77.247.216.0/21 DIR0
+ALL 78.24.72.0/21 DIR0
+ALL 78.25.0.0/19 DIR0
+ALL 78.25.32.0/20 DIR0
+ALL 78.25.48.0/21 DIR0
+ALL 78.25.58.0/23 DIR0
+ALL 78.25.60.0/22 DIR0
+ALL 78.26.128.0/17 DIR0
+ALL 78.27.128.0/17 DIR0
+ALL 78.30.192.0/18 DIR0
+ALL 78.31.176.0/21 DIR0
+ALL 78.31.232.0/21 DIR0
+ALL 78.31.248.0/21 DIR0
+ALL 78.109.16.0/20 DIR0
+ALL 78.111.16.0/21 DIR0
+ALL 78.111.176.0/20 DIR0
+ALL 78.111.208.0/20 DIR0
+ALL 78.137.0.0/19 DIR0
+ALL 78.137.32.0/24 DIR0
+ALL 78.137.34.0/24 DIR0
+ALL 78.152.160.0/19 DIR0
+ALL 78.154.160.0/19 DIR0
+ALL 78.159.32.0/19 DIR0
+ALL 79.110.16.0/20 DIR0
+ALL 79.110.32.0/19 DIR0
+ALL 79.110.64.0/20 DIR0
+ALL 79.110.96.0/20 DIR0
+ALL 79.110.128.0/18 DIR0
+ALL 79.110.208.0/20 DIR0
+ALL 79.110.224.0/20 DIR0
+ALL 79.124.96.0/21 DIR0
+ALL 79.124.104.0/22 DIR0
+ALL 79.124.108.0/23 DIR0
+ALL 79.124.110.0/24 DIR0
+ALL 79.124.128.0/17 DIR0
+ALL 79.135.192.0/19 DIR0
+ALL 79.140.0.0/20 DIR0
+ALL 79.142.192.0/20 DIR0
+ALL 79.143.32.0/20 DIR0
+ALL 79.171.120.0/21 DIR0
+ALL 79.174.0.0/19 DIR0
+ALL 80.67.208.0/20 DIR0
+ALL 80.70.64.0/20 DIR0
+ALL 80.70.80.0/24 DIR0
+ALL 80.70.82.0/23 DIR0
+ALL 80.73.0.0/20 DIR0
+ALL 80.77.32.0/20 DIR0
+ALL 80.78.32.0/19 DIR0
+ALL 80.84.176.0/20 DIR0
+ALL 80.87.148.0/22 DIR0
+ALL 80.87.152.0/22 DIR0
+ALL 80.90.230.0/23 DIR0
+ALL 80.90.236.0/24 DIR0
+ALL 80.90.238.0/23 DIR0
+ALL 80.91.160.0/19 DIR0
+ALL 80.92.224.0/20 DIR0
+ALL 80.93.112.0/20 DIR0
+ALL 80.94.240.0/20 DIR0
+ALL 80.243.144.0/20 DIR0
+ALL 80.245.112.0/20 DIR0
+ALL 80.249.224.0/20 DIR0
+ALL 80.252.128.0/19 DIR0
+ALL 80.252.240.0/20 DIR0
+ALL 80.254.0.0/20 DIR0
+ALL 80.255.64.0/20 DIR0
+ALL 81.17.128.0/20 DIR0
+ALL 81.21.0.0/20 DIR0
+ALL 81.22.128.0/20 DIR0
+ALL 81.23.16.0/20 DIR0
+ALL 81.24.208.0/20 DIR0
+ALL 81.25.224.0/20 DIR0
+ALL 81.26.144.0/20 DIR0
+ALL 81.30.160.0/20 DIR0
+ALL 81.90.224.0/20 DIR0
+ALL 81.95.176.0/20 DIR0
+ALL 82.144.192.0/19 DIR0
+ALL 82.193.96.0/19 DIR0
+ALL 83.97.104.0/21 DIR0
+ALL 83.137.88.0/21 DIR0
+ALL 83.138.48.0/24 DIR0
+ALL 83.138.51.0/24 DIR0
+ALL 83.138.52.0/22 DIR0
+ALL 83.142.232.0/21 DIR0
+ALL 83.143.232.0/21 DIR0
+ALL 83.170.192.0/18 DIR0
+ALL 83.218.224.0/19 DIR0
+ALL 84.47.128.0/18 DIR0
+ALL 85.90.192.0/19 DIR0
+ALL 85.91.96.0/19 DIR0
+ALL 85.114.192.0/19 DIR0
+ALL 85.117.129.0/24 DIR0
+ALL 85.159.0.0/21 DIR0
+ALL 85.198.128.0/18 DIR0
+ALL 85.202.160.0/20 DIR0
+ALL 85.202.192.0/20 DIR0
+ALL 85.223.128.0/17 DIR0
+ALL 85.238.96.0/19 DIR0
+ALL 86.110.192.0/23 DIR0
+ALL 86.111.224.0/21 DIR0
+ALL 87.238.152.0/23 DIR0
+ALL 87.238.155.0/24 DIR0
+ALL 87.238.157.0/24 DIR0
+ALL 87.238.158.0/23 DIR0
+ALL 87.250.224.0/19 DIR0
+ALL 88.81.224.0/19 DIR0
+ALL 88.84.192.0/19 DIR0
+ALL 88.154.0.0/15 DIR0
+ALL 88.208.8.0/23 DIR0
+ALL 88.214.64.0/18 DIR0
+ALL 89.19.96.0/19 DIR0
+ALL 89.21.64.0/19 DIR0
+ALL 89.28.200.0/21 DIR0
+ALL 89.105.224.0/21 DIR0
+ALL 89.105.236.0/22 DIR0
+ALL 89.105.240.0/20 DIR0
+ALL 89.107.24.0/21 DIR0
+ALL 89.162.128.0/17 DIR0
+ALL 89.185.0.0/19 DIR0
+ALL 89.187.0.0/23 DIR0
+ALL 89.187.3.0/24 DIR0
+ALL 89.187.4.0/24 DIR0
+ALL 89.200.232.0/21 DIR0
+ALL 89.200.248.0/21 DIR0
+ALL 89.207.184.0/21 DIR0
+ALL 89.209.0.0/16 DIR0
+ALL 89.248.238.0/23 DIR0
+ALL 89.251.16.0/21 DIR0
+ALL 89.252.0.0/19 DIR0
+ALL 89.252.32.0/20 DIR0
+ALL 89.252.48.0/21 DIR0
+ALL 89.252.56.0/22 DIR0
+ALL 89.252.60.0/23 DIR0
+ALL 89.252.62.0/24 DIR0
+ALL 91.90.8.0/21 DIR0
+ALL 91.90.16.0/21 DIR0
+ALL 91.103.120.0/21 DIR0
+ALL 91.123.144.0/20 DIR0
+ALL 91.142.160.0/20 DIR0
+ALL 91.145.192.0/18 DIR0
+ALL 91.189.128.0/21 DIR0
+ALL 91.192.4.0/22 DIR0
+ALL 91.192.44.0/22 DIR0
+ALL 91.192.84.0/22 DIR0
+ALL 91.192.128.0/22 DIR0
+ALL 91.192.136.0/22 DIR0
+ALL 91.192.152.0/21 DIR0
+ALL 91.192.160.0/22 DIR0
+ALL 91.192.180.0/22 DIR0
+ALL 91.192.184.0/22 DIR0
+ALL 91.192.216.0/22 DIR0
+ALL 91.193.8.0/22 DIR0
+ALL 91.193.32.0/22 DIR0
+ALL 91.193.68.0/23 DIR0
+ALL 91.193.76.0/22 DIR0
+ALL 91.193.80.0/22 DIR0
+ALL 91.193.104.0/22 DIR0
+ALL 91.193.124.0/22 DIR0
+ALL 91.193.164.0/22 DIR0
+ALL 91.193.172.0/22 DIR0
+ALL 91.193.204.0/22 DIR0
+ALL 91.193.220.0/22 DIR0
+ALL 91.193.232.0/22 DIR0
+ALL 91.193.252.0/22 DIR0
+ALL 91.194.34.0/23 DIR0
+ALL 91.194.50.0/23 DIR0
+ALL 91.194.56.0/23 DIR0
+ALL 91.194.72.0/23 DIR0
+ALL 91.194.78.0/23 DIR0
+ALL 91.194.80.0/23 DIR0
+ALL 91.194.88.0/23 DIR0
+ALL 91.194.124.0/23 DIR0
+ALL 91.194.134.0/23 DIR0
+ALL 91.194.162.0/23 DIR0
+ALL 91.194.238.0/23 DIR0
+ALL 91.194.250.0/23 DIR0
+ALL 91.195.10.0/23 DIR0
+ALL 91.195.12.0/23 DIR0
+ALL 91.195.20.0/23 DIR0
+ALL 91.195.52.0/23 DIR0
+ALL 91.195.68.0/23 DIR0
+ALL 91.195.74.0/23 DIR0
+ALL 91.195.86.0/23 DIR0
+ALL 91.195.90.0/23 DIR0
+ALL 91.195.96.0/23 DIR0
+ALL 91.195.120.0/23 DIR0
+ALL 91.195.156.0/23 DIR0
+ALL 91.195.172.0/23 DIR0
+ALL 91.195.184.0/23 DIR0
+ALL 91.195.214.0/23 DIR0
+ALL 91.195.230.0/23 DIR0
+ALL 91.195.244.0/23 DIR0
+ALL 91.195.248.0/23 DIR0
+ALL 91.196.0.0/22 DIR0
+ALL 91.196.52.0/22 DIR0
+ALL 91.196.60.0/22 DIR0
+ALL 91.196.80.0/22 DIR0
+ALL 91.196.88.0/21 DIR0
+ALL 91.196.96.0/21 DIR0
+ALL 91.196.120.0/22 DIR0
+ALL 91.196.132.0/22 DIR0
+ALL 91.196.148.0/22 DIR0
+ALL 91.196.156.0/22 DIR0
+ALL 91.196.160.0/24 DIR0
+ALL 91.196.164.0/22 DIR0
+ALL 91.196.178.0/24 DIR0
+ALL 91.196.192.0/22 DIR0
+ALL 91.196.196.0/23 DIR0
+ALL 91.196.228.0/22 DIR0
+ALL 91.197.4.0/22 DIR0
+ALL 91.197.16.0/22 DIR0
+ALL 91.197.44.0/22 DIR0
+ALL 91.197.48.0/22 DIR0
+ALL 91.197.56.0/22 DIR0
+ALL 91.197.80.0/22 DIR0
+ALL 91.197.128.0/21 DIR0
+ALL 91.197.144.0/22 DIR0
+ALL 91.197.168.0/22 DIR0
+ALL 91.197.184.0/22 DIR0
+ALL 91.197.216.0/21 DIR0
+ALL 91.197.236.0/22 DIR0
+ALL 91.197.252.0/22 DIR0
+ALL 91.198.1.0/24 DIR0
+ALL 91.198.10.0/24 DIR0
+ALL 91.198.20.0/24 DIR0
+ALL 91.198.34.0/24 DIR0
+ALL 91.198.36.0/24 DIR0
+ALL 91.198.50.0/24 DIR0
+ALL 91.198.83.0/24 DIR0
+ALL 91.198.86.0/24 DIR0
+ALL 91.198.101.0/24 DIR0
+ALL 91.198.116.0/24 DIR0
+ALL 91.198.133.0/24 DIR0
+ALL 91.198.140.0/24 DIR0
+ALL 91.198.143.0/24 DIR0
+ALL 91.198.153.0/24 DIR0
+ALL 91.198.175.0/24 DIR0
+ALL 91.198.188.0/24 DIR0
+ALL 91.198.233.0/24 DIR0
+ALL 91.198.235.0/24 DIR0
+ALL 91.198.249.0/24 DIR0
+ALL 91.199.13.0/24 DIR0
+ALL 91.199.28.0/24 DIR0
+ALL 91.199.33.0/24 DIR0
+ALL 91.199.35.0/24 DIR0
+ALL 91.199.37.0/24 DIR0
+ALL 91.199.54.0/24 DIR0
+ALL 91.199.75.0/24 DIR0
+ALL 91.199.82.0/24 DIR0
+ALL 91.199.91.0/24 DIR0
+ALL 91.199.92.0/23 DIR0
+ALL 91.199.106.0/24 DIR0
+ALL 91.199.115.0/24 DIR0
+ALL 91.199.138.0/23 DIR0
+ALL 91.199.144.0/24 DIR0
+ALL 91.199.182.0/24 DIR0
+ALL 91.199.188.0/24 DIR0
+ALL 91.199.194.0/24 DIR0
+ALL 91.199.206.0/24 DIR0
+ALL 91.199.222.0/24 DIR0
+ALL 91.199.245.0/24 DIR0
+ALL 91.200.0.0/20 DIR0
+ALL 91.200.40.0/23 DIR0
+ALL 91.200.44.0/22 DIR0
+ALL 91.200.52.0/22 DIR0
+ALL 91.200.56.0/22 DIR0
+ALL 91.200.72.0/22 DIR0
+ALL 91.200.104.0/22 DIR0
+ALL 91.200.112.0/22 DIR0
+ALL 91.200.136.0/22 DIR0
+ALL 91.200.160.0/22 DIR0
+ALL 91.200.180.0/22 DIR0
+ALL 91.200.200.0/22 DIR0
+ALL 91.200.212.0/22 DIR0
+ALL 91.200.220.0/22 DIR0
+ALL 91.200.232.0/22 DIR0
+ALL 91.200.244.0/22 DIR0
+ALL 91.200.248.0/21 DIR0
+ALL 91.201.24.0/22 DIR0
+ALL 91.201.36.0/22 DIR0
+ALL 91.201.40.0/22 DIR0
+ALL 91.201.68.0/22 DIR0
+ALL 91.201.84.0/22 DIR0
+ALL 91.201.96.0/22 DIR0
+ALL 91.201.108.0/22 DIR0
+ALL 91.201.124.0/22 DIR0
+ALL 91.201.144.0/22 DIR0
+ALL 91.201.156.0/22 DIR0
+ALL 91.201.168.0/22 DIR0
+ALL 91.201.180.0/22 DIR0
+ALL 91.201.188.0/22 DIR0
+ALL 91.201.196.0/22 DIR0
+ALL 91.201.212.0/22 DIR0
+ALL 91.201.224.0/22 DIR0
+ALL 91.201.232.0/21 DIR0
+ALL 91.201.240.0/21 DIR0
+ALL 91.201.252.0/22 DIR0
+ALL 91.202.0.0/22 DIR0
+ALL 91.202.8.0/22 DIR0
+ALL 91.202.39.0/24 DIR0
+ALL 91.202.52.0/22 DIR0
+ALL 91.202.56.0/22 DIR0
+ALL 91.202.72.0/22 DIR0
+ALL 91.202.104.0/21 DIR0
+ALL 91.202.128.0/21 DIR0
+ALL 91.202.144.0/22 DIR0
+ALL 91.202.160.0/22 DIR0
+ALL 91.202.208.0/21 DIR0
+ALL 91.202.232.0/22 DIR0
+ALL 91.202.240.0/21 DIR0
+ALL 91.203.4.0/22 DIR0
+ALL 91.203.12.0/22 DIR0
+ALL 91.203.24.0/22 DIR0
+ALL 91.203.48.0/22 DIR0
+ALL 91.203.60.0/22 DIR0
+ALL 91.203.76.0/22 DIR0
+ALL 91.203.88.0/21 DIR0
+ALL 91.203.112.0/22 DIR0
+ALL 91.203.136.0/21 DIR0
+ALL 91.203.144.0/22 DIR0
+ALL 91.203.164.0/22 DIR0
+ALL 91.204.36.0/22 DIR0
+ALL 91.204.40.0/21 DIR0
+ALL 91.204.48.0/22 DIR0
+ALL 91.204.60.0/22 DIR0
+ALL 91.204.76.0/22 DIR0
+ALL 91.204.84.0/22 DIR0
+ALL 91.204.92.0/22 DIR0
+ALL 91.204.120.0/22 DIR0
+ALL 91.204.132.0/22 DIR0
+ALL 91.204.180.0/22 DIR0
+ALL 91.204.196.0/22 DIR0
+ALL 91.204.212.0/22 DIR0
+ALL 91.205.16.0/22 DIR0
+ALL 91.205.64.0/22 DIR0
+ALL 91.205.80.0/22 DIR0
+ALL 91.205.108.0/22 DIR0
+ALL 91.205.164.0/22 DIR0
+ALL 91.206.110.0/23 DIR0
+ALL 91.206.186.0/23 DIR0
+ALL 91.206.200.0/23 DIR0
+ALL 91.206.212.0/23 DIR0
+ALL 91.206.218.0/23 DIR0
+ALL 91.206.226.0/23 DIR0
+ALL 91.207.4.0/22 DIR0
+ALL 91.207.8.0/23 DIR0
+ALL 91.207.44.0/22 DIR0
+ALL 91.207.54.0/23 DIR0
+ALL 91.207.60.0/23 DIR0
+ALL 91.207.98.0/23 DIR0
+ALL 91.207.122.0/23 DIR0
+ALL 91.207.146.0/23 DIR0
+ALL 91.207.210.0/23 DIR0
+ALL 91.207.224.0/23 DIR0
+ALL 91.208.25.0/24 DIR0
+ALL 91.208.52.0/24 DIR0
+ALL 91.208.65.0/24 DIR0
+ALL 91.208.97.0/24 DIR0
+ALL 91.208.116.0/24 DIR0
+ALL 91.208.127.0/24 DIR0
+ALL 91.208.153.0/24 DIR0
+ALL 91.208.154.0/24 DIR0
+ALL 91.208.208.0/24 DIR0
+ALL 91.209.11.0/24 DIR0
+ALL 91.209.24.0/24 DIR0
+ALL 91.209.54.0/24 DIR0
+ALL 91.210.8.0/21 DIR0
+ALL 91.210.20.0/22 DIR0
+ALL 91.210.28.0/22 DIR0
+ALL 91.210.32.0/21 DIR0
+ALL 91.210.92.0/22 DIR0
+ALL 91.210.96.0/22 DIR0
+ALL 91.210.120.0/22 DIR0
+ALL 91.210.148.0/22 DIR0
+ALL 92.49.192.0/21 DIR0
+ALL 92.49.208.0/20 DIR0
+ALL 92.49.224.0/19 DIR0
+ALL 92.240.96.0/21 DIR0
+ALL 92.240.104.0/22 DIR0
+ALL 92.240.112.0/21 DIR0
+ALL 92.240.120.0/22 DIR0
+ALL 92.240.124.0/23 DIR0
+ALL 92.240.126.0/24 DIR0
+ALL 92.242.96.0/19 DIR0
+ALL 92.244.96.0/19 DIR0
+ALL 92.249.64.0/18 DIR0
+ALL 93.72.0.0/13 DIR0
+ALL 93.89.208.0/20 DIR0
+ALL 93.126.64.0/18 DIR0
+ALL 93.127.0.0/24 DIR0
+ALL 93.127.6.0/23 DIR0
+ALL 93.127.8.0/21 DIR0
+ALL 93.127.16.0/20 DIR0
+ALL 93.127.32.0/21 DIR0
+ALL 93.127.48.0/21 DIR0
+ALL 93.157.8.0/21 DIR0
+ALL 93.157.24.0/21 DIR0
+ALL 93.158.128.0/18 DIR0
+ALL 93.175.224.0/20 DIR0
+ALL 93.178.192.0/22 DIR0
+ALL 93.178.204.0/23 DIR0
+ALL 93.178.206.0/24 DIR0
+ALL 93.178.210.0/23 DIR0
+ALL 93.180.192.0/18 DIR0
+ALL 93.183.192.0/18 DIR0
+ALL 93.185.192.0/19 DIR0
+ALL 93.188.32.0/21 DIR0
+ALL 93.190.40.0/21 DIR0
+ALL 94.27.0.0/17 DIR0
+ALL 94.74.64.0/18 DIR0
+ALL 94.76.96.0/21 DIR0
+ALL 94.100.208.0/20 DIR0
+ALL 94.124.160.0/21 DIR0
+ALL 94.125.120.0/21 DIR0
+ALL 94.130.0.0/15 DIR0
+ALL 94.153.0.0/16 DIR0
+ALL 94.154.0.0/17 DIR0
+ALL 94.154.128.0/18 DIR0
+ALL 94.158.16.0/20 DIR0
+ALL 94.158.32.0/20 DIR0
+ALL 94.158.64.0/19 DIR0
+ALL 94.158.144.0/20 DIR0
+ALL 94.240.128.0/18 DIR0
+ALL 94.248.0.0/17 DIR0
+ALL 193.0.227.0/24 DIR0
+ALL 193.0.228.0/24 DIR0
+ALL 193.0.240.0/24 DIR0
+ALL 193.0.247.0/24 DIR0
+ALL 193.16.45.0/24 DIR0
+ALL 193.16.47.0/24 DIR0
+ALL 193.16.101.0/24 DIR0
+ALL 193.16.158.0/24 DIR0
+ALL 193.16.233.0/24 DIR0
+ALL 193.16.247.0/24 DIR0
+ALL 193.17.46.0/24 DIR0
+ALL 193.17.69.0/24 DIR0
+ALL 193.17.75.0/24 DIR0
+ALL 193.17.174.0/24 DIR0
+ALL 193.17.208.0/24 DIR0
+ALL 193.17.213.0/24 DIR0
+ALL 193.17.216.0/23 DIR0
+ALL 193.17.253.0/24 DIR0
+ALL 193.19.74.0/23 DIR0
+ALL 193.19.84.0/22 DIR0
+ALL 193.19.100.0/23 DIR0
+ALL 193.19.108.0/22 DIR0
+ALL 193.19.132.0/22 DIR0
+ALL 193.19.144.0/22 DIR0
+ALL 193.19.152.0/23 DIR0
+ALL 193.19.184.0/22 DIR0
+ALL 193.19.228.0/22 DIR0
+ALL 193.19.240.0/21 DIR0
+ALL 193.19.252.0/22 DIR0
+ALL 193.22.84.0/24 DIR0
+ALL 193.22.140.0/24 DIR0
+ALL 193.23.53.0/24 DIR0
+ALL 193.23.60.0/24 DIR0
+ALL 193.23.122.0/24 DIR0
+ALL 193.23.157.0/24 DIR0
+ALL 193.23.181.0/24 DIR0
+ALL 193.23.183.0/24 DIR0
+ALL 193.23.225.0/24 DIR0
+ALL 193.24.25.0/24 DIR0
+ALL 193.24.30.0/24 DIR0
+ALL 193.25.176.0/23 DIR0
+ALL 193.25.255.0/24 DIR0
+ALL 193.26.3.0/24 DIR0
+ALL 193.26.13.0/24 DIR0
+ALL 193.26.20.0/24 DIR0
+ALL 193.26.27.0/24 DIR0
+ALL 193.26.134.0/24 DIR0
+ALL 193.27.0.0/24 DIR0
+ALL 193.27.47.0/24 DIR0
+ALL 193.27.80.0/23 DIR0
+ALL 193.27.234.0/23 DIR0
+ALL 193.27.242.0/23 DIR0
+ALL 193.28.85.0/24 DIR0
+ALL 193.28.87.0/24 DIR0
+ALL 193.28.92.0/24 DIR0
+ALL 193.28.156.0/24 DIR0
+ALL 193.28.177.0/24 DIR0
+ALL 193.28.184.0/24 DIR0
+ALL 193.28.186.0/24 DIR0
+ALL 193.28.190.0/24 DIR0
+ALL 193.28.200.0/24 DIR0
+ALL 193.29.203.0/24 DIR0
+ALL 193.29.204.0/24 DIR0
+ALL 193.29.220.0/24 DIR0
+ALL 193.30.240.0/22 DIR0
+ALL 193.32.21.0/24 DIR0
+ALL 193.33.48.0/23 DIR0
+ALL 193.33.54.0/23 DIR0
+ALL 193.33.64.0/23 DIR0
+ALL 193.33.104.0/23 DIR0
+ALL 193.33.146.0/23 DIR0
+ALL 193.33.172.0/23 DIR0
+ALL 193.33.194.0/23 DIR0
+ALL 193.33.196.0/23 DIR0
+ALL 193.33.202.0/23 DIR0
+ALL 193.33.206.0/23 DIR0
+ALL 193.33.212.0/23 DIR0
+ALL 193.33.236.0/23 DIR0
+ALL 193.34.20.0/22 DIR0
+ALL 193.34.60.0/22 DIR0
+ALL 193.34.72.0/21 DIR0
+ALL 193.34.92.0/22 DIR0
+ALL 193.34.128.0/23 DIR0
+ALL 193.34.140.0/23 DIR0
+ALL 193.34.154.0/23 DIR0
+ALL 193.34.168.0/23 DIR0
+ALL 193.34.172.0/23 DIR0
+ALL 193.35.25.0/24 DIR0
+ALL 193.37.133.0/24 DIR0
+ALL 193.37.141.0/24 DIR0
+ALL 193.37.156.0/24 DIR0
+ALL 193.39.69.0/24 DIR0
+ALL 193.39.72.0/24 DIR0
+ALL 193.39.75.0/24 DIR0
+ALL 193.39.76.0/23 DIR0
+ALL 193.39.114.0/24 DIR0
+ALL 193.39.118.0/24 DIR0
+ALL 193.41.4.0/23 DIR0
+ALL 193.41.38.0/24 DIR0
+ALL 193.41.48.0/23 DIR0
+ALL 193.41.51.0/24 DIR0
+ALL 193.41.60.0/22 DIR0
+ALL 193.41.80.0/24 DIR0
+ALL 193.41.88.0/24 DIR0
+ALL 193.41.128.0/22 DIR0
+ALL 193.41.160.0/22 DIR0
+ALL 193.41.172.0/22 DIR0
+ALL 193.41.184.0/22 DIR0
+ALL 193.41.218.0/23 DIR0
+ALL 193.41.239.0/24 DIR0
+ALL 193.43.95.0/24 DIR0
+ALL 193.43.222.0/23 DIR0
+ALL 193.43.248.0/21 DIR0
+ALL 193.46.46.0/24 DIR0
+ALL 193.46.66.0/24 DIR0
+ALL 193.46.81.0/24 DIR0
+ALL 193.46.86.0/24 DIR0
+ALL 193.46.89.0/24 DIR0
+ALL 193.46.201.0/24 DIR0
+ALL 193.46.210.0/24 DIR0
+ALL 193.47.85.0/24 DIR0
+ALL 193.47.137.0/24 DIR0
+ALL 193.47.145.0/24 DIR0
+ALL 193.47.166.0/24 DIR0
+ALL 193.58.251.0/24 DIR0
+ALL 193.84.17.0/24 DIR0
+ALL 193.84.23.0/24 DIR0
+ALL 193.84.50.0/24 DIR0
+ALL 193.84.72.0/24 DIR0
+ALL 193.84.76.0/23 DIR0
+ALL 193.84.90.0/24 DIR0
+ALL 193.93.12.0/22 DIR0
+ALL 193.93.16.0/22 DIR0
+ALL 193.93.48.0/22 DIR0
+ALL 193.93.76.0/22 DIR0
+ALL 193.93.100.0/22 DIR0
+ALL 193.93.108.0/22 DIR0
+ALL 193.93.116.0/22 DIR0
+ALL 193.93.160.0/22 DIR0
+ALL 193.93.184.0/21 DIR0
+ALL 193.93.192.0/22 DIR0
+ALL 193.93.228.0/22 DIR0
+ALL 193.108.38.0/23 DIR0
+ALL 193.108.46.0/23 DIR0
+ALL 193.108.48.0/22 DIR0
+ALL 193.108.56.0/22 DIR0
+ALL 193.108.102.0/23 DIR0
+ALL 193.108.104.0/23 DIR0
+ALL 193.108.112.0/21 DIR0
+ALL 193.108.120.0/22 DIR0
+ALL 193.108.128.0/22 DIR0
+ALL 193.108.162.0/23 DIR0
+ALL 193.108.170.0/23 DIR0
+ALL 193.108.209.0/24 DIR0
+ALL 193.108.226.0/23 DIR0
+ALL 193.108.236.0/23 DIR0
+ALL 193.108.240.0/22 DIR0
+ALL 193.108.248.0/22 DIR0
+ALL 193.109.8.0/22 DIR0
+ALL 193.109.80.0/24 DIR0
+ALL 193.109.93.0/24 DIR0
+ALL 193.109.100.0/22 DIR0
+ALL 193.109.118.0/24 DIR0
+ALL 193.109.128.0/23 DIR0
+ALL 193.109.144.0/22 DIR0
+ALL 193.109.160.0/21 DIR0
+ALL 193.109.240.0/23 DIR0
+ALL 193.109.248.0/23 DIR0
+ALL 193.110.16.0/21 DIR0
+ALL 193.110.72.0/21 DIR0
+ALL 193.110.89.0/24 DIR0
+ALL 193.110.106.0/23 DIR0
+ALL 193.110.112.0/22 DIR0
+ALL 193.110.124.0/22 DIR0
+ALL 193.110.160.0/22 DIR0
+ALL 193.110.172.0/22 DIR0
+ALL 193.110.176.0/23 DIR0
+ALL 193.110.184.0/23 DIR0
+ALL 193.110.188.0/23 DIR0
+ALL 193.111.6.0/23 DIR0
+ALL 193.111.8.0/23 DIR0
+ALL 193.111.83.0/24 DIR0
+ALL 193.111.114.0/23 DIR0
+ALL 193.111.126.0/23 DIR0
+ALL 193.111.156.0/22 DIR0
+ALL 193.111.173.0/24 DIR0
+ALL 193.111.188.0/22 DIR0
+ALL 193.111.204.0/23 DIR0
+ALL 193.111.239.0/24 DIR0
+ALL 193.111.240.0/22 DIR0
+ALL 193.111.248.0/22 DIR0
+ALL 193.124.48.0/24 DIR0
+ALL 193.124.54.0/24 DIR0
+ALL 193.124.57.0/24 DIR0
+ALL 193.124.59.0/24 DIR0
+ALL 193.124.60.0/23 DIR0
+ALL 193.124.70.0/24 DIR0
+ALL 193.124.76.0/22 DIR0
+ALL 193.124.229.0/24 DIR0
+ALL 193.138.77.0/24 DIR0
+ALL 193.138.84.0/24 DIR0
+ALL 193.138.87.0/24 DIR0
+ALL 193.138.93.0/24 DIR0
+ALL 193.138.114.0/24 DIR0
+ALL 193.138.122.0/24 DIR0
+ALL 193.138.132.0/22 DIR0
+ALL 193.138.144.0/22 DIR0
+ALL 193.138.184.0/22 DIR0
+ALL 193.138.236.0/22 DIR0
+ALL 193.138.244.0/22 DIR0
+ALL 193.142.124.0/24 DIR0
+ALL 193.142.213.0/24 DIR0
+ALL 193.142.218.0/23 DIR0
+ALL 193.142.221.0/24 DIR0
+ALL 193.151.12.0/22 DIR0
+ALL 193.151.56.0/22 DIR0
+ALL 193.151.104.0/22 DIR0
+ALL 193.151.240.0/21 DIR0
+ALL 193.151.252.0/22 DIR0
+ALL 193.164.92.0/22 DIR0
+ALL 193.164.130.0/24 DIR0
+ALL 193.164.149.0/24 DIR0
+ALL 193.178.34.0/24 DIR0
+ALL 193.178.124.0/22 DIR0
+ALL 193.178.144.0/22 DIR0
+ALL 193.178.162.0/24 DIR0
+ALL 193.178.190.0/23 DIR0
+ALL 193.178.228.0/23 DIR0
+ALL 193.178.236.0/23 DIR0
+ALL 193.178.248.0/22 DIR0
+ALL 193.186.9.0/24 DIR0
+ALL 193.186.15.0/24 DIR0
+ALL 193.188.254.0/24 DIR0
+ALL 193.189.96.0/23 DIR0
+ALL 193.189.126.0/23 DIR0
+ALL 193.192.36.0/23 DIR0
+ALL 193.193.192.0/19 DIR0
+ALL 193.200.22.0/24 DIR0
+ALL 193.200.32.0/23 DIR0
+ALL 193.200.36.0/22 DIR0
+ALL 193.200.64.0/23 DIR0
+ALL 193.200.68.0/23 DIR0
+ALL 193.200.84.0/23 DIR0
+ALL 193.200.151.0/24 DIR0
+ALL 193.200.160.0/23 DIR0
+ALL 193.200.173.0/24 DIR0
+ALL 193.200.175.0/24 DIR0
+ALL 193.200.179.0/24 DIR0
+ALL 193.200.183.0/24 DIR0
+ALL 193.200.190.0/24 DIR0
+ALL 193.200.205.0/24 DIR0
+ALL 193.200.209.0/24 DIR0
+ALL 193.200.212.0/24 DIR0
+ALL 193.200.219.0/24 DIR0
+ALL 193.200.229.0/24 DIR0
+ALL 193.200.248.0/24 DIR0
+ALL 193.200.255.0/24 DIR0
+ALL 193.201.60.0/22 DIR0
+ALL 193.201.80.0/22 DIR0
+ALL 193.201.98.0/23 DIR0
+ALL 193.201.100.0/24 DIR0
+ALL 193.201.116.0/23 DIR0
+ALL 193.201.140.0/22 DIR0
+ALL 193.201.175.0/24 DIR0
+ALL 193.201.198.0/23 DIR0
+ALL 193.201.206.0/23 DIR0
+ALL 193.201.208.0/22 DIR0
+ALL 193.201.216.0/22 DIR0
+ALL 193.201.224.0/22 DIR0
+ALL 193.202.21.0/24 DIR0
+ALL 193.202.110.0/24 DIR0
+ALL 193.202.118.0/24 DIR0
+ALL 193.203.110.0/23 DIR0
+ALL 193.203.218.0/23 DIR0
+ALL 193.203.236.0/23 DIR0
+ALL 193.218.144.0/22 DIR0
+ALL 193.219.99.0/24 DIR0
+ALL 193.219.124.0/24 DIR0
+ALL 193.222.111.0/24 DIR0
+ALL 193.222.140.0/24 DIR0
+ALL 193.223.98.0/24 DIR0
+ALL 193.227.97.0/24 DIR0
+ALL 193.227.115.0/24 DIR0
+ALL 193.227.119.0/24 DIR0
+ALL 193.227.120.0/24 DIR0
+ALL 193.227.206.0/23 DIR0
+ALL 193.227.208.0/22 DIR0
+ALL 193.227.230.0/23 DIR0
+ALL 193.227.250.0/23 DIR0
+ALL 193.228.2.0/24 DIR0
+ALL 193.232.65.0/24 DIR0
+ALL 193.238.20.0/22 DIR0
+ALL 193.238.32.0/22 DIR0
+ALL 193.238.96.0/22 DIR0
+ALL 193.238.108.0/22 DIR0
+ALL 193.238.116.0/22 DIR0
+ALL 193.238.152.0/22 DIR0
+ALL 193.238.192.0/22 DIR0
+ALL 193.239.24.0/22 DIR0
+ALL 193.239.68.0/23 DIR0
+ALL 193.239.72.0/22 DIR0
+ALL 193.239.128.0/23 DIR0
+ALL 193.239.132.0/24 DIR0
+ALL 193.239.142.0/23 DIR0
+ALL 193.239.152.0/23 DIR0
+ALL 193.239.170.0/23 DIR0
+ALL 193.239.178.0/23 DIR0
+ALL 193.239.228.0/23 DIR0
+ALL 193.239.234.0/23 DIR0
+ALL 193.239.238.0/23 DIR0
+ALL 193.239.250.0/23 DIR0
+ALL 193.239.254.0/23 DIR0
+ALL 193.242.114.0/24 DIR0
+ALL 193.243.152.0/23 DIR0
+ALL 193.243.156.0/22 DIR0
+ALL 193.254.196.0/23 DIR0
+ALL 193.254.216.0/22 DIR0
+ALL 193.254.220.0/23 DIR0
+ALL 193.254.224.0/22 DIR0
+ALL 193.254.232.0/22 DIR0
+ALL 194.0.88.0/22 DIR0
+ALL 194.0.104.0/22 DIR0
+ALL 194.0.116.0/23 DIR0
+ALL 194.0.131.0/24 DIR0
+ALL 194.0.138.0/24 DIR0
+ALL 194.0.148.0/24 DIR0
+ALL 194.0.150.0/24 DIR0
+ALL 194.0.187.0/24 DIR0
+ALL 194.0.200.0/24 DIR0
+ALL 194.0.206.0/24 DIR0
+ALL 194.0.218.0/24 DIR0
+ALL 194.0.231.0/24 DIR0
+ALL 194.1.193.0/24 DIR0
+ALL 194.1.195.0/24 DIR0
+ALL 194.6.196.0/22 DIR0
+ALL 194.6.231.0/24 DIR0
+ALL 194.6.232.0/23 DIR0
+ALL 194.8.51.0/24 DIR0
+ALL 194.8.56.0/24 DIR0
+ALL 194.8.64.0/23 DIR0
+ALL 194.9.0.0/23 DIR0
+ALL 194.9.14.0/23 DIR0
+ALL 194.9.26.0/23 DIR0
+ALL 194.9.36.0/23 DIR0
+ALL 194.9.50.0/23 DIR0
+ALL 194.9.68.0/23 DIR0
+ALL 194.15.147.0/24 DIR0
+ALL 194.24.162.0/23 DIR0
+ALL 194.24.182.0/23 DIR0
+ALL 194.24.184.0/22 DIR0
+ALL 194.24.190.0/23 DIR0
+ALL 194.24.236.0/23 DIR0
+ALL 194.24.246.0/23 DIR0
+ALL 194.29.60.0/22 DIR0
+ALL 194.29.184.0/22 DIR0
+ALL 194.29.205.0/24 DIR0
+ALL 194.30.163.0/24 DIR0
+ALL 194.30.168.0/24 DIR0
+ALL 194.30.170.0/24 DIR0
+ALL 194.30.172.0/24 DIR0
+ALL 194.33.15.0/24 DIR0
+ALL 194.33.180.0/23 DIR0
+ALL 194.33.188.0/23 DIR0
+ALL 194.37.248.0/24 DIR0
+ALL 194.42.192.0/20 DIR0
+ALL 194.44.0.0/24 DIR0
+ALL 194.44.2.0/23 DIR0
+ALL 194.44.5.0/24 DIR0
+ALL 194.44.7.0/24 DIR0
+ALL 194.44.8.0/22 DIR0
+ALL 194.44.13.0/24 DIR0
+ALL 194.44.14.0/23 DIR0
+ALL 194.44.16.0/22 DIR0
+ALL 194.44.21.0/24 DIR0
+ALL 194.44.22.0/23 DIR0
+ALL 194.44.24.0/23 DIR0
+ALL 194.44.27.0/24 DIR0
+ALL 194.44.28.0/22 DIR0
+ALL 194.44.32.0/20 DIR0
+ALL 194.44.48.0/24 DIR0
+ALL 194.44.50.0/24 DIR0
+ALL 194.44.53.0/24 DIR0
+ALL 194.44.54.0/23 DIR0
+ALL 194.44.56.0/21 DIR0
+ALL 194.44.64.0/24 DIR0
+ALL 194.44.66.0/23 DIR0
+ALL 194.44.69.0/24 DIR0
+ALL 194.44.70.0/23 DIR0
+ALL 194.44.72.0/21 DIR0
+ALL 194.44.80.0/22 DIR0
+ALL 194.44.88.0/23 DIR0
+ALL 194.44.91.0/24 DIR0
+ALL 194.44.92.0/22 DIR0
+ALL 194.44.96.0/21 DIR0
+ALL 194.44.104.0/22 DIR0
+ALL 194.44.108.0/23 DIR0
+ALL 194.44.111.0/24 DIR0
+ALL 194.44.112.0/23 DIR0
+ALL 194.44.114.0/24 DIR0
+ALL 194.44.116.0/22 DIR0
+ALL 194.44.120.0/22 DIR0
+ALL 194.44.126.0/23 DIR0
+ALL 194.44.128.0/20 DIR0
+ALL 194.44.144.0/21 DIR0
+ALL 194.44.152.0/22 DIR0
+ALL 194.44.156.0/23 DIR0
+ALL 194.44.158.0/24 DIR0
+ALL 194.44.160.0/23 DIR0
+ALL 194.44.163.0/24 DIR0
+ALL 194.44.164.0/22 DIR0
+ALL 194.44.168.0/21 DIR0
+ALL 194.44.176.0/22 DIR0
+ALL 194.44.181.0/24 DIR0
+ALL 194.44.182.0/23 DIR0
+ALL 194.44.184.0/22 DIR0
+ALL 194.44.188.0/24 DIR0
+ALL 194.44.190.0/23 DIR0
+ALL 194.44.192.0/18 DIR0
+ALL 194.48.175.0/24 DIR0
+ALL 194.48.212.0/24 DIR0
+ALL 194.50.0.0/24 DIR0
+ALL 194.50.9.0/24 DIR0
+ALL 194.50.85.0/24 DIR0
+ALL 194.50.98.0/24 DIR0
+ALL 194.50.114.0/24 DIR0
+ALL 194.50.116.0/24 DIR0
+ALL 194.50.119.0/24 DIR0
+ALL 194.50.125.0/24 DIR0
+ALL 194.50.161.0/24 DIR0
+ALL 194.50.167.0/24 DIR0
+ALL 194.50.169.0/24 DIR0
+ALL 194.50.254.0/24 DIR0
+ALL 194.54.80.0/22 DIR0
+ALL 194.54.88.0/22 DIR0
+ALL 194.54.152.0/21 DIR0
+ALL 194.54.184.0/22 DIR0
+ALL 194.58.82.0/24 DIR0
+ALL 194.60.69.0/24 DIR0
+ALL 194.60.77.0/24 DIR0
+ALL 194.63.140.0/22 DIR0
+ALL 194.79.8.0/22 DIR0
+ALL 194.79.20.0/22 DIR0
+ALL 194.79.60.0/22 DIR0
+ALL 194.88.1.0/24 DIR0
+ALL 194.88.138.0/23 DIR0
+ALL 194.88.150.0/23 DIR0
+ALL 194.88.152.0/23 DIR0
+ALL 194.88.206.0/23 DIR0
+ALL 194.88.218.0/23 DIR0
+ALL 194.88.220.0/23 DIR0
+ALL 194.93.160.0/19 DIR0
+ALL 194.99.240.0/22 DIR0
+ALL 194.105.136.0/23 DIR0
+ALL 194.105.144.0/23 DIR0
+ALL 194.106.208.0/23 DIR0
+ALL 194.106.216.0/22 DIR0
+ALL 194.107.21.0/24 DIR0
+ALL 194.110.79.0/24 DIR0
+ALL 194.110.126.0/24 DIR0
+ALL 194.110.129.0/24 DIR0
+ALL 194.110.210.0/24 DIR0
+ALL 194.110.219.0/24 DIR0
+ALL 194.110.248.0/24 DIR0
+ALL 194.110.252.0/24 DIR0
+ALL 194.110.254.0/24 DIR0
+ALL 194.114.132.0/22 DIR0
+ALL 194.114.136.0/22 DIR0
+ALL 194.116.162.0/23 DIR0
+ALL 194.116.170.0/23 DIR0
+ALL 194.116.194.0/23 DIR0
+ALL 194.116.228.0/23 DIR0
+ALL 194.116.232.0/23 DIR0
+ALL 194.116.238.0/23 DIR0
+ALL 194.116.244.0/23 DIR0
+ALL 194.125.224.0/22 DIR0
+ALL 194.125.244.0/23 DIR0
+ALL 194.125.248.0/23 DIR0
+ALL 194.126.180.0/22 DIR0
+ALL 194.126.204.0/24 DIR0
+ALL 194.126.224.0/24 DIR0
+ALL 194.135.249.0/24 DIR0
+ALL 194.140.228.0/24 DIR0
+ALL 194.140.237.0/24 DIR0
+ALL 194.143.136.0/23 DIR0
+ALL 194.143.144.0/22 DIR0
+ALL 194.145.117.0/24 DIR0
+ALL 194.145.198.0/23 DIR0
+ALL 194.145.214.0/23 DIR0
+ALL 194.145.216.0/23 DIR0
+ALL 194.145.220.0/23 DIR0
+ALL 194.146.110.0/24 DIR0
+ALL 194.146.112.0/24 DIR0
+ALL 194.146.132.0/22 DIR0
+ALL 194.146.136.0/21 DIR0
+ALL 194.146.156.0/23 DIR0
+ALL 194.146.188.0/22 DIR0
+ALL 194.146.196.0/22 DIR0
+ALL 194.146.220.0/22 DIR0
+ALL 194.146.228.0/22 DIR0
+ALL 194.150.72.0/21 DIR0
+ALL 194.150.92.0/22 DIR0
+ALL 194.150.104.0/22 DIR0
+ALL 194.150.174.0/23 DIR0
+ALL 194.150.192.0/23 DIR0
+ALL 194.150.204.0/23 DIR0
+ALL 194.150.220.0/23 DIR0
+ALL 194.150.232.0/23 DIR0
+ALL 194.153.128.0/23 DIR0
+ALL 194.153.148.0/23 DIR0
+ALL 194.165.46.0/24 DIR0
+ALL 194.165.62.0/24 DIR0
+ALL 194.169.193.0/24 DIR0
+ALL 194.169.205.0/24 DIR0
+ALL 194.169.206.0/23 DIR0
+ALL 194.169.210.0/24 DIR0
+ALL 194.169.238.0/24 DIR0
+ALL 194.176.97.0/24 DIR0
+ALL 194.183.160.0/19 DIR0
+ALL 194.187.28.0/22 DIR0
+ALL 194.187.48.0/22 DIR0
+ALL 194.187.56.0/22 DIR0
+ALL 194.187.104.0/21 DIR0
+ALL 194.187.128.0/22 DIR0
+ALL 194.187.148.0/22 DIR0
+ALL 194.187.152.0/22 DIR0
+ALL 194.187.208.0/24 DIR0
+ALL 194.187.216.0/22 DIR0
+ALL 194.187.228.0/22 DIR0
+ALL 194.213.6.0/24 DIR0
+ALL 194.213.23.0/24 DIR0
+ALL 194.220.139.0/24 DIR0
+ALL 194.220.172.0/24 DIR0
+ALL 194.242.53.0/24 DIR0
+ALL 194.242.60.0/24 DIR0
+ALL 194.242.96.0/22 DIR0
+ALL 194.242.100.0/23 DIR0
+ALL 194.242.102.0/24 DIR0
+ALL 194.242.116.0/22 DIR0
+ALL 194.246.99.0/24 DIR0
+ALL 194.246.104.0/23 DIR0
+ALL 194.246.116.0/23 DIR0
+ALL 194.246.120.0/23 DIR0
+ALL 195.2.236.0/23 DIR0
+ALL 195.2.242.0/23 DIR0
+ALL 195.3.128.0/21 DIR0
+ALL 195.3.148.0/22 DIR0
+ALL 195.3.156.0/22 DIR0
+ALL 195.3.196.0/22 DIR0
+ALL 195.3.204.0/22 DIR0
+ALL 195.3.236.0/22 DIR0
+ALL 195.3.244.0/22 DIR0
+ALL 195.5.108.0/23 DIR0
+ALL 195.5.124.0/23 DIR0
+ALL 195.5.184.0/24 DIR0
+ALL 195.8.200.0/23 DIR0
+ALL 195.8.218.0/23 DIR0
+ALL 195.9.87.0/24 DIR0
+ALL 195.9.247.0/24 DIR0
+ALL 195.10.210.0/24 DIR0
+ALL 195.10.218.0/24 DIR0
+ALL 195.12.36.0/22 DIR0
+ALL 195.14.17.0/24 DIR0
+ALL 195.20.4.0/22 DIR0
+ALL 195.20.28.0/22 DIR0
+ALL 195.20.96.0/23 DIR0
+ALL 195.20.100.0/22 DIR0
+ALL 195.20.118.0/23 DIR0
+ALL 195.20.124.0/23 DIR0
+ALL 195.20.128.0/19 DIR0
+ALL 195.22.112.0/22 DIR0
+ALL 195.22.130.0/23 DIR0
+ALL 195.22.132.0/23 DIR0
+ALL 195.22.140.0/23 DIR0
+ALL 195.24.128.0/19 DIR0
+ALL 195.24.234.0/24 DIR0
+ALL 195.24.252.0/23 DIR0
+ALL 195.26.16.0/22 DIR0
+ALL 195.26.64.0/22 DIR0
+ALL 195.26.80.0/21 DIR0
+ALL 195.26.92.0/22 DIR0
+ALL 195.28.0.0/23 DIR0
+ALL 195.28.186.0/23 DIR0
+ALL 195.34.74.0/23 DIR0
+ALL 195.34.90.0/23 DIR0
+ALL 195.34.94.0/23 DIR0
+ALL 195.34.196.0/22 DIR0
+ALL 195.34.204.0/22 DIR0
+ALL 195.35.65.0/24 DIR0
+ALL 195.38.16.0/23 DIR0
+ALL 195.38.18.0/24 DIR0
+ALL 195.39.196.0/23 DIR0
+ALL 195.39.210.0/23 DIR0
+ALL 195.39.214.0/23 DIR0
+ALL 195.39.232.0/23 DIR0
+ALL 195.39.240.0/22 DIR0
+ALL 195.39.248.0/23 DIR0
+ALL 195.39.252.0/23 DIR0
+ALL 195.42.126.0/23 DIR0
+ALL 195.42.130.0/23 DIR0
+ALL 195.42.136.0/23 DIR0
+ALL 195.43.40.0/22 DIR0
+ALL 195.43.146.0/24 DIR0
+ALL 195.43.148.0/24 DIR0
+ALL 195.46.56.0/22 DIR0
+ALL 195.47.202.0/24 DIR0
+ALL 195.47.219.0/24 DIR0
+ALL 195.47.248.0/24 DIR0
+ALL 195.47.253.0/24 DIR0
+ALL 195.49.128.0/22 DIR0
+ALL 195.49.148.0/22 DIR0
+ALL 195.49.164.0/22 DIR0
+ALL 195.58.224.0/19 DIR0
+ALL 195.60.66.0/23 DIR0
+ALL 195.60.70.0/23 DIR0
+ALL 195.60.174.0/23 DIR0
+ALL 195.60.184.0/23 DIR0
+ALL 195.60.200.0/23 DIR0
+ALL 195.60.224.0/24 DIR0
+ALL 195.60.226.0/24 DIR0
+ALL 195.62.14.0/23 DIR0
+ALL 195.62.24.0/23 DIR0
+ALL 195.62.36.0/23 DIR0
+ALL 195.64.136.0/23 DIR0
+ALL 195.64.142.0/23 DIR0
+ALL 195.64.148.0/23 DIR0
+ALL 195.64.166.0/23 DIR0
+ALL 195.64.190.0/23 DIR0
+ALL 195.64.224.0/19 DIR0
+ALL 195.66.65.0/24 DIR0
+ALL 195.66.66.0/24 DIR0
+ALL 195.66.79.0/24 DIR0
+ALL 195.66.87.0/24 DIR0
+ALL 195.66.93.0/24 DIR0
+ALL 195.66.105.0/24 DIR0
+ALL 195.66.136.0/23 DIR0
+ALL 195.66.140.0/23 DIR0
+ALL 195.66.152.0/23 DIR0
+ALL 195.66.156.0/23 DIR0
+ALL 195.66.192.0/19 DIR0
+ALL 195.68.196.0/23 DIR0
+ALL 195.68.202.0/23 DIR0
+ALL 195.68.210.0/23 DIR0
+ALL 195.68.216.0/22 DIR0
+ALL 195.68.222.0/23 DIR0
+ALL 195.69.76.0/22 DIR0
+ALL 195.69.84.0/22 DIR0
+ALL 195.69.132.0/22 DIR0
+ALL 195.69.168.0/22 DIR0
+ALL 195.69.176.0/23 DIR0
+ALL 195.69.179.0/24 DIR0
+ALL 195.69.184.0/22 DIR0
+ALL 195.69.196.0/22 DIR0
+ALL 195.69.200.0/22 DIR0
+ALL 195.69.220.0/22 DIR0
+ALL 195.69.244.0/22 DIR0
+ALL 195.69.248.0/22 DIR0
+ALL 195.72.144.0/22 DIR0
+ALL 195.72.156.0/22 DIR0
+ALL 195.74.67.0/24 DIR0
+ALL 195.78.38.0/23 DIR0
+ALL 195.78.58.0/23 DIR0
+ALL 195.78.68.0/23 DIR0
+ALL 195.78.92.0/23 DIR0
+ALL 195.78.232.0/22 DIR0
+ALL 195.78.244.0/22 DIR0
+ALL 195.78.252.0/23 DIR0
+ALL 195.80.231.0/24 DIR0
+ALL 195.80.232.0/24 DIR0
+ALL 195.82.150.0/23 DIR0
+ALL 195.85.198.0/24 DIR0
+ALL 195.85.214.0/24 DIR0
+ALL 195.85.219.0/24 DIR0
+ALL 195.85.250.0/24 DIR0
+ALL 195.90.122.0/23 DIR0
+ALL 195.93.138.0/23 DIR0
+ALL 195.93.154.0/23 DIR0
+ALL 195.93.160.0/23 DIR0
+ALL 195.93.172.0/23 DIR0
+ALL 195.93.184.0/23 DIR0
+ALL 195.93.190.0/23 DIR0
+ALL 195.93.204.0/23 DIR0
+ALL 195.93.212.0/22 DIR0
+ALL 195.95.139.0/24 DIR0
+ALL 195.95.147.0/24 DIR0
+ALL 195.95.151.0/24 DIR0
+ALL 195.95.157.0/24 DIR0
+ALL 195.95.165.0/24 DIR0
+ALL 195.95.171.0/24 DIR0
+ALL 195.95.189.0/24 DIR0
+ALL 195.95.206.0/23 DIR0
+ALL 195.95.210.0/23 DIR0
+ALL 195.95.222.0/23 DIR0
+ALL 195.95.232.0/23 DIR0
+ALL 195.110.6.0/23 DIR0
+ALL 195.114.6.0/23 DIR0
+ALL 195.114.30.0/23 DIR0
+ALL 195.114.96.0/23 DIR0
+ALL 195.114.120.0/23 DIR0
+ALL 195.114.128.0/19 DIR0
+ALL 195.123.0.0/16 DIR0
+ALL 195.128.16.0/22 DIR0
+ALL 195.128.56.0/21 DIR0
+ALL 195.128.178.0/23 DIR0
+ALL 195.128.182.0/23 DIR0
+ALL 195.128.230.0/23 DIR0
+ALL 195.128.248.0/23 DIR0
+ALL 195.128.252.0/23 DIR0
+ALL 195.135.196.0/22 DIR0
+ALL 195.137.167.0/24 DIR0
+ALL 195.137.192.0/23 DIR0
+ALL 195.137.196.0/23 DIR0
+ALL 195.137.202.0/23 DIR0
+ALL 195.137.226.0/23 DIR0
+ALL 195.137.232.0/23 DIR0
+ALL 195.137.240.0/23 DIR0
+ALL 195.137.244.0/23 DIR0
+ALL 195.137.250.0/23 DIR0
+ALL 195.138.64.0/19 DIR0
+ALL 195.138.160.0/19 DIR0
+ALL 195.138.193.0/24 DIR0
+ALL 195.138.198.0/24 DIR0
+ALL 195.138.217.0/24 DIR0
+ALL 195.138.218.0/24 DIR0
+ALL 195.140.160.0/22 DIR0
+ALL 195.140.168.0/22 DIR0
+ALL 195.140.176.0/22 DIR0
+ALL 195.140.224.0/22 DIR0
+ALL 195.140.244.0/22 DIR0
+ALL 195.144.6.0/24 DIR0
+ALL 195.144.21.0/24 DIR0
+ALL 195.144.25.0/24 DIR0
+ALL 195.144.28.0/24 DIR0
+ALL 195.149.70.0/24 DIR0
+ALL 195.149.90.0/24 DIR0
+ALL 195.149.96.0/24 DIR0
+ALL 195.149.108.0/23 DIR0
+ALL 195.149.112.0/24 DIR0
+ALL 195.149.114.0/24 DIR0
+ALL 195.149.125.0/24 DIR0
+ALL 195.160.192.0/22 DIR0
+ALL 195.160.220.0/22 DIR0
+ALL 195.160.232.0/22 DIR0
+ALL 195.177.68.0/22 DIR0
+ALL 195.177.72.0/22 DIR0
+ALL 195.177.92.0/22 DIR0
+ALL 195.177.112.0/21 DIR0
+ALL 195.177.124.0/22 DIR0
+ALL 195.177.208.0/23 DIR0
+ALL 195.177.222.0/23 DIR0
+ALL 195.177.236.0/22 DIR0
+ALL 195.177.240.0/23 DIR0
+ALL 195.178.128.0/19 DIR0
+ALL 195.182.0.0/24 DIR0
+ALL 195.182.7.0/24 DIR0
+ALL 195.182.21.0/24 DIR0
+ALL 195.182.22.0/24 DIR0
+ALL 195.182.192.0/22 DIR0
+ALL 195.184.70.0/24 DIR0
+ALL 195.184.80.0/23 DIR0
+ALL 195.184.192.0/19 DIR0
+ALL 195.189.8.0/22 DIR0
+ALL 195.189.16.0/22 DIR0
+ALL 195.189.44.0/22 DIR0
+ALL 195.189.48.0/22 DIR0
+ALL 195.189.60.0/22 DIR0
+ALL 195.189.96.0/22 DIR0
+ALL 195.189.104.0/22 DIR0
+ALL 195.189.200.0/23 DIR0
+ALL 195.189.214.0/23 DIR0
+ALL 195.189.226.0/23 DIR0
+ALL 195.189.228.0/23 DIR0
+ALL 195.189.234.0/23 DIR0
+ALL 195.189.240.0/23 DIR0
+ALL 195.189.246.0/23 DIR0
+ALL 195.189.248.0/23 DIR0
+ALL 195.190.13.0/24 DIR0
+ALL 195.200.64.0/23 DIR0
+ALL 195.200.90.0/23 DIR0
+ALL 195.200.196.0/24 DIR0
+ALL 195.200.221.0/24 DIR0
+ALL 195.206.224.0/21 DIR0
+ALL 195.214.192.0/21 DIR0
+ALL 195.214.208.0/21 DIR0
+ALL 195.214.220.0/22 DIR0
+ALL 195.214.236.0/22 DIR0
+ALL 195.216.204.0/23 DIR0
+ALL 195.216.206.0/24 DIR0
+ALL 195.216.210.0/23 DIR0
+ALL 195.216.212.0/23 DIR0
+ALL 195.216.226.0/24 DIR0
+ALL 195.216.248.0/24 DIR0
+ALL 195.225.52.0/23 DIR0
+ALL 195.225.96.0/22 DIR0
+ALL 195.225.112.0/22 DIR0
+ALL 195.225.144.0/22 DIR0
+ALL 195.225.156.0/22 DIR0
+ALL 195.225.228.0/22 DIR0
+ALL 195.230.96.0/24 DIR0
+ALL 195.230.103.0/24 DIR0
+ALL 195.230.115.0/24 DIR0
+ALL 195.230.128.0/19 DIR0
+ALL 195.234.61.0/24 DIR0
+ALL 195.234.68.0/22 DIR0
+ALL 195.234.72.0/22 DIR0
+ALL 195.234.112.0/22 DIR0
+ALL 195.234.132.0/24 DIR0
+ALL 195.234.148.0/24 DIR0
+ALL 195.234.174.0/24 DIR0
+ALL 195.234.200.0/22 DIR0
+ALL 195.234.212.0/22 DIR0
+ALL 195.234.220.0/22 DIR0
+ALL 195.238.92.0/23 DIR0
+ALL 195.238.176.0/21 DIR0
+ALL 195.238.188.0/22 DIR0
+ALL 195.242.94.0/23 DIR0
+ALL 195.242.112.0/22 DIR0
+ALL 195.242.148.0/22 DIR0
+ALL 195.242.161.0/24 DIR0
+ALL 195.242.200.0/22 DIR0
+ALL 195.244.4.0/23 DIR0
+ALL 195.244.8.0/23 DIR0
+ALL 195.245.76.0/23 DIR0
+ALL 195.245.80.0/23 DIR0
+ALL 195.245.96.0/23 DIR0
+ALL 195.245.112.0/23 DIR0
+ALL 195.245.118.0/23 DIR0
+ALL 195.245.120.0/23 DIR0
+ALL 195.245.200.0/24 DIR0
+ALL 195.245.215.0/24 DIR0
+ALL 195.245.221.0/24 DIR0
+ALL 195.245.249.0/24 DIR0
+ALL 195.245.253.0/24 DIR0
+ALL 195.246.104.0/23 DIR0
+ALL 195.246.217.0/24 DIR0
+ALL 195.248.93.0/24 DIR0
+ALL 195.248.160.0/19 DIR0
+ALL 195.248.234.0/23 DIR0
+ALL 195.250.36.0/24 DIR0
+ALL 195.250.43.0/24 DIR0
+ALL 195.250.62.0/24 DIR0
+ALL 195.254.142.0/23 DIR0
+ALL 195.254.150.0/23 DIR0
+ALL 209.62.181.0/24 DIR0
+ALL 209.62.187.0/24 DIR0
+ALL 209.62.189.0/24 DIR0
+ALL 209.85.128.0/17 DIR0
+ALL 212.1.64.0/18 DIR0
+ALL 212.2.128.0/19 DIR0
+ALL 212.3.96.0/19 DIR0
+ALL 212.8.32.0/19 DIR0
+ALL 212.9.224.0/19 DIR0
+ALL 212.15.128.0/19 DIR0
+ALL 212.22.192.0/20 DIR0
+ALL 212.26.128.0/19 DIR0
+ALL 212.28.64.0/19 DIR0
+ALL 212.35.160.0/19 DIR0
+ALL 212.40.32.0/19 DIR0
+ALL 212.42.64.0/19 DIR0
+ALL 212.58.160.0/19 DIR0
+ALL 212.66.32.0/19 DIR0
+ALL 212.68.160.0/19 DIR0
+ALL 212.74.234.0/24 DIR0
+ALL 212.80.32.0/19 DIR0
+ALL 212.82.192.0/19 DIR0
+ALL 212.86.96.0/19 DIR0
+ALL 212.86.225.0/24 DIR0
+ALL 212.86.226.0/24 DIR0
+ALL 212.86.228.0/22 DIR0
+ALL 212.86.232.0/21 DIR0
+ALL 212.86.240.0/20 DIR0
+ALL 212.87.160.0/19 DIR0
+ALL 212.90.96.0/20 DIR0
+ALL 212.90.112.0/23 DIR0
+ALL 212.90.116.0/23 DIR0
+ALL 212.90.124.0/22 DIR0
+ALL 212.90.160.0/19 DIR0
+ALL 212.92.224.0/19 DIR0
+ALL 212.109.32.0/19 DIR0
+ALL 212.111.192.0/19 DIR0
+ALL 212.113.32.0/20 DIR0
+ALL 212.115.224.0/19 DIR0
+ALL 212.178.0.0/19 DIR0
+ALL 213.130.0.0/20 DIR0
+ALL 213.130.16.0/23 DIR0
+ALL 213.130.18.0/24 DIR0
+ALL 213.130.20.0/22 DIR0
+ALL 213.130.24.0/21 DIR0
+ALL 213.133.160.0/19 DIR0
+ALL 213.135.64.0/23 DIR0
+ALL 213.135.67.0/24 DIR0
+ALL 213.135.68.0/22 DIR0
+ALL 213.135.72.0/21 DIR0
+ALL 213.151.0.0/19 DIR0
+ALL 213.154.192.0/19 DIR0
+ALL 213.155.0.0/19 DIR0
+ALL 213.156.64.0/19 DIR0
+ALL 213.159.224.0/19 DIR0
+ALL 213.160.128.0/19 DIR0
+ALL 213.169.64.0/19 DIR0
+ALL 213.180.192.0/19 DIR0
+ALL 213.186.112.0/20 DIR0
+ALL 213.186.192.0/19 DIR0
+ALL 213.200.32.0/23 DIR0
+ALL 213.200.43.0/24 DIR0
+ALL 213.208.160.0/19 DIR0
+ALL 213.227.192.0/18 DIR0
+ALL 213.231.0.0/18 DIR0
+ALL 213.238.0.0/22 DIR0
+ALL 213.238.16.0/24 DIR0
+ALL 213.238.20.0/24 DIR0
+ALL 213.238.24.0/24 DIR0
+ALL 213.238.28.0/24 DIR0
+ALL 216.73.80.0/24 DIR0
+ALL 216.73.87.0/24 DIR0
+ALL 216.239.32.0/19 DIR0
+ALL 217.9.0.0/24 DIR0
+ALL 217.9.4.0/24 DIR0
+ALL 217.12.192.0/19 DIR0
+ALL 217.19.208.0/20 DIR0
+ALL 217.24.160.0/20 DIR0
+ALL 217.25.192.0/20 DIR0
+ALL 217.27.144.0/20 DIR0
+ALL 217.28.254.0/24 DIR0
+ALL 217.65.240.0/21 DIR0
+ALL 217.66.96.0/20 DIR0
+ALL 217.73.128.0/20 DIR0
+ALL 217.76.192.0/20 DIR0
+ALL 217.77.208.0/20 DIR0
+ALL 217.112.208.0/20 DIR0
+ALL 217.114.32.0/20 DIR0
+ALL 217.117.64.0/20 DIR0
+ALL 217.144.64.0/20 DIR0
+ALL 217.146.240.0/20 DIR0
+ALL 217.147.160.0/21 DIR0
+ALL 217.147.168.0/24 DIR0
+ALL 217.175.80.0/20 DIR0
+ALL 217.196.160.0/20 DIR0
+ALL 217.198.128.0/20 DIR0
+ALL 217.199.208.0/20 DIR0
+ALL 217.199.224.0/20 DIR0
diff --git a/projects/traffcounter/rules.cpp b/projects/traffcounter/rules.cpp
new file mode 100644 (file)
index 0000000..165addb
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.1.1.1 $
+ $Date: 2009/02/24 08:13:03 $
+ $Author: faust $
+ */
+
+#include <fstream>
+#include <sstream>
+#include <cstdlib>
+#include <limits>
+#include <cerrno>
+#include <locale>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "rules.h"
+#include "utils.h"
+
+using namespace std;
+
+STG::RULES_PARSER::RULES_PARSER()
+    : rules(),
+      error(false),
+      errorStream(""),
+      protocols()
+{
+error = InitProtocols();
+}
+
+STG::RULES_PARSER::RULES_PARSER(const string & fileName)
+    : rules(),
+      error(false),
+      errorStream(""),
+      protocols()
+{
+error = InitProtocols();
+SetFile(fileName);
+}
+
+void STG::RULES_PARSER::SetFile(const string & fileName)
+{
+errorStream.str("");
+
+ifstream rulesFile(fileName.c_str());
+
+int lineNumber = 0;
+
+if (!rulesFile)
+    {
+    error = true;
+    errorStream << "RULES_PARSER::SetFile - Error opening file '" << fileName << "'\n";
+    return;
+    }
+
+string line;
+
+rules.erase(rules.begin(), rules.end());
+
+while (getline(rulesFile, line))
+    {
+    lineNumber++;
+    if (ParseLine(line))
+        {
+        error = true;
+        errorStream << "RULES_PARSER::SetFile - Error parsing line at '" << fileName << ":" << lineNumber << "'\n";
+        return;
+        }
+    }
+
+STG::RULE rule;
+
+// Adding lastest rule: ALL 0.0.0.0/0 NULL
+rule.dir = -1; //NULL
+rule.ip = 0;  //0.0.0.0
+rule.mask = 0;
+rule.port1 = 0;
+rule.port2 = 65535;
+rule.proto = -1;
+
+rules.push_back(rule);
+
+errorStream.str("");
+
+return;
+}
+
+bool STG::RULES_PARSER::ParseLine(string line)
+{
+size_t pos;
+
+pos = line.find('#');
+if (pos != string::npos)
+    {
+    line = line.substr(0, pos);
+    }
+
+if (line.empty())
+    {
+    return false;
+    }
+
+size_t lpos = line.find_first_not_of("\t ", 0, 2);
+
+if (lpos == string::npos)
+    {
+    return false;
+    }
+
+size_t rpos = line.find_first_of("\t ", lpos, 2);
+
+if (rpos == string::npos)
+    {
+    return false;
+    }
+
+string proto(line.begin() + lpos, line.begin() + rpos);
+
+lpos = line.find_first_not_of("\t ", rpos, 2);
+
+if (lpos == string::npos)
+    {
+    return false;
+    }
+
+rpos = line.find_first_of("\t ", lpos, 2);
+
+if (rpos == string::npos)
+    {
+    return false;
+    }
+
+string address(line.begin() + lpos, line.begin() + rpos);
+
+lpos = line.find_first_not_of("\t ", rpos, 2);
+
+if (lpos == string::npos)
+    {
+    return false;
+    }
+string direction(line.begin() + lpos, line.end());
+
+if (proto.empty() ||
+    address.empty() ||
+    direction.empty())
+    {
+    return false;
+    }
+
+map<string, int>::const_iterator it(protocols.find(proto));
+
+if (it == protocols.end())
+    {
+    errorStream << "RULES_PARSER::ParseLine - Invalid protocol\n";
+    return true;
+    }
+
+STG::RULE rule;
+
+rule.proto = it->second;
+
+if (direction.length() < 4)
+    {
+    errorStream << "RULES_PARSER::ParseLine - Invalid direction\n";
+    return true;
+    }
+
+if (direction == "NULL")
+    {
+    rule.dir = -1;
+    }
+else
+    {
+    string prefix(direction.begin(), direction.begin() + 3);
+    direction = direction.substr(3, direction.length() - 3);
+    if (prefix != "DIR")
+        {
+        errorStream << "RULES_PARSER::ParseLine - Invalid direction prefix\n";
+        return true;
+        }
+    char * endptr;
+    /* 
+     * 'cause strtol don't change errno on success
+     * according to: http://www.opengroup.org/onlinepubs/000095399/functions/strtol.html
+     */
+    errno = 0;
+    rule.dir = strtol(direction.c_str(), &endptr, 10);
+
+    // Code from strtol(3) release 3.10
+    if ((errno == ERANGE && (rule.dir == numeric_limits<int>::max() ||
+                             rule.dir == numeric_limits<int>::min()))
+        || (errno != 0 && rule.dir == 0))
+        {
+            errorStream << "RULES_PARSER::ParseLine - Direction out of range\n";
+            return true;
+        }
+    if (endptr == direction.c_str())
+        {
+            errorStream << "RULES_PARSER::ParseLine - Invalid direction\n";
+            return true;
+        }
+    }
+
+if (ParseAddress(address, &rule))
+    {
+    errorStream << "RULES_PARSER::ParseLine - Invalid address\n";
+    return true;
+    }
+
+rules.push_back(rule);
+
+return false;
+}
+
+bool STG::RULES_PARSER::ParseAddress(const string & address, RULE * rule) const
+{
+// Format: <address>[/<mask>[:<port1>[-<port2>]]]
+size_t pos = address.find('/');
+string ip;
+string mask;
+string ports;
+
+if (pos != string::npos)
+    {
+    ip = address.substr(0, pos);
+    mask = address.substr(pos + 1, address.length() - pos - 1);
+    pos = mask.find(':');
+    if (pos != string::npos)
+        {
+        ports = mask.substr(pos + 1, mask.length() - pos - 1);
+        mask = mask.substr(0, pos);
+        }
+    else
+        {
+        ports = "0-65535";
+        }
+    }
+else
+    {
+    mask = "32";
+    pos = address.find(':');
+    if (pos != string::npos)
+        {
+        ip = address.substr(0, pos);
+        ports = address.substr(pos + 1, address.length() - pos - 1);
+        }
+    else
+        {
+        ip = address;
+        ports = "0-65536";
+        }
+    }
+
+struct in_addr ipaddr;
+
+if (!inet_aton(ip.c_str(), &ipaddr))
+    {
+    errorStream << "RULES_PARSER::ParseAddress - Invalid IP\n";
+    return true;
+    }
+
+rule->ip = ntohl(ipaddr.s_addr);
+
+if (ParseMask(mask, rule))
+    {
+    errorStream << "RULES_PARSER::ParseAddress - Error parsing mask\n";
+    return true;
+    }
+
+pos = ports.find('-');
+string port1;
+string port2;
+
+if (pos != string::npos)
+    {
+    port1 = ports.substr(0, pos);
+    port2 = ports.substr(pos + 1, ports.length() - pos - 1);
+    }
+else
+    {
+    port1 = port2 = ports;
+    }
+
+if (ParsePorts(port1, port2, rule))
+    {
+    errorStream << "RULES_PARSER::ParseAddress - Error pasing ports\n";
+    return true;
+    }
+
+return false;
+}
+
+bool STG::RULES_PARSER::ParseMask(const string & mask, RULE * rule) const
+{
+char * endptr;
+
+errno = 0;
+/* 
+ * 'cause strtol don't change errno on success
+ * according to: http://www.opengroup.org/onlinepubs/000095399/functions/strtol.html
+ */
+rule->mask = strtol(mask.c_str(), &endptr, 10);
+
+if ((errno == ERANGE && (rule->mask == numeric_limits<uint32_t>::max() ||
+                         rule->mask == numeric_limits<uint32_t>::min()))
+    || (errno != 0 && rule->mask == 0))
+    {
+    errorStream << "RULES_PARSER::ParseMask - Mask is out of range\n";
+    return true;
+    }
+
+if (endptr == NULL)
+    {
+    errorStream << "RULES_PARSER::ParseMask - NULL endptr\n";
+    return true;
+    }
+
+if (*endptr != '\0')
+    {
+    errorStream << "RULES_PARSER::ParseMask - Invalid mask\n";
+    return true;
+    }
+
+if (rule->mask > 32)
+    {
+    errorStream << "RULES_PARSER::ParseMask - Mask is greater than 32\n";
+    return true;
+    }
+
+rule->mask = 0xffFFffFF >> (32 - rule->mask);
+
+return false;
+}
+
+bool STG::RULES_PARSER::ParsePorts(const string & port1,
+                              const string & port2,
+                              RULE * rule) const
+{
+char * endptr;
+
+errno = 0;
+/* 
+ * 'cause strtol don't change errno on success
+ * according to: http://www.opengroup.org/onlinepubs/000095399/functions/strtol.html
+ */
+rule->port1 = strtol(port1.c_str(), &endptr, 10);
+
+if ((errno == ERANGE && (rule->port1 == numeric_limits<uint16_t>::max() ||
+                         rule->port1 == numeric_limits<uint16_t>::min()))
+    || (errno != 0 && rule->port1 == 0))
+    {
+    errorStream << "RULES_PARSER::ParsePorts - Min port is out of range\n";
+    return true;
+    }
+
+if (endptr == NULL)
+    {
+    errorStream << "RULES_PARSER::ParsePorts - NULL endptr on min port\n";
+    return true;
+    }
+
+if (*endptr != '\0')
+    {
+    errorStream << "RULES_PARSER::ParsePorts - Invalid min port\n";
+    return true;
+    }
+
+errno = 0;
+/* 
+ * 'cause strtol don't change errno on success
+ * according to: http://www.opengroup.org/onlinepubs/000095399/functions/strtol.html
+ */
+rule->port2 = strtol(port2.c_str(), &endptr, 10);
+
+if ((errno == ERANGE && (rule->port2 == numeric_limits<uint16_t>::max() ||
+                         rule->port2 == numeric_limits<uint16_t>::min()))
+    || (errno != 0 && rule->port2 == 0))
+    {
+        errorStream << "RULES_PARSER::ParseAddress - Max port is out of range\n";
+        return true;
+    }
+
+if (endptr == NULL)
+    {
+    errorStream << "RULES_PARSER::ParsePorts - NULL endptr on max port\n";
+    return true;
+    }
+
+if (*endptr != '\0')
+    {
+    errorStream << "RULES_PARSER::ParsePorts - Invalid max port\n";
+    return true;
+    }
+
+return false;
+}
+
+bool STG::RULES_PARSER::InitProtocols()
+{
+struct protoent * pe;
+
+locale loc("");
+
+protocols.erase(protocols.begin(), protocols.end());
+
+setprotoent(true); // Open link to /etc/protocols
+
+while ((pe = getprotoent()) != NULL)
+    {
+    string proto(pe->p_name);
+    protocols.insert(make_pair(STG::ToUpper(pe->p_name, loc), pe->p_proto));
+    }
+
+endprotoent();
+
+protocols["ALL"] = -1;
+protocols["TCP_UDP"] = -2;
+
+errorStream.str("");
+
+return protocols.empty();
+}
diff --git a/projects/traffcounter/rules.h b/projects/traffcounter/rules.h
new file mode 100644 (file)
index 0000000..049f437
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.1.1.1 $
+ $Date: 2009/02/24 08:13:03 $
+ $Author: faust $
+ */
+
+
+#ifndef __RULES_H__
+#define __RULES_H__
+
+#include <list>
+#include <string>
+#include <sstream>
+#include <map>
+
+#ifdef HAVE_STDINT
+    #include <stdint.h>
+#else
+    #ifdef HAVE_INTTYPES
+       #include <inttypes.h>
+    #else
+       #error "You need either stdint.h or inttypes.h to compile this!"
+    #endif
+#endif
+
+namespace STG
+{
+
+    //-----------------------------------------------------------------------------
+    struct RULE
+    {
+    uint32_t    ip;             // IP
+    uint32_t    mask;           // Netmask
+    uint16_t    port1;          // Port 1
+    uint16_t    port2;          // Port 2
+    int         proto;          // Protocol
+    int         dir;            // Direction
+    };
+    //-----------------------------------------------------------------------------
+    typedef std::list<RULE> RULES;
+    //-----------------------------------------------------------------------------
+    class RULES_PARSER
+    {
+    public:
+        RULES_PARSER();
+
+        RULES_PARSER(const std::string & fileName);
+
+        ~RULES_PARSER() {};
+
+        void SetFile(const std::string & fileName);
+
+        const RULES & GetRules() const { return rules; };
+        bool IsError() const { return error; };
+        const std::string ErrorMsg() const { return errorStream.str(); };
+
+    private:
+        RULES rules;
+        bool error;
+        mutable std::stringstream errorStream;
+        std::map<std::string, int> protocols;
+
+        bool InitProtocols();
+        bool ParseLine(std::string line);
+        bool ParseAddress(const std::string & address, RULE * rule) const;
+        bool ParseMask(const std::string & mask, RULE * rule) const;
+        bool ParsePorts(const std::string & port1,
+                        const std::string & port2,
+                        RULE * rule) const;
+    };
+
+}
+
+#endif // __RULES_H__
diff --git a/projects/traffcounter/rules_finder.cpp b/projects/traffcounter/rules_finder.cpp
new file mode 100644 (file)
index 0000000..82b398a
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.3 $
+ $Date: 2009/10/12 08:46:05 $
+ $Author: faust $
+ */
+
+#include "rules_finder.h"
+#include "logger.h"
+#include "lock.h"
+
+STG::RULES_FINDER::RULES_FINDER()
+{
+    pthread_mutex_init(&mutex, NULL);
+}
+
+STG::RULES_FINDER::~RULES_FINDER()
+{
+    pthread_mutex_destroy(&mutex);
+}
+
+void STG::RULES_FINDER::SetRules(const RULES & r)
+{
+SCOPED_LOCK lock(mutex);
+rules = r;
+}
+
+int STG::RULES_FINDER::GetDir(const PENDING_PACKET & packet) const
+{
+bool addrMatch;
+bool portMatch;
+
+STG::RULES::const_iterator ln;
+int ruleLine(1);
+
+SCOPED_LOCK lock(mutex);
+
+ln = rules.begin();
+
+while (ln != rules.end())
+    {
+    addrMatch = false;
+    portMatch = false;
+
+    // Port range
+    switch (packet.direction) {
+        case PENDING_PACKET::INCOMING:
+            portMatch = (packet.sport >= ln->port1) &&
+                        (packet.sport <= ln->port2);
+            break;
+        case PENDING_PACKET::OUTGOING:
+            portMatch = (packet.dport >= ln->port1) &&
+                        (packet.dport <= ln->port2);
+            break;
+        case PENDING_PACKET::LOCAL:
+            portMatch = ((packet.sport >= ln->port1) &&
+                        (packet.sport <= ln->port2)) ||
+                        ((packet.dport >= ln->port1) &&
+                        (packet.dport <= ln->port2));
+            break;
+        default:
+            ++ruleLine;
+            ++ln;
+            continue;
+    }
+
+    if (!portMatch) {
+        ++ruleLine;
+        ++ln;
+        continue;
+    }
+
+    /*portMatch = ((packet.sport >= ln->port1) &&
+                 (packet.sport <= ln->port2) &&
+                 (packet.direction == PENDING_PACKET::INCOMING)) ||
+                ((packet.dport >= ln->port1) &&
+                 (packet.dport <= ln->port2) &&
+                 (packet.direction == PENDING_PACKET::OUTGOING));*/
+
+    if (ln->proto != packet.proto)
+        {
+        // Is it a normal protcol number?
+        if (ln->proto >= 0)
+            {
+            ++ruleLine;
+            ++ln;
+            continue;
+            }
+        else if (ln->proto == -2)
+            {
+            // -2 - TCP_UDP
+            if (packet.proto != 6 &&
+                packet.proto != 17)
+                {
+                ++ruleLine;
+                ++ln;
+                continue;
+                }
+            }
+        // -1 - ALL
+        }
+
+    switch (packet.direction) {
+        case PENDING_PACKET::INCOMING:
+            // From outer world to us
+            addrMatch = (packet.saddr & ln->mask) == ln->ip;
+            break;
+        case PENDING_PACKET::OUTGOING:
+            // From us to outer world
+            addrMatch = (packet.daddr & ln->mask) == ln->ip;
+            break;
+        case PENDING_PACKET::LOCAL:
+            // From us to us
+            addrMatch = (packet.saddr & ln->mask) == ln->ip ||
+                        (packet.daddr & ln->mask) == ln->ip;
+            break;
+        default:
+            // From outer world to outer world
+            ++ruleLine;
+            ++ln;
+            continue;
+    }
+
+
+    if (addrMatch)
+        {
+        // At this point ports and protocol are matched
+        return ln->dir;
+        }
+
+    ++ruleLine;
+    ++ln;
+    }   //while (ln != rules.end())
+
+return -1;
+}
diff --git a/projects/traffcounter/rules_finder.h b/projects/traffcounter/rules_finder.h
new file mode 100644 (file)
index 0000000..8c11081
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.2 $
+ $Date: 2009/02/26 18:32:59 $
+ $Author: faust $
+ */
+
+
+#ifndef __RULES_FINDER_H__
+#define __RULES_FINDER_H__
+
+#include <pthread.h>
+
+#include "rules.h"
+#include "tc_packets.h"
+
+namespace STG
+{
+
+    class RULES_FINDER
+    {
+    public:
+        RULES_FINDER();
+        ~RULES_FINDER();
+
+        void SetRules(const RULES & r);
+
+        int GetDir(const PENDING_PACKET & packet) const;
+
+    private:
+        RULES rules;
+        mutable pthread_mutex_t mutex;
+    };
+
+}
+
+#endif
diff --git a/projects/traffcounter/rules_tester.cpp b/projects/traffcounter/rules_tester.cpp
new file mode 100644 (file)
index 0000000..e9fd30d
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.1.1.1 $
+ $Date: 2009/02/24 08:13:03 $
+ $Author: faust $
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <string>
+#include <map>
+#include <algorithm>
+#include <functional>
+
+#include "rules.h"
+#include "logger.h"
+
+using namespace STG;
+
+STGLogger log;
+
+typedef std::pair<std::string, bool> TEST_ENTRY;
+struct TEST_INFO {
+    bool wantedError;
+    bool actualError; // Parser error status
+    bool stdException; // Parser throws an std execption
+    bool otherException; // Parser throws another exception
+    std::string message; // Parser error message
+};
+
+class RULES_PARSER_TESTER : public std::unary_function<std::pair<std::string, bool>, void> {
+public:
+    RULES_PARSER_TESTER(RULES_PARSER & p) : parser(p),
+                                            testLog(),
+                                            testResult(),
+                                            result(true)
+        {
+        };
+    ~RULES_PARSER_TESTER()
+        {
+        PrintLog();
+        if (result)
+            exit(EXIT_SUCCESS);
+        exit(EXIT_FAILURE);
+        }
+    void operator()(const std::pair<std::string, bool> & entry)
+        {
+        testLog[entry.first].wantedError = entry.second;
+        testLog[entry.first].actualError = false;
+        testLog[entry.first].stdException = false;
+        testLog[entry.first].otherException = false;
+        testLog[entry.first].message = "";
+        testResult[entry.first] = true;
+        try
+            {
+            parser.SetFile(entry.first);
+            }
+        catch (std::exception & ex)
+            {
+            testLog[entry.first].stdException = true;
+            testResult[entry.first] &= false;
+            }
+        catch (...)
+            {
+            testLog[entry.first].otherException = true;
+            testResult[entry.first] &= false;
+            }
+        testLog[entry.first].actualError = parser.IsError();
+        testLog[entry.first].message = parser.ErrorMsg();
+        testResult[entry.first] &= (parser.IsError() == entry.second);
+        result &= testResult[entry.first];
+        };
+
+    void PrintLog()
+        {
+        std::cout << "RULES_PARSER_TESTER results:\n";
+        std::cout << "-----------------------------------------------------------------\n";
+        std::map<std::string, bool>::const_iterator it;
+        for (it = testResult.begin(); it != testResult.end(); ++it)
+            {
+            std::cout << "File: '" << it->first << "'\t"
+                      << "Correct: " << testLog[it->first].wantedError << "\t"
+                      << "Actual:" << testLog[it->first].actualError << "\t"
+                      << "STD exceptions: " << testLog[it->first].stdException << "\t"
+                      << "Other exceptions: " << testLog[it->first].otherException << "\t"
+                      << "Result: " << it->second << "\n";
+            if (!testLog[it->first].message.empty())
+                {
+                    std::cout << "Messages: \n" << testLog[it->first].message << "\n";
+                }
+            }
+        std::cout << "-----------------------------------------------------------------\n";
+        std::cout << "Final result: " << (result ? "passed" : "failed") << std::endl;
+        }
+
+    bool Result() const { return result; };
+private:
+    RULES_PARSER & parser;
+    std::map<std::string, TEST_INFO> testLog;
+    std::map<std::string, bool> testResult;
+    bool result;
+};
+
+int main(int argc, char ** argv)
+{
+RULES_PARSER parser;
+std::map<std::string, bool> tests;
+
+tests["./test_rules"] = false;
+tests["./rules"] = false;
+tests["./test_rules_bad_address"] = true;
+tests["./test_rules_bad_port"] = true;
+tests["./test_rules_bad_mask"] = true;
+tests["./test_rules_bad_proto"] = true;
+tests["./test_rules_bad_dir_prefix"] = true;
+tests["./test_rules_bad_dir_range"] = true;
+tests["./test_rules_bad_dir"] = true;
+
+/*parser.SetFile("./rules");
+std::cout << parser.ErrorMsg() << std::endl;*/
+
+// TODO: find errors and write checks for regression
+
+std::for_each(tests.begin(),
+             tests.end(),
+             RULES_PARSER_TESTER(parser));
+
+return EXIT_FAILURE;
+}
diff --git a/projects/traffcounter/table b/projects/traffcounter/table
new file mode 100644 (file)
index 0000000..5759561
--- /dev/null
@@ -0,0 +1,14 @@
+                | ips           | pendingPackets| sessions      | ip2sessions   | rules         |
+________________|_______________|_______________|_______________|_______________|_______________|
+SetRules        |               |               |               |               |       w       |
+________________|_______________|_______________|_______________|_______________|_______________|
+AddPacket       |       r       |       w       |               |               |               |
+________________|_______________|_______________|_______________|_______________|_______________|
+AddIP           |       w       |               |               |               |               |
+________________|_______________|_______________|_______________|_______________|_______________|
+GetIP           |               |               |       w       |       r       |               |
+________________|_______________|_______________|_______________|_______________|_______________|
+DeleteIP        |       w       |               |       w       |       w       |               |
+________________|_______________|_______________|_______________|_______________|_______________|
+Process         |               |       w       |       w       |       w       |       r       |
+________________|_______________|_______________|_______________|_______________|_______________|
diff --git a/projects/traffcounter/tc_packets.h b/projects/traffcounter/tc_packets.h
new file mode 100644 (file)
index 0000000..e0fa13d
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.3 $
+ $Date: 2009/04/10 14:14:49 $
+ $Author: faust $
+ */
+
+
+#ifndef __TC_PACKETS_H__
+#define __TC_PACKETS_H__
+
+#include <netinet/ip.h>
+
+#ifdef HAVE_STDINT
+    #include <stdint.h>
+#else
+    #ifdef HAVE_INTTYPES
+       #include <inttypes.h>
+    #else
+       #error "You need either stdint.h or inttypes.h to compile this!"
+    #endif
+#endif
+
+namespace STG
+{
+
+    //-----------------------------------------------------------------------------
+    /*
+     *  Session identifier
+     * A session is an amount of bytes transfered in one direction between two
+     * fixed addresses by one protocol.
+     * In case of UDP/TCP session is also identified by ports.
+     */
+    struct SESSION_ID
+    {
+    SESSION_ID()
+        : saddr(0),
+          daddr(0),
+          sport(0),
+          dport(0),
+          proto(0)
+        {
+        }
+
+    SESSION_ID(const iphdr & ipHdr, uint16_t sp, uint16_t dp)
+        : saddr(ipHdr.saddr),
+          daddr(ipHdr.daddr),
+          sport(sp),
+          dport(dp),
+          proto(ipHdr.protocol)
+        {
+        }
+
+    uint32_t    saddr;
+    uint32_t    daddr;
+    uint16_t    sport;
+    uint16_t    dport;
+    uint8_t     proto;
+
+    bool operator ==(const SESSION_ID & rval)
+        {
+        return saddr == rval.saddr &&
+               sport == rval.sport &&
+               daddr == rval.daddr &&
+               dport == rval.dport &&
+               proto == rval.proto;
+        }
+    };
+    //-----------------------------------------------------------------------------
+    /*
+     *  Ordering functor to use SESSION_ID as key-type in maps
+     */
+    struct SESSION_LESS 
+        : public std::binary_function<SESSION_ID, SESSION_ID, bool> {
+    bool operator()(const SESSION_ID & lval, const SESSION_ID & rval) const
+        {
+        if (lval.saddr > rval.saddr)
+            return false;
+        if (lval.saddr < rval.saddr)
+            return true;
+        if (lval.daddr > rval.daddr)
+            return false;
+        if (lval.daddr < rval.daddr)
+            return true;
+        if (lval.sport > rval.sport)
+            return false;
+        if (lval.sport < rval.sport)
+            return true;
+        if (lval.dport > rval.dport)
+            return false;
+        if (lval.dport < rval.dport)
+            return true;
+        if (lval.proto > rval.proto)
+            return false;
+        if (lval.proto < rval.proto)
+            return true;
+        return false;
+        };
+    };
+    //-----------------------------------------------------------------------------
+    /*
+     *  A packet in the incoming queue
+     * Can create a new session or be attached to an existing one
+     */
+    struct PENDING_PACKET : public SESSION_ID
+    {
+    PENDING_PACKET()
+        {
+        }
+    PENDING_PACKET(const iphdr & ipHdr, uint16_t sp, uint16_t dp)
+        : SESSION_ID(ipHdr, sp, dp),
+          length(ipHdr.tot_len),
+          direction(FOREIGN)
+        {
+        }
+
+    uint16_t    length;
+    enum DIRECTION
+        {
+        INCOMING = 0,   // From outer world to user
+        OUTGOING,       // From user to outer world
+        LOCAL,   // From user to user
+        FOREIGN         // From outer world to outer world
+        } direction;
+    };
+    //-----------------------------------------------------------------------------
+    /*
+     *  Session length and meta-information
+     * Used to identify data cost
+     */
+    struct SESSION_DATA
+    {
+    SESSION_DATA()
+        {
+        dir          = -1; // NULL direction
+        length       = 0;
+        };
+
+    SESSION_DATA(const SESSION_DATA & sp)
+        {
+        dir          = sp.dir;
+        length       = sp.length;
+        };
+
+    int         dir;
+    uint32_t    length;
+    };
+    //-----------------------------------------------------------------------------
+    /*
+     *  User-related types
+     */
+    typedef std::pair<SESSION_ID, SESSION_DATA> TRAFF_ITEM;
+    typedef std::list<TRAFF_ITEM> TRAFF_DATA;
+
+}
+
+#endif
diff --git a/projects/traffcounter/tc_tester.cpp b/projects/traffcounter/tc_tester.cpp
new file mode 100644 (file)
index 0000000..1ccc394
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ *  Network:
+ *   - server: 192.168.0.1
+ *   - user A: 192.168.0.2
+ *   - user B: 192.168.0.3
+ *
+ *  External resources:
+ *   - host 1: 216.239.59.104
+ *   - host 2: 72.14.221.104
+ *   - host 3: 66.249.93.104
+ *   - host 4: 195.5.61.68
+ *   
+ *  Directions:
+ *   - Local: ALL 192.168.0.0/24
+ *   - DNS: TCP_UDP 195.5.61.68/32:53
+ *   - FTP: TCP 129.22.8.159/32:20-21
+ *   - World: ALL 0.0.0.0/0
+ *
+ */
+
+
+
+#include <iostream>
+#include <algorithm>
+#include <functional>
+
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <sys/time.h>
+
+#include "rules.h"
+#include "traffcounter.h"
+#include "logger.h"
+
+using namespace std;
+using namespace STG;
+
+class StatPrinter: public unary_function<const TRAFF_ITEM &, void> {
+public:
+    void operator()(const TRAFF_ITEM & item) const
+    {
+        LOG_IT << inet_ntoa(*(in_addr *)(&item.first.saddr));
+        cout   << ":" << item.first.sport;
+        cout   << " -> " << inet_ntoa(*(in_addr *)(&item.first.daddr));
+        cout   << ":" << item.first.dport;
+        cout   << "\tproto: " << item.first.proto;
+        cout   << "\tlength: " << item.second.length;
+        cout   << endl;
+    }
+};
+
+STGLogger log;
+
+struct PACKET
+{
+    iphdr hdr;
+    uint16_t sport;
+    uint16_t dport;
+};
+
+RULE MakeRule(const string & ip,
+              const string & mask,
+              uint16_t port1,
+              uint16_t port2,
+              int proto,
+              int dir)
+{
+    RULE rule;
+
+    rule.ip = inet_addr(ip.c_str());
+    rule.mask = inet_addr(mask.c_str());
+    rule.port1 = port1;
+    rule.port2 = port2;
+    rule.proto = proto;
+    rule.dir = dir;
+
+    return rule;
+}
+
+RULES PrepareRules()
+{
+    RULES rules;
+    RULE local(MakeRule("192.168.0.0",
+                        "255.255.255.0",
+                        0,
+                        65535,
+                        -1,
+                        0));
+    RULE dns(MakeRule("195.5.61.68",
+                      "255.255.255.255",
+                      53,
+                      53,
+                      -1,
+                      1));
+    RULE ftp(MakeRule("129.22.8.159",
+                      "255.255.255.255",
+                      20,
+                      21,
+                      -1,
+                      2));
+    RULE world(MakeRule("0.0.0.0",
+                        "0.0.0.0",
+                        0,
+                        65535,
+                        -1,
+                        3));
+
+    rules.push_back(local);
+
+    rules.push_back(dns);
+
+    rules.push_back(ftp);
+
+    rules.push_back(world);
+
+    return rules;
+}
+
+iphdr MakePacket(const string & from,
+                 const string & to,
+                 int proto,
+                 uint16_t length)
+{
+    iphdr hdr;
+
+    hdr.ihl = 5;
+    hdr.version = 4;
+    hdr.tos = 0;
+    hdr.tot_len = length;
+    hdr.id = 0;
+    hdr.frag_off = 50;
+    hdr.ttl = 64;
+    hdr.protocol = proto;
+    hdr.check = 0;
+    hdr.saddr = inet_addr(from.c_str());
+    hdr.daddr = inet_addr(to.c_str());
+
+    return hdr;
+}
+
+void PrepareTraffic(vector<PACKET> & pckts,
+                    const iphdr & skel,
+                    uint16_t sport,
+                    uint16_t dport,
+                    uint32_t in,
+                    uint32_t out,
+                    int packets)
+{
+    PACKET inpacket;
+    PACKET outpacket;
+
+    inpacket.hdr = skel;
+    outpacket.hdr = skel;
+
+    outpacket.hdr.saddr ^= outpacket.hdr.daddr;
+    outpacket.hdr.daddr ^= outpacket.hdr.saddr;
+    outpacket.hdr.saddr ^= outpacket.hdr.daddr;
+
+    inpacket.sport = sport;
+    inpacket.dport = dport;
+    outpacket.sport = dport;
+    outpacket.dport = sport;
+
+    inpacket.hdr.tot_len = in / packets;
+    outpacket.hdr.tot_len = out / packets;
+
+    for (int i = 0; i < packets; ++i) {
+        //inpacket.hdr.daddr = outpacket.hdr.saddr = rand() * 32768 + rand();
+        pckts.push_back(inpacket);
+        pckts.push_back(outpacket);
+    }
+}
+
+struct TC_TESTER : public unary_function<const PACKET &, void>
+{
+public:
+    TC_TESTER(TRAFFCOUNTER & t)
+        : tc(t)
+    {}
+
+    void operator () (const PACKET & p)
+    {
+        tc.AddPacket(p.hdr, p.sport, p.dport);
+    }
+private:
+    TRAFFCOUNTER & tc;
+};
+
+int main()
+{
+    RULES rules(PrepareRules());
+
+    TRAFFCOUNTER tc;
+
+    vector<PACKET> packets;
+
+    tc.SetRules(rules);
+
+    if (tc.Start()) {
+        LOG_IT << "::main() Error: traffcounter not started" << endl;
+        return EXIT_FAILURE;
+    }
+
+    tc.AddIP(inet_addr("192.168.0.1")); // Server
+    tc.AddIP(inet_addr("192.168.0.2")); // User A
+    tc.AddIP(inet_addr("192.168.0.3")); // User B
+
+    for (int i = 0; i < 10000; ++i) {
+        tc.AddIP(rand() * 32768 + rand());
+    }
+
+    /*
+     * A -> S
+     * S -> A
+     * A -> B
+     * B -> A
+     * A -> h1
+     * h1 -> A
+     * A -> h2
+     * h2 -> A
+     * A -> h3
+     * h3 -> A
+     * A -> h4
+     * h4 -> A
+     */
+
+    timeval tv_from;
+    timeval tv_to;
+    gettimeofday(&tv_from, NULL);
+    // S - local, A - local
+    PrepareTraffic(packets, MakePacket("192.168.0.2", "192.168.0.1", 6, 0), 3215, 20, 1024 * 1024, 2048 * 1024, 512 * 2);
+    // S - local, B - local
+    PrepareTraffic(packets, MakePacket("192.168.0.3", "192.168.0.1", 6, 0), 5432, 22, 2048 * 1024, 1024 * 1024, 512 * 2);
+    // A - local, B - local
+    PrepareTraffic(packets, MakePacket("192.168.0.3", "192.168.0.2", 6, 0), 9875, 21, 2048 * 1024, 2048 * 1024, 512 * 2);
+    // A - DNS
+    //PrepareTraffic(packets, MakePacket("192.168.0.2", "195.5.61.68", 6, 0), 4521, 53, 1024 * 1024, 2048 * 1024, 512 * 2);
+    // A - World
+    //PrepareTraffic(packets, MakePacket("192.168.0.2", "195.5.61.68", 6, 0), 4521, 80, 1024 * 1024, 2048 * 1024, 512 * 2);
+    // A - FTP
+    //PrepareTraffic(packets, MakePacket("192.168.0.2", "129.22.8.159", 6, 0), 4522, 20, 512 * 1024, 512  * 1024, 512 * 2);
+    // A - FTP
+    //PrepareTraffic(packets, MakePacket("192.168.0.2", "129.22.8.159", 6, 0), 4522, 21, 512 * 1024, 4096 * 1024, 512 * 2);
+    // B - World
+    //PrepareTraffic(packets, MakePacket("192.168.0.3", "66.249.93.104", 6, 0), 3541, 80, 1024 * 1024, 1024 * 1024, 512 * 2);
+    gettimeofday(&tv_to, NULL);
+
+    uint64_t diff = tv_to.tv_sec - tv_from.tv_sec;
+    diff *= 1000000;
+    diff -= tv_from.tv_usec;
+    diff += tv_to.tv_usec;
+
+    LOG_IT << "::main() Prepared " << packets.size() << " packets by " << diff << " usecs" << endl;
+
+    gettimeofday(&tv_from, NULL);
+    for_each(packets.begin(),
+                  packets.end(),
+                  TC_TESTER(tc));
+    gettimeofday(&tv_to, NULL);
+
+    diff = tv_to.tv_sec - tv_from.tv_sec;
+    diff *= 1000000;
+    diff -= tv_from.tv_usec;
+    diff += tv_to.tv_usec;
+
+    LOG_IT << "::main() Recorded " << packets.size() << " packets by " << diff << " usecs" << endl;
+
+    int p;
+    while ((p = tc.PendingCount())) {
+        LOG_IT << "::main() Pending packets: " << p << " at " << time(NULL) << endl;
+        sleep(1);
+    }
+
+    TRAFF_DATA data;
+
+    tc.DeleteIP(inet_addr("192.168.0.1"), &data);
+    for_each(data.begin(),
+                  data.end(),
+                  StatPrinter());
+    data.erase(data.begin(), data.end());
+    tc.DeleteIP(inet_addr("192.168.0.2"), &data);
+    for_each(data.begin(),
+                  data.end(),
+                  StatPrinter());
+    data.erase(data.begin(), data.end());
+    tc.DeleteIP(inet_addr("192.168.0.3"), &data);
+    for_each(data.begin(),
+                  data.end(),
+                  StatPrinter());
+    data.erase(data.begin(), data.end());
+
+    if (tc.Stop()) {
+        LOG_IT << "::main() Error: traffcounter not stopped" << endl;
+        return EXIT_FAILURE;
+    }
+
+    LOG_IT << "::main() Sessions: " << tc.SessionsCount() << endl;
+    LOG_IT << "::main() Cache hits: " << tc.CacheHits() << endl;
+    LOG_IT << "::main() Cache misses: " << tc.CacheMisses() << endl;
+    LOG_IT << "::main() Stream quality: " << tc.StreamQuality() << endl;
+
+    return EXIT_SUCCESS;
+}
diff --git a/projects/traffcounter/test_rules b/projects/traffcounter/test_rules
new file mode 100644 (file)
index 0000000..bb36d93
--- /dev/null
@@ -0,0 +1,12 @@
+# foo bar baz
+
+UDP     10.0.0.0/24:1024-65535  DIR0 #blah-blah-blah
+
+TCP     192.168.1.1:21-22       DIR1
+
+ALL     192.168.2.0/16          DIR2
+
+GRE     192.168.3.0/24          NULL
+
+ALL     0.0.0.0                 DIR3
+
diff --git a/projects/traffcounter/test_rules_bad_address b/projects/traffcounter/test_rules_bad_address
new file mode 100644 (file)
index 0000000..7ab64ac
--- /dev/null
@@ -0,0 +1,7 @@
+
+UDP     10.0.0.0/24:1024-65535  DIR0
+
+TCP     192.168.1.1:21-22       DIR1
+ALL     192.168.2.0/16          DIR2
+ALL     0.0.0.a                 DIR3
+
diff --git a/projects/traffcounter/test_rules_bad_dir b/projects/traffcounter/test_rules_bad_dir
new file mode 100644 (file)
index 0000000..327f662
--- /dev/null
@@ -0,0 +1,7 @@
+
+UDP     10.0.0.0/24:1024-65535  DIR0
+
+TCP     192.168.1.1:21-22       DIRA
+ALL     192.168.2.0/16          DIR2
+ALL     0.0.0.0                 DIR3
+
diff --git a/projects/traffcounter/test_rules_bad_dir_prefix b/projects/traffcounter/test_rules_bad_dir_prefix
new file mode 100644 (file)
index 0000000..57489f3
--- /dev/null
@@ -0,0 +1,8 @@
+
+UDP     10.0.0.0/24:1024-65535  DIR0
+
+TCP     192.168.1.1:21-22       WOR1
+ALL     192.168.2.0/16          DIR2
+ALL     0.0.0.0                 DIR3
+
+
diff --git a/projects/traffcounter/test_rules_bad_dir_range b/projects/traffcounter/test_rules_bad_dir_range
new file mode 100644 (file)
index 0000000..9f63356
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+UDP     10.0.0.0/24:1024-65535  DIR0
+
+TCP     192.168.1.1:21-22       DIR8945298579834755982745892734958
+ALL     192.168.2.0/16          DIR2
+ALL     0.0.0.0                 DIR3
+
diff --git a/projects/traffcounter/test_rules_bad_mask b/projects/traffcounter/test_rules_bad_mask
new file mode 100644 (file)
index 0000000..60ebb1d
--- /dev/null
@@ -0,0 +1,7 @@
+
+UDP     10.0.0.0/2a:1024-65535  DIR0
+
+TCP     192.168.1.1:21-22       DIR1
+ALL     192.168.2.0/16          DIR2
+ALL     0.0.0.0                 DIR3
+
diff --git a/projects/traffcounter/test_rules_bad_port b/projects/traffcounter/test_rules_bad_port
new file mode 100644 (file)
index 0000000..93f246c
--- /dev/null
@@ -0,0 +1,7 @@
+
+UDP     10.0.0.0/24:1024-65535  DIR0
+
+TCP     192.168.1.1:21-2a       DIR1
+ALL     192.168.2.0/16          DIR2
+ALL     0.0.0.0                 DIR3
+
diff --git a/projects/traffcounter/test_rules_bad_proto b/projects/traffcounter/test_rules_bad_proto
new file mode 100644 (file)
index 0000000..8a19a03
--- /dev/null
@@ -0,0 +1,7 @@
+
+UDP     10.0.0.0/24:1024-65535  DIR0
+
+TCP     192.168.1.1:21-22       DIR1
+QMTSP     192.168.2.0/16          DIR2
+ALL     0.0.0.0                 DIR3
+
diff --git a/projects/traffcounter/traffcounter.cpp b/projects/traffcounter/traffcounter.cpp
new file mode 100644 (file)
index 0000000..baa999a
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ *    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>
+ */
+
+/*
+ $Revision: 1.5 $
+ $Date: 2009/10/12 08:43:32 $
+ $Author: faust $
+ */
+
+#include <csignal>
+#include <cassert>
+#include <algorithm>
+
+#include "traffcounter.h"
+#include "logger.h"
+#include "lock.h"
+#include "utils.h"
+
+//-----------------------------------------------------------------------------
+STG::TRAFFCOUNTER::TRAFFCOUNTER()
+    : rulesFinder(),
+      pendingPackets(),
+      sessions(),
+      cacheHits(0),
+      cacheMisses(0),
+      pendingCount(0),
+      maxPending(0),
+      ip2sessions(),
+      stopped(true),
+      running(false)
+{
+LOG_IT << "TRAFFCOUNTER::TRAFFCOUNTER()\n";
+pthread_mutex_init(&sessionMutex, NULL);
+pthread_mutex_init(&pendingMutex, NULL);
+pthread_mutex_init(&ipMutex, NULL);
+pthread_mutex_init(&rulesMutex, NULL);
+pthread_cond_init(&pendingCond, NULL);
+}
+//-----------------------------------------------------------------------------
+STG::TRAFFCOUNTER::~TRAFFCOUNTER()
+{
+LOG_IT << "TRAFFCOUNTER::~TRAFFCOUNTER()\n";
+pthread_cond_destroy(&pendingCond);
+pthread_mutex_destroy(&rulesMutex);
+pthread_mutex_destroy(&ipMutex);
+pthread_mutex_destroy(&pendingMutex);
+pthread_mutex_destroy(&sessionMutex);
+}
+//-----------------------------------------------------------------------------
+//  Starting processing thread
+bool STG::TRAFFCOUNTER::Start()
+{
+LOG_IT << "TRAFFCOUNTER::Start()\n";
+
+if (running)
+    return false;
+
+running = true;
+stopped = true;
+
+if (pthread_create(&thread, NULL, Run, this))
+    {
+    LOG_IT << "TRAFFCOUNTER::Start() Error: Cannot start thread!\n";
+    return true;
+    }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool STG::TRAFFCOUNTER::Stop()
+{
+LOG_IT << "TRAFFCOUNTER::Stop()\n";
+LOG_IT << "maxPending: " << maxPending << std::endl;
+
+if (!running)
+    return false;
+
+running = false;
+// Awake thread
+pthread_cond_signal(&pendingCond);
+
+//5 seconds to thread stops itself
+for (int i = 0; i < 25 && !stopped; ++i)
+    {
+    usleep(200000);
+    }
+
+//after 5 seconds waiting thread still running. now kill it
+if (!stopped)
+    {
+    LOG_IT << "TRAFFCOUNTER::Stop() Killing thread\n";
+    if (pthread_kill(thread, SIGINT))
+        {
+        return true;
+        }
+    LOG_IT << "TRAFFCOUNTER::Stop() Thread killed\n";
+    }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+double STG::TRAFFCOUNTER::StreamQuality() const
+{
+if (!cacheHits && !cacheMisses)
+    {
+    return 0;
+    }
+
+double quality = cacheHits;
+return quality / (quality + cacheMisses);
+}
+//-----------------------------------------------------------------------------
+void STG::TRAFFCOUNTER::AddPacket(const iphdr & ipHdr, uint16_t sport, uint16_t dport)
+{
+/*
+ *  Intersects with AddIP (from user thread), DeleteIP (from user thread) and
+ * Process (internal thread). AddPacket is calling from capturer's thread
+ *
+ *  ips is affected by AddIP (logarithmic lock time) and
+ *  DeleteIP (from user thread)
+ *
+ *  May be locked by AddIP or DeleteIP (from user thread)
+ *
+ *  Lock AddIP (user thread) or DeleteIP (user thread)
+ *  Logarithmic lock time
+ */
+
+bool srcExists;
+bool dstExists;
+
+    {
+    SCOPED_LOCK lock(ipMutex);
+    srcExists = std::binary_search(ips.begin(), ips.end(), ipHdr.saddr);
+    dstExists = std::binary_search(ips.begin(), ips.end(), ipHdr.daddr);
+    }
+
+if (!srcExists &&
+    !dstExists)
+    {
+    // Just drop the packet
+    return;
+    }
+
+STG::PENDING_PACKET p(ipHdr, sport, dport);
+
+// Packet classification
+if (srcExists)
+    {
+    if (dstExists)
+        {
+        // Both src and dst are countable
+        p.direction = PENDING_PACKET::LOCAL;
+        }
+    else
+        {
+        // Src is countable
+        p.direction = PENDING_PACKET::OUTGOING;
+        }
+    }
+else
+    {
+    if (dstExists)
+        {
+        // Dst is countable
+        p.direction = PENDING_PACKET::INCOMING;
+        }
+    else
+        {
+        assert(0);
+        // Not src nor dst are countable
+        p.direction = PENDING_PACKET::FOREIGN;
+        }
+    }
+
+/*
+ *  pendingPackets is affected by Process (from internal thread)
+ *
+ *  May be locked by Process (internal thread)
+ *
+ *  Lock Process (internal thread)
+ *  Constant lock time
+ */
+SCOPED_LOCK lock(pendingMutex);
+pendingPackets.push_back(p);
+pendingCount++;
+#ifdef STATISTIC
+if (pendingCount > maxPending)
+    maxPending = pendingCount;
+#endif
+pthread_cond_signal(&pendingCond);
+
+}
+//-----------------------------------------------------------------------------
+void STG::TRAFFCOUNTER::AddIP(uint32_t ip)
+{
+/*
+ *  AddIP is calling from users and affect DeleteIP and AddPacket.
+ * DeleteIP cannot be called concurrently with AddIP - it's the same
+ * thread. AddPacket is calling from capturer's thread - concurrently
+ * with AddIP.
+ *
+ * May be locked by AddPacket (from capturer's thread)
+ * Logarithmic lock time
+ *
+ * Lock AddPacket (capturer's thread)
+ * Logarithmic lock time
+ */
+SCOPED_LOCK lock(ipMutex);
+IP_ITER it(std::lower_bound(ips.begin(), ips.end(), ip));
+
+if (it != ips.end() && *it == ip)
+    {
+    return;
+    }
+// Insertion
+ips.insert(it, ip);
+}
+//-----------------------------------------------------------------------------
+void STG::TRAFFCOUNTER::DeleteIP(uint32_t ip, STG::TRAFF_DATA * traff)
+{
+/*
+ *  DeleteIP is calling from users and affect AddIP, AddPacket, GetIP and
+ * Process. AddIP and GetIP cannot be called concurrently with DeleteIP - it's
+ * the same thread. AddPacket is calling from capturer's thread - concurrently
+ * with DeleteIP. Process is calling from internal thread - concurrently with
+ * DeleteIP.
+ *
+ * May be locked by AddPacket (from capturer's thread)
+ * Logarithmic lock time
+ *
+ * Lock AddPacket (capturer's thread)
+ * Logarithmic lock time
+ */
+
+    {
+    SCOPED_LOCK lock(ipMutex);
+
+    IP_ITER it(std::lower_bound(ips.begin(), ips.end(), ip));
+    if (it == ips.end())
+        {
+        return;
+        }
+    if (*it != ip)
+        {
+        return;
+        }
+
+    ips.erase(it);
+    }
+
+// Get sessions for this ip
+std::pair<INDEX_ITER,
+          INDEX_ITER> range;
+
+SCOPED_LOCK lock(sessionMutex);
+range = ip2sessions.equal_range(ip);
+std::list<INDEX_ITER> toDelete;
+
+// Lock session growing
+for (INDEX_ITER it = range.first; it != range.second; ++it)
+    {
+    traff->push_back(STG::TRAFF_ITEM(it->second->first, it->second->second));
+
+    // Include self
+    toDelete.push_back(it);
+
+    /*if (ip == it->second->first.saddr)
+        {
+        toDelete.push_back(it->second->second.dIdx);
+        }
+    else
+        {
+        toDelete.push_back(it->second->second.sIdx);
+        }*/
+
+    --it->second->second.refCount;
+
+    // Remove session
+    /*
+     *  Normally we will lock here only in case of session between
+     *  two users from ips list
+     */
+    if (!it->second->second.refCount)
+        {
+        sessions.erase(it->second);
+        }
+    }
+
+// Remove indexes
+for (std::list<INDEX_ITER>::iterator it = toDelete.begin();
+     it != toDelete.end();
+     ++it)
+    {
+    ip2sessions.erase(*it);
+    }
+}
+//-----------------------------------------------------------------------------
+void STG::TRAFFCOUNTER::GetIP(uint32_t ip, STG::TRAFF_DATA * traff)
+{
+/*
+ *  Normally we will lock here only in case of session between
+ *  two users from ips list
+ */
+std::pair<INDEX_ITER,
+          INDEX_ITER> range;
+
+SCOPED_LOCK lock(sessionMutex);
+range = ip2sessions.equal_range(ip);
+std::list<INDEX_ITER> toDelete;
+
+// TODO: replace with foreach
+for (SESSION_INDEX::iterator it = range.first;
+     it != range.second;
+     ++it)
+    {
+    traff->push_back(STG::TRAFF_ITEM(it->second->first, it->second->second));
+    toDelete.push_back(it);
+    --it->second->second.refCount;
+    if (!it->second->second.refCount)
+        {
+        sessions.erase(it->second);
+        }
+    }
+
+for (std::list<INDEX_ITER>::iterator it = toDelete.begin();
+     it != toDelete.end();
+     ++it)
+    {
+    ip2sessions.erase(*it);
+    }
+}
+//-----------------------------------------------------------------------------
+void * STG::TRAFFCOUNTER::Run(void * data)
+{
+STG::TRAFFCOUNTER * tc = static_cast<STG::TRAFFCOUNTER *>(data);
+tc->stopped = false;
+
+while (tc->running)
+    {
+    STG::PENDING_PACKET packet;
+        {
+        SCOPED_LOCK lock(tc->pendingMutex);
+        if (tc->pendingPackets.empty())
+            {
+            pthread_cond_wait(&tc->pendingCond, &tc->pendingMutex);
+            }
+        if (!tc->running)
+            {
+            break;
+            }
+        packet = *tc->pendingPackets.begin();
+        tc->pendingPackets.pop_front();
+        --tc->pendingCount;
+        }
+    tc->Process(packet);
+    }
+
+tc->stopped = true;
+return NULL;
+}
+//-----------------------------------------------------------------------------
+void STG::TRAFFCOUNTER::Process(const STG::PENDING_PACKET & p)
+{
+// Bypass on stop
+if (!running)
+    return;
+
+// Fail on foreign packets
+if (p.direction == PENDING_PACKET::FOREIGN) {
+    assert(0);
+}
+
+// Searching a new packet in a tree.
+SESSION_ITER si;
+    {
+    SCOPED_LOCK lock(sessionMutex);
+    si = sessions.find(STG::SESSION_ID(p));
+    }
+
+// Packet found - update length and time
+if (si != sessions.end())
+    {
+    // Grow session
+    SCOPED_LOCK lock(sessionMutex);
+    si->second.length += p.length;
+    ++cacheHits;
+    return;
+    }
+
+++cacheMisses;
+
+// Packet not found - add new packet
+
+// This packet is alowed to create session
+STG::SESSION_ID sid(p);
+SESSION_FULL_DATA sd;
+
+// Identify a packet
+    {
+    SCOPED_LOCK lock(rulesMutex);
+    sd.dir = rulesFinder.GetDir(p);
+    }
+
+sd.length = p.length;
+
+if (p.direction == PENDING_PACKET::LOCAL)
+    {
+    sd.refCount = 2;
+    }
+else
+    {
+    sd.refCount = 1;
+    }
+
+// Create a session
+std::pair<SESSION_ITER,
+          bool> sIt(sessions.insert(std::make_pair(sid, sd)));
+    {
+    SCOPED_LOCK lock(sessionMutex);
+    std::pair<SESSION_ITER,
+              bool> sIt(sessions.insert(std::make_pair(sid, sd)));
+
+    // Create an indexes
+    sIt.first->second.sIdx = ip2sessions.insert(std::make_pair(p.saddr, sIt.first));
+    sIt.first->second.dIdx = ip2sessions.insert(std::make_pair(p.daddr, sIt.first));
+    }
+
+}
+//-----------------------------------------------------------------------------
+void STG::TRAFFCOUNTER::SetRules(const STG::RULES & data)
+{
+/*
+ *  SetRules is calling from outside internel thread. Process is calling
+ * from internal thread and calls DeterminateDir which use rules data.
+ *
+ * May be locked by DeterminateDir (Process) from internal thread.
+ *
+ * Lock DeterminateDir (Process) - internal thread.
+ * Linear lock time
+ */
+SCOPED_LOCK lock(rulesMutex);
+rulesFinder.SetRules(data);
+}
diff --git a/projects/traffcounter/traffcounter.h b/projects/traffcounter/traffcounter.h
new file mode 100644 (file)
index 0000000..418620b
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.3 $
+ $Date: 2009/04/10 14:15:46 $
+ $Author: faust $
+ */
+
+
+#ifndef TRAFFCOUNTER_H
+#define TRAFFCOUNTER_H
+
+#include <pthread.h>
+#include <netinet/ip.h>
+
+#ifdef HAVE_STDINT
+    #include <stdint.h>
+#else
+    #ifdef HAVE_INTTYPES
+        #include <inttypes.h>
+    #else
+        #error "You need either stdint.h or inttypes.h to compile this!"
+    #endif
+#endif
+
+#include <ctime>
+#include <list>
+#include <vector>
+#include <map>
+
+#include "rules.h"
+#include "rules_finder.h"
+#include "tc_packets.h"
+#include "user_tc_iface.h"
+#include "capturer_tc_iface.h"
+
+#define PACKET_TIMEOUT 300
+
+namespace STG
+{
+
+    class TRAFFCOUNTER : public IUSER_TC, public ICAPTURER_TC
+    {
+    public:
+        TRAFFCOUNTER();
+        ~TRAFFCOUNTER();
+
+        void            SetRules(const RULES & data);
+
+        bool            Start();
+        bool            Stop();
+
+        // Capturer API
+        void            AddPacket(const iphdr & ipHdr, uint16_t sport, uint16_t dport);
+
+        // User API
+        void            AddIP(uint32_t ip);
+        void            DeleteIP(uint32_t ip, TRAFF_DATA * traff);
+        void            GetIP(uint32_t ip, TRAFF_DATA * traff);
+
+        /*
+         * Stream quality represents a "scatterness" of data stream
+         * When sessions represend a large amount of information - it's a good
+         * stream. Most of common-use protocols (HTTP, FTP, etc.) shows a good
+         * stream quality.
+         * When there are a lot of packet that creates a new streams - it's a
+         * bad stream. p2p traffic has a bias to show a bad stream quality.
+         */
+        double          StreamQuality() const;
+        uint64_t        PendingCount() const { return pendingCount; };
+        uint64_t        SessionsCount() const { return sessions.size(); };
+        uint64_t        IndexesCount() const { return ip2sessions.size(); };
+        uint64_t        CacheHits() const { return cacheHits; };
+        uint64_t        CacheMisses() const { return cacheMisses; };
+
+    private:
+        static void *   Run(void * data);
+
+        void            Process(const PENDING_PACKET & p);
+
+        RULES_FINDER rulesFinder;
+
+        /*
+         * SESSION_INDEX: ip -> SESSION_ITER
+         * SESSIONS: SESSION_ID -> SESSION_DATA
+         *                -> SESSION_INDEX (saddr)
+         *                -> SESSION_INDEX (daddr)
+         */
+        struct SESSION_FULL_DATA; // Forward declaration
+        typedef std::map<SESSION_ID, SESSION_FULL_DATA, SESSION_LESS> SESSIONS;
+        typedef SESSIONS::iterator SESSION_ITER;
+        /*
+         *  This structure is used to take a fast session access by IP
+         * Normally, one IP can reffer multiple sessions. For each data stream there
+         * are 2 sessions: incoming data and outgoing data.
+         */
+        typedef std::multimap<uint32_t, SESSION_ITER> SESSION_INDEX;
+        typedef SESSION_INDEX::iterator INDEX_ITER;
+        /*
+         *  Append session meta-information with back-indexes
+         * In process of removing IP from TRAFFCOUNTER we need to remove indexes of
+         * sessions, reffered by this IP. To prevent slow searching by index tree we
+         * use 2 back-references: for source and destination IP.
+         */
+        struct SESSION_FULL_DATA : public SESSION_DATA
+        {
+            INDEX_ITER sIdx; // Back reference for fast index removing
+            INDEX_ITER dIdx; // Back reference for fast index removing
+            int        refCount; // Reference count for packet removing
+        };
+
+        std::list<PENDING_PACKET> pendingPackets;
+
+        SESSIONS sessions; // A map with sessions data
+
+        /*
+         * When pending packet appends a session - it's a "cache hit"
+         * When pending packet creates a new session - it's a "cache miss"
+         */
+        uint64_t cacheHits;
+        uint64_t cacheMisses;
+        uint64_t pendingCount;
+        uint64_t maxPending;
+
+        SESSION_INDEX ip2sessions; // IP index for sessions data
+
+        /*
+         * A sorted vector of allowed/disallowed ips
+         */
+        std::vector<uint32_t> ips;
+        typedef std::vector<uint32_t>::iterator IP_ITER;
+
+        bool        stopped;
+        bool        running;
+
+        mutable pthread_mutex_t         sessionMutex; // For sessions
+        mutable pthread_mutex_t         pendingMutex; // For pendinPackets
+        mutable pthread_cond_t          pendingCond;  //
+        mutable pthread_mutex_t         ipMutex;      // For ip list
+        mutable pthread_mutex_t         rulesMutex;   // For rules list
+        pthread_t               thread;
+
+    };
+
+}
+
+#endif //TRAFFCOUNTER_H
diff --git a/projects/traffcounter/user_tc_iface.h b/projects/traffcounter/user_tc_iface.h
new file mode 100644 (file)
index 0000000..d70034a
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __USER_TC_IFACE_H__
+#define __USER_TC_IFACE_H__
+
+#ifdef HAVE_STDINT
+    #include <stdint.h>
+#else
+    #ifdef HAVE_INTTYPES
+        #include <inttypes.h>
+    #else
+        #error "You need either stdint.h or inttypes.h to compile this!"
+    #endif
+#endif
+
+#include "tc_packets.h"
+
+namespace STG
+{
+
+    class IUSER_TC
+    {
+    public:
+        virtual ~IUSER_TC() {};
+        virtual void AddIP(uint32_t) = 0;
+        virtual void DeleteIP(uint32_t, TRAFF_DATA *) = 0;
+        virtual void GetIP(uint32_t, TRAFF_DATA *) = 0;
+    };
+
+}
+
+#endif
diff --git a/projects/traffcounter/utils.cpp b/projects/traffcounter/utils.cpp
new file mode 100644 (file)
index 0000000..ac8634c
--- /dev/null
@@ -0,0 +1,55 @@
+#include <algorithm>
+#include <functional>
+
+#include <iostream>
+#include <cerrno>
+#include <cstring>
+
+#include <arpa/inet.h>
+
+#include "utils.h"
+
+using namespace std;
+
+string STG::ToLower(const string & val, const locale & loc)
+{
+    std::string res;
+    transform(val.begin(),
+             val.end(),
+             back_inserter(res),
+             STG::ToLowerHelper(loc));
+    return res;
+}
+
+string STG::ToUpper(const string & val, const locale & loc)
+{
+    std::string res;
+    transform(val.begin(),
+             val.end(),
+             back_inserter(res),
+             STG::ToUpperHelper(loc));
+    return res;
+}
+
+string STG::Trim(const string & val, const locale & loc)
+{
+    if (val.empty())
+        return std::string();
+    string::const_iterator first(find_if(
+               val.begin(),
+               val.end(),
+               STG::IsNotSpace(loc)));
+    string::const_reverse_iterator last(find_if(
+               val.rbegin(),
+               val.rend(),
+               STG::IsNotSpace(loc)));
+    if (first == val.end())
+        return std::string();
+    return std::string(first, last.base());
+}
+std::string inet_ntostring(uint32_t ip)
+{
+    char buf[INET_ADDRSTRLEN + 1];
+
+    return inet_ntop(AF_INET, &ip, buf, INET_ADDRSTRLEN);
+}
diff --git a/projects/traffcounter/utils.h b/projects/traffcounter/utils.h
new file mode 100644 (file)
index 0000000..92d32e7
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <string>
+#include <locale>
+
+namespace STG
+{
+
+class IsNotSpace : public std::unary_function<bool, char> {
+public:
+    IsNotSpace(const std::locale & l) : loc(l) {};
+    bool operator() (char c)
+        {
+        return !std::use_facet<casefacet>(loc).is(std::ctype_base::space, c);
+        };
+private:
+    const std::locale & loc;
+
+    typedef std::ctype<char> casefacet;
+};
+
+class ToLowerHelper : public std::unary_function<char, char> {
+public:
+    ToLowerHelper(const std::locale & l) : loc(l) {};
+    char operator() (char c)
+        {
+        return std::tolower(c, loc);
+        };
+private:
+    const std::locale & loc;
+};
+
+class ToUpperHelper : public std::unary_function<char, char> {
+public:
+    ToUpperHelper(const std::locale & l) : loc(l) {};
+    char operator() (char c)
+        {
+        return std::toupper(c, loc);
+        };
+private:
+    const std::locale & loc;
+};
+
+std::string Trim(const std::string & val, const std::locale & loc);
+std::string ToLower(const std::string & val, const std::locale & loc);
+std::string ToUpper(const std::string & val, const std::locale & loc);
+
+inline std::string Trim(const std::string & val)
+    {
+    return Trim(val, std::locale(""));
+    }
+
+inline std::string ToLower(const std::string & val)
+    {
+    return ToLower(val, std::locale(""));
+    }
+
+inline std::string ToUpper(const std::string & val)
+    {
+    return ToUpper(val, std::locale(""));
+    }
+
+}
+
+std::string inet_ntostring(uint32_t ip);
+
+#endif
diff --git a/stglibs/Makefile b/stglibs/Makefile
new file mode 100644 (file)
index 0000000..f7d5e45
--- /dev/null
@@ -0,0 +1,22 @@
+###############################################################################
+# $Id: Makefile,v 1.7 2008/03/10 14:00:00 faust Exp $
+###############################################################################
+
+include ../Makefile.conf
+
+.PHONY: all $(STG_LIBS)
+.PHONY: clean install uninstall includes
+all: $(STG_LIBS)
+
+$(STG_LIBS):
+       $(MAKE) $(MAKECMDGOALS) -C $@
+
+includes: all
+
+clean: all
+       rm -f $(DIR_LIB)/*
+
+install: all
+
+uninstall: all
+
diff --git a/stglibs/Makefile.in b/stglibs/Makefile.in
new file mode 100644 (file)
index 0000000..0c42dd5
--- /dev/null
@@ -0,0 +1,94 @@
+###############################################################################
+# $Id: Makefile.in,v 1.28 2009/03/03 15:50:14 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+PROG = lib$(LIB_NAME).so
+
+ifeq ($(PROT), on)
+DEFS += -DLINPROT
+endif
+
+ifeq ($(DEMO), on)
+DEFS += -DDEMO
+endif
+
+ifeq ($(OS), bsd)
+    ifeq ($(PROT), on)
+    DEFS += -DFREEBDSPROT
+    endif
+MAKE = gmake
+endif
+
+ifeq ($(OS), bsd5)
+    ifeq ($(PROT), on)
+    DEFS += -DFREEBDSPROT
+    endif
+MAKE = gmake
+endif
+
+ifeq ($(STG_TIME), yes)
+DEFS += -DSTG_TIME
+endif
+
+ifneq ($(ADD_DEFS_1),)
+DEFS += $(ADD_DEFS_1)
+endif
+
+SEARCH_DIRS = -I $(DIR_INCLUDE) -I ./
+
+OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))))
+
+INST_INCS = $(addprefix $(DIR_INCLUDE)/, $(notdir $(INCS)))
+INST_LIBS = $(DIR_LIB)/lib$(LIB_NAME)
+
+CXXFLAGS += -fPIC
+LDFLAGS += -shared -Wl,-rpath,$(PREFIX)/usr/lib/stg
+
+ifneq ($(ADD_CXXFLAGS_1),)
+CXXFLAGS += $(ADD_CXXFLAGS_1)
+endif
+
+vpath %.so $(DIR_LIB)
+
+all: $(PROG)
+
+$(PROG): $(OBJS) $(STGLIBS)
+       g++ $(LDFLAGS) -Wl,-soname,$(PROG) $^ $(LIBS) -o $(PROG) -L $(DIR_LIB) 
+       ar rc lib$(LIB_NAME).a $(OBJS)
+       ranlib lib$(LIB_NAME).a
+       cp *.so $(DIR_LIB)
+       cp *.a $(DIR_LIB)
+
+includes: $(INCS)
+       cp -p $(INCS) $(DIR_INCLUDE)
+
+clean:
+       rm -f deps $(PROG) *.o *.a *.so tags *.*~ 
+       for file in $(INCS); do \
+           rm -f $(DIR_INCLUDE)/$$file; \
+       done
+
+install: $(PROG)
+       mkdir -m $(BIN_MODE) -p $(PREFIX)/usr/lib/stg
+       install -m $(BIN_MODE) -o $(OWNER) -s $(PROG) $(PREFIX)/usr/lib/stg/$(PROG)
+
+uninstall:
+       rm -f $(PREFIX)/usr/lib/stg/$(PROG)
+
+ifneq ($(MAKECMDGOALS),includes)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+-include deps
+endif
+endif
+endif
+
+deps:  $(SRCS) ../../Makefile.conf
+       @>deps ;\
+       for file in $(SRCS); do\
+         echo "`$(CC) $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS) -MM -MG $$file` Makefile ../../Makefile.conf" >> deps ;\
+         echo -e '\t$$(CC) $(CXXFLAGS) $(SEARCH_DIRS) $(DEFS) -c $$<' >> deps ;\
+       done
+
diff --git a/stglibs/common.lib/Makefile b/stglibs/common.lib/Makefile
new file mode 100644 (file)
index 0000000..d1c816b
--- /dev/null
@@ -0,0 +1,23 @@
+###############################################################################
+# $Id: Makefile,v 1.9 2010/01/21 13:02:12 faust Exp $
+###############################################################################
+
+include ../../Makefile.conf
+
+LIB_NAME = stg_common
+PROG = lib$(LIB_NAME)
+
+SRCS = debug.c \
+       stg_error.c \
+       common.cpp \
+       stg_strptime.cpp
+
+INCS = debug.h \
+       stg_error.h \
+       common.h
+
+ifneq ($(OS),linux)
+LIBS += -liconv
+endif
+
+include ../Makefile.in
diff --git a/stglibs/common.lib/common.bpf b/stglibs/common.lib/common.bpf
new file mode 100644 (file)
index 0000000..e3c42ce
--- /dev/null
@@ -0,0 +1,9 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+#define Library
+
+// To add a file to the library use the Project menu 'Add to Project'.
+
\ No newline at end of file
diff --git a/stglibs/common.lib/common.bpr b/stglibs/common.lib/common.bpr
new file mode 100644 (file)
index 0000000..d7cb659
--- /dev/null
@@ -0,0 +1,130 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+  <MACROS>
+    <VERSION value="BCB.06.00"/>
+    <PROJECT value="..\..\lib\common.lib"/>
+    <OBJFILES value="common.obj"/>
+    <RESFILES value=""/>
+    <IDLFILES value=""/>
+    <IDLGENFILES value=""/>
+    <DEFFILE value=""/>
+    <RESDEPEN value="$(RESFILES)"/>
+    <LIBFILES value=""/>
+    <LIBRARIES value=""/>
+    <PACKAGES value=""/>
+    <PATHCPP value=".;"/>
+    <PATHPAS value=".;"/>
+    <PATHRC value=".;"/>
+    <PATHASM value=".;"/>
+    <LINKER value="TLib"/>
+    <USERDEFINES value="_DEBUG;WIN32"/>
+    <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
+    <MAINSOURCE value="common.bpf"/>
+    <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl;..\..\include"/>
+    <LIBPATH value="$(BCB)\lib\obj;$(BCB)\lib;..\..\lib"/>
+    <WARNINGS value="-w-par"/>
+    <LISTFILE value=""/>
+    <OTHERFILES value=""/>
+  </MACROS>
+  <OPTIONS>
+    <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -I..\..\include -src_suffix cpp 
+      -D_DEBUG -DWIN32 -boa"/>
+    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c 
+      -tW -tWM"/>
+    <PFLAGS value="-$YD -$W -$O- -$A8 -v -JPHNE -M"/>
+    <AFLAGS value="/mx /w2 /zd"/>
+    <LFLAGS value=""/>
+    <OTHERFILES value=""/>
+  </OPTIONS>
+  <LINKER>
+    <ALLOBJ value="$(OBJFILES)"/>
+    <ALLLIB value=""/>
+    <OTHERFILES value=""/>
+  </LINKER>
+  <FILELIST>
+      <FILE FILENAME="common.bpf" FORMNAME="" UNITNAME="common" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="common.cpp" FORMNAME="" UNITNAME="common.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="common.h" FORMNAME="" UNITNAME="common.h" CONTAINERID="" DESIGNCLASS="" LOCALCOMMAND=""/>
+  </FILELIST>
+  <BUILDTOOLS>
+  </BUILDTOOLS>
+
+  <IDEOPTIONS>
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1049
+CodePage=1251
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include;$(BCB)\include\vcl;..\..\include
+Item1=$(BCB)\include;$(BCB)\include\vcl
+
+[HistoryLists\hlLibraryPath]
+Count=2
+Item0=$(BCB)\lib\obj;$(BCB)\lib;..\..\lib
+Item1=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[HistoryLists\hlConditionals]
+Count=2
+Item0=_DEBUG;WIN32
+Item1=_DEBUG
+
+[HistoryLists\hlFinalOutputDir]
+Count=2
+Item0=..\..\lib\
+Item1=..\..\lib
+
+[Debugging]
+DebugSourceDirs=$(BCB)\source\vcl
+
+[Parameters]
+RunParams=
+Launcher=
+UseLauncher=0
+DebugCWD=
+HostApplication=
+RemoteHost=
+RemotePath=
+RemoteLauncher=
+RemoteCWD=
+RemoteDebug=0
+
+[Compiler]
+ShowInfoMsgs=0
+LinkDebugVcl=0
+LinkCGLIB=0
+
+[CORBA]
+AddServerUnit=1
+AddClientUnit=1
+PrecompiledHeaders=1
+  </IDEOPTIONS>
+</PROJECT>
\ No newline at end of file
diff --git a/stglibs/common.lib/common.cpp b/stglibs/common.lib/common.cpp
new file mode 100644 (file)
index 0000000..a5899dd
--- /dev/null
@@ -0,0 +1,885 @@
+/*
+ *    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>
+ */
+
+ /*
+ $Revision: 1.41 $
+ $Date: 2010/11/03 10:26:30 $
+ $Author: faust $
+ */
+
+
+/*#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <iconv.h>
+
+
+#include <stdarg.h>
+
+
+#include <sys/types.h>
+#include <math.h>
+
+#ifdef WIN32
+#include <sysutils.hpp>
+#else
+#include <unistd.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#endif*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <iconv.h>
+
+#include <cstdlib>
+#include <cstdarg>
+#include <cstdio>
+#include <cstring>
+#include <cerrno>
+#include <cassert>
+
+#include "common.h"
+
+#ifndef INET_ADDRSTRLEN
+#   define INET_ADDRSTRLEN 16
+#endif
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+int strtodouble2(const char * s, double &a)
+{
+char *res;
+
+a = strtod(s, &res);
+
+if (*res != 0)
+    return EINVAL;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+#ifdef DEBUG
+int printfd(const char * __file__, const char * fmt, ...)
+#else
+int printfd(const char *, const char *, ...)
+#endif
+{
+#ifdef DEBUG
+char buff[1024];
+
+time_t t = time(NULL);
+
+va_list vl;
+va_start(vl, fmt);
+vsnprintf(buff, sizeof(buff), fmt, vl);
+va_end(vl);
+
+printf("%18s > %s > ", __file__, LogDate(t)+11);
+printf("%s", buff);
+
+#endif
+return 0;
+}
+//-----------------------------------------------------------------------------
+int strprintf(string * str, const char * fmt, ...)
+{
+char buff[1024];
+
+va_list vl;
+va_start(vl, fmt);
+int n = vsnprintf(buff, sizeof(buff), fmt, vl);
+va_end(vl);
+buff[1023] = 0;
+*str = buff;
+
+return n;
+}
+//-----------------------------------------------------------------------------
+const char *IntToKMG(long long a, int stat)
+{
+static int64_t M = 1024*1024;
+static int64_t G = 1024*1024*1024;
+static char str[30];
+
+switch (stat)
+    {
+    case ST_B:
+        #ifdef __WIN32__
+        sprintf(str, "%Ld", a);
+        #else
+        sprintf(str, "%lld", a);
+        #endif
+        break;
+    case ST_KB:
+        sprintf(str, "%.2f kb", double(a)/1024.0);
+        break;
+    case ST_MB:
+        sprintf(str, "%.2f Mb", double(a)/(1024.0*1024.0));
+        break;
+    default:
+        if (a > G)
+            {
+            sprintf(str, "%.2f Gb", double(a)/double(G));
+            return &str[0];
+            }
+        if (a < -G)
+            {
+            sprintf(str, "%.2f Gb", double(a)/double(G));
+            return &str[0];
+            }
+        if (a > M)
+            {
+            sprintf(str, "%.2f Mb", double(a)/double(M));
+            return &str[0];
+            }
+        if (a < -M)
+            {
+            sprintf(str, "%.2f Mb", double(a)/double(M));
+            return &str[0];
+            }
+
+        sprintf(str, "%.2f kb", double(a)/1024.0);
+        break;
+    }
+return str;
+}
+//---------------------------------------------------------------------------
+unsigned char koi2win[] = {
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+        0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+        0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+        0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+        0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+        0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+        0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+        0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+        0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+        0xA0, 0xA1, 0xA2, 0xB8, 0xBA, 0xA5, 0xB3, 0xBF,
+        0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xB4, 0xAE, 0xAF,
+        0xB0, 0xB1, 0xB2, 0xA8, 0xAA, 0xB5, 0xB2, 0xAF,
+        0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xA5, 0xBE, 0xBF,
+        0xFE, 0xE0, 0xE1, 0xF6, 0xE4, 0xE5, 0xF4, 0xE3,
+        0xF5, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE,
+        0xEF, 0xFF, 0xF0, 0xF1, 0xF2, 0xF3, 0xE6, 0xE2,
+        0xFC, 0xFB, 0xE7, 0xF8, 0xFD, 0xF9, 0xF7, 0xFA,
+        0xDE, 0xC0, 0xC1, 0xD6, 0xC4, 0xC5, 0xD4, 0xC3,
+        0xD5, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE,
+        0xCF, 0xDF, 0xD0, 0xD1, 0xD2, 0xD3, 0xC6, 0xC2,
+        0xDC, 0xDB, 0xC7, 0xD8, 0xDD, 0xD9, 0xD7, 0xDA};
+
+
+unsigned char win2koi[] = {
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+        0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+        0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+        0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+        0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+        0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+        0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+        0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+        0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xBD, 0xA6, 0xA7,
+        0xB3, 0xA9, 0xB4, 0xAB, 0xAC, 0xAD, 0xAE, 0xB7,
+        0xB0, 0xB1, 0xB6, 0xA6, 0xAD, 0xB5, 0xB6, 0xB7,
+        0xA3, 0xB9, 0xA4, 0xBB, 0xBC, 0xBD, 0xBE, 0xA7,
+        0xE1, 0xE2, 0xF7, 0xE7, 0xE4, 0xE5, 0xF6, 0xFA,
+        0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0,
+        0xF2, 0xF3, 0xF4, 0xF5, 0xE6, 0xE8, 0xE3, 0xFE,
+        0xFB, 0xFD, 0xFF, 0xF9, 0xF8, 0xFC, 0xE0, 0xF1,
+        0xC1, 0xC2, 0xD7, 0xC7, 0xC4, 0xC5, 0xD6, 0xDA,
+        0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0,
+        0xD2, 0xD3, 0xD4, 0xD5, 0xC6, 0xC8, 0xC3, 0xDE,
+        0xDB, 0xDD, 0xDF, 0xD9, 0xD8, 0xDC, 0xC0, 0xD1};
+//---------------------------------------------------------------------------
+void KOIToWin(const char * s1, char * s2, int l)
+{
+unsigned char t;
+for (int j = 0; j < l; j++)
+    {
+    t = s1[j];
+    s2[j] = koi2win[t];
+
+    if (s1[j] == 0)
+        break;
+    }
+}
+//---------------------------------------------------------------------------
+void WinToKOI(const char * s1, char * s2, int l)
+{
+unsigned char t;
+for (int j = 0; j < l; j++)
+    {
+    t = s1[j];
+    s2[j] = win2koi[t];
+
+    if (s1[j] == 0)
+        break;
+    }
+}
+//---------------------------------------------------------------------------
+void KOIToWin(const string & s1, string * s2)
+{
+s2->erase(s2->begin(), s2->end());
+unsigned char t;
+s2->reserve(s1.length());
+for (int j = 0; j < (int)s1.length(); j++)
+    {
+    t = s1[j];
+    s2->push_back(koi2win[t]);
+    }
+}
+//---------------------------------------------------------------------------
+void WinToKOI(const string & s1, string * s2)
+{
+s2->erase(s2->begin(), s2->end());
+unsigned char t;
+s2->reserve(s1.length());
+for (int j = 0; j < (int)s1.length(); j++)
+    {
+    t = s1[j];
+    s2->push_back(win2koi[t]);
+    }
+}
+//---------------------------------------------------------------------------
+void Encode12str(string & dst, const string & src)
+{
+dst.erase(dst.begin(), dst.end());
+for (size_t i = 0; i < src.length(); i++)
+    {
+    dst.push_back('a' + (src[i] & 0x0f));
+    dst.push_back('a' + ((src[i] & 0xf0) >> 4));
+    }
+}
+//---------------------------------------------------------------------------
+void Decode21str(std::string & dst, const std::string & src)
+{
+dst.erase(dst.begin(), dst.end());
+for (size_t i = 0; i < src.length() / 2; i++)
+    {
+    char c1 = src[i * 2];
+    char c2 = src[i * 2 + 1];
+
+    c1 -= 'a';
+    c2 -= 'a';
+
+    dst.push_back(c1 + (c2 << 4));
+    }
+}
+//---------------------------------------------------------------------------
+void Encode12(char * dst, const char * src, size_t srcLen)
+{
+for (size_t i = 0; i <= srcLen; i++)
+    {
+    if (src[i] == 0)
+        {
+        dst[i * 2] = 'a';
+        dst[i * 2 + 1] = 'a';
+        break;
+        }
+    char c1 = src[i] & 0x0f;
+    char c2 = (src[i] & 0xf0) >> 4;
+
+    c1 += 'a';
+    c2 += 'a';
+
+    dst[i * 2] = c1;
+    dst[i * 2 + 1] = c2;
+    }
+dst[srcLen * 2] = 0;
+}
+//---------------------------------------------------------------------------
+void Decode21(char * dst, const char * src)
+{
+for (size_t i = 0; ; i++)
+    {
+    if (src[i * 2] == 0)
+        break;
+
+    char c1 = src[i * 2];
+    char c2 = src[i * 2 + 1];
+
+    c1 -= 'a';
+    c2 -= 'a';
+
+    dst[i] = c1 + (c2 << 4);
+    }
+dst[strlen(src) / 2] = 0;
+}
+//---------------------------------------------------------------------------
+int ParseIPString(const char * str, uint32_t * ips, int maxIP)
+{
+/*
+ *Function Name:ParseIPString
+ *
+ *Parameters:
+ ÓÔÒÏËÁ ÄÌÑ ÒÁÚÂÏÒÁ É ÍÁÓÓÉ× ËÕÄÁ ÚÁÎÏÓÉÔØ ÐÏÌÕÞÅÎÎÙÅ ÁÄÒÅÓÁ
+ *
+ *Description:
+ îÁ ×ÈÏÄÅ ÄÏÌÖÎÁ ÂÙÔØ ÓÔÒÏËÁ ×ÉÄÁ "ip1,ip2,ip3" ÉÌÉ "*"
+ ÷ ÐÅÒ×ÏÍ ÓÌÕÞÁÅ × ÍÁÓÓÉ× ÚÁÎÏÓÑÔÓÑ ÒÁÚÏÂÒÁÎÎÙÅ ÁÄÒÅÓÁ.
+ åÓÌÉ ÉÈ ÍÅÎØÛÅ MAX_IP?, ÔÏ ÐÏÓÌÅÄÎÉÊ ÁÄÒÅÓ ÂÕÄÅÔ 255.255.255.255
+ åÓÌÉ ÓÔÒÏËÁ * , ÔÏ ÐÅÒ×ÁÙÊ ÁÄÒÅÓ ÂÕÄÅÔ 0.0.0.0, Ô.Å. ÌÀÂÏÊ
+ *
+ *Returns: 0 ÅÓÌÉ ×ÓÅ ïë
+ *
+ */
+
+char p[255];
+char * p1, *pp;
+int n = 0;
+
+strncpy(p, str, 254);
+pp = p;
+
+memset(ips, 0xFF, sizeof(unsigned long) * maxIP);
+
+if (str[0] == '*' && strlen(str) == 1)
+    {
+    ips[0] = 0;
+    return 0;
+    }
+
+for (int i = 0; i < maxIP; i++)
+    {
+    p1 = strtok(pp, ",\n ");
+    pp = NULL;
+
+    if (p1 == NULL && n == 0)// ÕËÁÚÁÔÅÌØ ÎÕÌØ É ÐÒÏÞÉÔÁÎÏ ÁÄÒÅÓÏ× ÔÏÖÅ ÎÏÌØ
+        {
+        return EINVAL;
+        }
+
+    if (p1 == NULL && n)
+        {
+        return 0;
+        }
+
+    struct in_addr in;
+    if (!inet_aton(p1, &in))
+        {
+        //printf("INADDR_NONE\n");
+        return EINVAL;
+        }
+
+    ips[n] = in.s_addr;
+
+    /*if (ips[n] == INADDR_NONE)
+        return EINVAL;*/
+
+    n++;
+
+    if (n >= maxIP)
+        return 0;
+
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int DaysInCurrentMonth()
+{
+time_t t = time(NULL);
+
+struct tm * lt = localtime(&t);
+
+return DaysInMonth(lt->tm_year, lt->tm_mon);
+}
+//-----------------------------------------------------------------------------
+int DaysInMonth(unsigned year, unsigned mon)
+{
+assert(mon < 12 && "Month number should be 0 - 11");
+switch (mon)
+    {
+    case 0: return 31;  //jan
+    case 1:
+        if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+            return 29;
+        return 28;      //feb
+    case 2: return 31;  //mar
+    case 3: return 30;  //apr
+    case 4: return 31;  //may
+    case 5: return 30;  //june
+    case 6: return 31;  //jule
+    case 7: return 31;  //aug
+    case 8: return 30;  //sep
+    case 9: return 31;  //oct
+    case 10: return 30; //nov
+    case 11: return 31; //dec
+    }
+return -1; // We will never reach here
+}
+//-----------------------------------------------------------------------------
+int Min8(int a)
+{
+/*
+æÕÎËÃÉÑ ×ÏÚ×ÒÁÝÁÅÔ ÎÁÉÍÅÎØÛÅÅ ÞÉÓÌÏ ËÒÁÔÎÏÅ 8-ÍÉ ÂÏÌØÛÅÅ ÉÌÉ ÒÁ×ÎÏÅ ÚÁÄÁÎÎÏÍÕ
+ * */
+if (a % 8 == 0)
+    return a;
+
+return a + (8 - a % 8);
+}
+//-----------------------------------------------------------------------------
+/*char * inet_ntostr(unsigned long ip)
+{
+struct in_addr addr = {ip};
+return inet_ntoa(addr);
+}*/
+//-----------------------------------------------------------------------------
+std::string inet_ntostring(uint32_t ip)
+{
+    char buf[INET_ADDRSTRLEN + 1];
+    return inet_ntop(AF_INET, &ip, buf, INET_ADDRSTRLEN);
+}
+//-----------------------------------------------------------------------------
+uint32_t inet_strington(const std::string & value)
+{
+    uint32_t result;
+
+    if (inet_pton(AF_INET, value.c_str(), &result) <= 0)
+        return 0;
+
+    return result;
+}
+//-----------------------------------------------------------------------------
+int ParseTariffTimeStr(const char * str, int &h1, int &m1, int &h2, int &m2)
+{
+char hs1[10], ms1[10], hs2[10], ms2[10];
+char s1[25], s2[25];
+char ss[49];
+char *p1, *p2;
+
+strncpy(ss, str, 48);
+
+p1 = strtok(ss, "-");
+if (!p1)
+    return -1;
+
+strncpy(s1, p1, 24);
+
+p2 = strtok(NULL, "-");
+if (!p2)
+    return -1;
+
+strncpy(s2, p2, 24);
+
+p1 = strtok(s1, ":");
+if (!p1)
+    return -1;
+
+strncpy(hs1, p1, 9);
+
+p2 = strtok(NULL, ":");
+if (!p2)
+    return -1;
+
+strncpy(ms1, p2, 9);
+
+p1 = strtok(s2, ":");
+if (!p1)
+    return -1;
+
+strncpy(hs2, p1, 9);
+
+p2 = strtok(NULL, ":");
+if (!p2)
+    return -1;
+
+strncpy(ms2, p2, 9);
+
+if (str2x(hs1, h1) != 0)
+    return -1;
+
+if (str2x(ms1, m1) != 0)
+    return -1;
+
+if (str2x(hs2, h2) != 0)
+    return -1;
+
+if (str2x(ms2, m2) != 0)
+    return -1;
+
+return 0;
+}
+/*//---------------------------------------------------------------------------
+bool IsDigit(char c)
+{
+if (c >= '0' && c <= '9')
+    return true;
+return false;
+}
+//-----------------------------------------------------------------------------
+bool IsAlpha(char c)
+{
+if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+    return true;
+return false;
+}*/
+//-----------------------------------------------------------------------------
+const char * LogDate(time_t t)
+{
+static char s[32];
+struct tm * tt = localtime(&t);
+
+snprintf(s, 20, "%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;
+}
+//-----------------------------------------------------------------------------
+uint32_t CalcMask(uint32_t msk)
+{
+if (msk >= 32) return 0xFFffFFff;
+if (msk == 0) return 0;
+return htonl(0xFFffFFff << (32 - msk));
+}
+//---------------------------------------------------------------------------
+void TouchFile(const string & fileName)
+{
+FILE * f = fopen(fileName.c_str(), "w");
+if (f)
+    fclose(f);
+}
+//---------------------------------------------------------------------------
+#ifdef WIN32
+void EncodeStr(char * str, unsigned long serial, int useHDD)
+{
+int len = strlen(str);
+char stren[100];
+int i, j = 0;
+char c1, c2;
+char serial_c[sizeof(serial)];
+memcpy(serial_c, &serial, sizeof(serial));
+
+for (i = 0; i < len; i++)
+    {
+    if (!useHDD)
+        str[i] = str[i]^49;
+    else
+        {
+        str[i] = str[i]^serial_c[j%sizeof(serial)];
+        j++;
+        }
+    }
+
+for (i = 0; i < 2*len; i++)
+    {
+    if (i%2)
+        {
+        c1 = (str[i/2] >> 4);
+        c1 = c1 + 50;
+        stren[i] = c1;
+        }
+    else
+        {
+        c2 = (str[i/2] & 0x0f);
+        c2 += 50;
+        stren[i] = c2;
+        }
+    }
+stren[i] = 0;
+strcpy(str, stren);
+}
+//---------------------------------------------------------------------------
+void DecodeStr(char * str, unsigned long serial, int useHDD)
+{
+int len = strlen(str);
+char strdc[100];
+int i, j = 0;
+char c1, c2;
+char serial_c[sizeof(serial)];
+memcpy(serial_c, &serial, sizeof(serial));
+
+for (i = 0; i < len; i += 2)
+    {
+    c1 = (str[i] - 50);
+    c2 = (str[i+1] - 50)<<4;
+    strdc[i/2] = c1+c2;
+    }
+for (i = 0; i < len/2; i++)
+    {
+    if (!useHDD)
+        strdc[i] = strdc[i]^49;
+    else
+        {
+        strdc[i] = strdc[i]^serial_c[j%sizeof(serial)];
+        j++;
+        }
+    }
+strdc[i] = 0;
+strcpy(str, strdc);
+}
+//---------------------------------------------------------------------------
+#endif //WIN32
+void SwapBytes(uint16_t & value)
+{
+    value = (value >> 8) |
+            (value << 8);
+}
+//---------------------------------------------------------------------------
+void SwapBytes(uint32_t & value)
+{
+    value = (value >> 24) |
+            ((value << 8) &  0x00FF0000L)|
+            ((value >> 8) &  0x0000FF00L)|
+            (value << 24);
+}
+//---------------------------------------------------------------------------
+void SwapBytes(uint64_t & value)
+{
+    value = (value >> 56) |
+            ((value << 40) & 0x00FF000000000000LL) |
+            ((value << 24) & 0x0000FF0000000000LL) |
+            ((value << 8)  & 0x000000FF00000000LL) |
+            ((value >> 8)  & 0x00000000FF000000LL) |
+            ((value >> 24) & 0x0000000000FF0000LL) |
+            ((value >> 40) & 0x000000000000FF00LL) |
+            (value << 56);
+}
+//---------------------------------------------------------------------------
+void SwapBytes(int16_t & value)
+{
+    uint16_t temp = value;
+    SwapBytes(temp);
+    value = temp;
+}
+//---------------------------------------------------------------------------
+void SwapBytes(int32_t & value)
+{
+    uint32_t temp = value;
+    SwapBytes(temp);
+    value = temp;
+}
+//---------------------------------------------------------------------------
+void SwapBytes(int64_t & value)
+{
+    uint64_t temp = value;
+    SwapBytes(temp);
+    value = temp;
+}
+//---------------------------------------------------------------------------
+int str2x(const std::string & str, int & x)
+{
+x = strtol(str.c_str(), NULL, 10);
+
+if (errno == ERANGE)
+    return -1;
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int str2x(const std::string & str, unsigned & x)
+{
+x = strtoul(str.c_str(), NULL, 10);
+
+if (errno == ERANGE)
+    return -1;
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int str2x(const std::string & str, long long & x)
+{
+x = strtoll(str.c_str(), NULL, 10);
+
+if (errno == ERANGE)
+    return -1;
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int str2x(const std::string & str, unsigned long long & x)
+{
+x = strtoull(str.c_str(), NULL, 10);
+
+if (errno == ERANGE)
+    return -1;
+
+return 0;
+}
+//---------------------------------------------------------------------------
+const std::string & x2str(unsigned x, std::string & s)
+{
+return unsigned2str(x, s);
+}
+//---------------------------------------------------------------------------
+const std::string & x2str(unsigned long long x, std::string & s)
+{
+return unsigned2str(x, s);
+}
+//---------------------------------------------------------------------------
+std::string & TrimL(std::string & val)
+{
+size_t pos = val.find_first_not_of(" \t");
+if (pos == std::string::npos)
+    {
+    val.erase(val.begin(), val.end());
+    }
+else
+    {
+    val.erase(0, pos);
+    }
+return val;
+}
+//---------------------------------------------------------------------------
+std::string & TrimR(std::string & val)
+{
+size_t pos = val.find_last_not_of(" \t");
+if (pos != std::string::npos)
+    {
+    val.erase(pos + 1);
+    }
+return val;
+}
+//---------------------------------------------------------------------------
+std::string & Trim(std::string & val)
+{
+return TrimR(TrimL(val));
+}
+//---------------------------------------------------------------------------
+time_t stg_timegm(struct tm * brokenTime)
+{
+#ifdef HAVE_TIMEGM
+return timegm(brokenTime);
+#else
+time_t ret;
+char *tz;
+tz = getenv("TZ");
+setenv("TZ", "", 1);
+tzset();
+ret = mktime(brokenTime);
+if (tz)
+    setenv("TZ", tz, 1);
+else
+    unsetenv("TZ");
+tzset();
+return ret;
+#endif
+}
+//---------------------------------------------------------------------------
+std::string IconvString(const std::string & source,
+                        const std::string & from,
+                        const std::string & to)
+{
+if (source.empty())
+    return std::string();
+
+size_t inBytesLeft = source.length() + 1;
+size_t outBytesLeft = source.length() * 2 + 1;
+
+char * inBuf = new char[inBytesLeft];
+char * outBuf = new char[outBytesLeft];
+
+strncpy(inBuf, source.c_str(), source.length());
+
+inBuf[source.length()] = 0;
+
+#if defined(FREE_BSD) || defined(FREE_BSD5)
+const char * srcPos = inBuf;
+#else
+char * srcPos = inBuf;
+#endif
+char * dstPos = outBuf;
+
+iconv_t handle = iconv_open(to.c_str(),
+                            from.c_str());
+
+if (handle == iconv_t(-1))
+    {
+    if (errno == EINVAL)
+        {
+        printfd(__FILE__, "IconvString(): iconv from %s to %s failed\n", from.c_str(), to.c_str());
+        delete[] outBuf;
+        delete[] inBuf;
+        return source;
+        }
+    else
+        printfd(__FILE__, "IconvString(): iconv_open error\n");
+
+    delete[] outBuf;
+    delete[] inBuf;
+    return source;
+    }
+
+size_t res = iconv(handle,
+                   &srcPos, &inBytesLeft,
+                   &dstPos, &outBytesLeft);
+
+if (res == size_t(-1))
+    {
+    printfd(__FILE__, "IconvString(): '%s'\n", strerror(errno));
+
+    iconv_close(handle);
+    delete[] outBuf;
+    delete[] inBuf;
+    return source;
+    }
+
+dstPos = 0;
+
+std::string dst(outBuf);
+
+iconv_close(handle);
+
+delete[] outBuf;
+delete[] inBuf;
+
+return dst;
+}
+//---------------------------------------------------------------------------
diff --git a/stglibs/common.lib/common.h b/stglibs/common.lib/common.h
new file mode 100644 (file)
index 0000000..971a2e7
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.31 $
+ $Date: 2010/11/03 10:26:30 $
+ $Author: faust $
+ */
+
+#ifndef common_h
+#define common_h
+
+#include <ctime>
+#include <string>
+
+#include "os_int.h"
+#include "stg_const.h"
+
+#define STAT_TIME_3         (1)
+#define STAT_TIME_2         (2)
+#define STAT_TIME_1         (3)
+#define STAT_TIME_1_2       (4)
+#define STAT_TIME_1_4       (5)
+#define STAT_TIME_1_6       (6)
+
+#define FN_STR_LEN      (NAME_MAX)
+
+#define ST_F    0
+#define ST_B    1
+#define ST_KB   2
+#define ST_MB   3
+
+//-----------------------------------------------------------------------------
+const char    * IntToKMG(long long a, int statType = ST_F);
+const char    * LogDate(time_t t);
+int             ParesTimeStat(const char * str);
+int             IsTimeStat(struct tm * t, int statTime);
+/*bool            IsDigit(char c);
+bool            IsAlpha(char c);*/
+int             strtodouble2(const char * s, double &a);
+int             printfd(const char * __file__, const char * fmt, ...);
+void            Encode12(char * dst, const char * src, size_t srcLen);
+void            Decode21(char * dst, const char * src);
+
+void            Encode12str(std::string & dst, const std::string & src);
+void            Decode21str(std::string & dst, const std::string & src);
+
+int             ParseIPString(const char * str, uint32_t * ips, int maxIP);
+void            KOIToWin(const char * s1, char * s2, int l);
+void            WinToKOI(const char * s1, char * s2, int l);
+void            KOIToWin(const std::string & s1, std::string * s2);
+void            WinToKOI(const std::string & s1, std::string * s2);
+int             DaysInMonth(unsigned year, unsigned mon);
+int             DaysInCurrentMonth();
+int             Min8(int a);
+//char          * inet_ntostr(unsigned long);
+std::string     inet_ntostring(uint32_t);
+uint32_t        inet_strington(const std::string & value);
+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);
+void            TouchFile(const std::string & fileName);
+#ifdef WIN32
+void            EncodeStr(char * str, unsigned long serial, int useHDD);
+void            DecodeStr(char * str, unsigned long serial, int useHDD);
+#endif //WIN32
+void            SwapBytes(uint16_t & value);
+void            SwapBytes(uint32_t & value);
+void            SwapBytes(uint64_t & value);
+void            SwapBytes(int16_t & value);
+void            SwapBytes(int32_t & value);
+void            SwapBytes(int64_t & value);
+
+std::string &   TrimL(std::string & val);
+std::string &   TrimR(std::string & val);
+std::string &   Trim(std::string & val);
+
+std::string     IconvString(const std::string & source, const std::string & from, const std::string & to);
+
+//-----------------------------------------------------------------------------
+template <typename varT>
+int str2x(const std::string & str, varT & x)
+{
+    int pos = 0;
+    int minus = 1;
+
+    if (str.empty())
+        return -1;
+
+    if (str[0] == '+')
+        pos++;
+
+    if (str[0] == '-')
+    {
+        pos++;
+        minus = -1;
+    }
+
+    if ((str[pos] < '0' || str[pos] > '9'))
+        return -1;
+
+    x = str[pos++] - '0';
+
+    for (unsigned i = pos; i < str.size(); i++)
+    {
+        if ((str[i] < '0' || str[i] > '9'))
+            return -1;
+
+        x *= 10;
+        x += str[i] - '0';
+    }
+
+    x*= minus;
+
+    return 0;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+const std::string & x2str(varT x, std::string & s)
+{
+    varT xx = x;
+    int pos = 1;
+
+    x /= 10;
+    while (x != 0)
+    {
+        x /= 10;
+        pos++;
+    }
+
+    if (xx < 0)
+    {
+        pos++;
+        s.resize(pos, 0);
+        s[0] = '-';
+    }
+    else if (xx > 0)
+    {
+        s.resize(pos, 0);
+    }
+    else
+    {
+        s.resize(1, 0);
+        s[0] = '0';
+        return s;
+    }
+
+    x = xx;
+
+    while (x != 0)
+    {
+        if (x < 0)
+            s[--pos] = -(x % 10) + '0';
+        else
+            s[--pos] = x % 10 + '0';
+
+        x /= 10;
+    }
+
+    return s;
+}
+//-----------------------------------------------------------------------------
+template <typename varT>
+const std::string & unsigned2str(varT x, std::string & s)
+{
+    varT xx = x;
+    int pos = 1;
+
+    x /= 10;
+    while (x != 0)
+    {
+        x /= 10;
+        pos++;
+    }
+
+    if (xx > 0)
+    {
+        s.resize(pos, 0);
+    }
+    else
+    {
+        s.resize(1, 0);
+        s[0] = '0';
+        return s;
+    }
+
+    x = xx;
+
+    while (x != 0)
+    {
+        s[--pos] = x % 10 + '0';
+
+        x /= 10;
+    }
+
+    return s;
+}
+//-----------------------------------------------------------------------------
+int str2x(const std::string & str, int & x);
+int str2x(const std::string & str, unsigned & x);
+int str2x(const std::string & str, long long & x);
+int str2x(const std::string & str, unsigned long long & x);
+//-----------------------------------------------------------------------------
+const std::string & x2str(unsigned x, std::string & s);
+const std::string & x2str(unsigned long long x, std::string & s);
+//-----------------------------------------------------------------------------
+char * stg_strptime(const char *, const char *, struct tm *);
+time_t stg_timegm(struct tm *);
+
+#endif
diff --git a/stglibs/common.lib/debug.c b/stglibs/common.lib/debug.c
new file mode 100644 (file)
index 0000000..8a2d15c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *****************************************************************************
+ *
+ * File:        debug.c
+ *
+ * Description: ÷Ù×ÏÄ ÏÔÌÁÄÏÞÎÏÊ ÉÎÆÏÒÍÁÃÉÉ × log ÆÁÊÌ
+ *
+ * $Id: debug.c,v 1.2 2005/11/16 16:19:40 nobunaga Exp $
+ *
+ *****************************************************************************
+ */
+
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+
+#include "debug.h"
+
+
+/*
+ *****************************************************************************
+ * -= óÏÚÄÁÎÉÅ ÚÁÐÉÓÉ × log-ÆÁÊÌÅ =-
+ *****************************************************************************
+ */
+void PrintfLog(FILE * logFile, char * scriptName, char * fmt, ...)
+{
+    #ifndef DEMO
+    va_list vaList;
+    char buff[MAX_LOG_BUFF_LEN];
+    time_t curTime;
+    char curTimeCh[26];
+
+    if (logFile)
+    {
+        va_start(vaList, fmt);
+        vsprintf(buff, fmt, vaList);
+        va_end(vaList);
+
+        curTime = time(NULL);
+        ctime_r(&curTime, curTimeCh);
+        curTimeCh[strlen(curTimeCh)-1] = 0;
+        fprintf(logFile, "%s [%s]: %s\n", scriptName, curTimeCh, buff);
+    }
+    #endif
+    return;
+} /* PrintfLog() */
+
+/* EOF */
+
diff --git a/stglibs/common.lib/debug.h b/stglibs/common.lib/debug.h
new file mode 100644 (file)
index 0000000..d80de9f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *****************************************************************************
+ *
+ * File:        debug.h
+ *
+ * Description: ÷Ù×ÏÄ ÏÔÌÁÄÏÞÎÏÊ ÉÎÆÏÒÍÁÃÉÉ × log ÆÁÊÌ
+ *
+ * $Id: debug.h,v 1.2 2006/03/07 18:33:56 nobunaga Exp $
+ *
+ *****************************************************************************
+ */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+
+#include <stdio.h>
+
+
+#define MAX_LOG_BUFF_LEN    (2048)
+
+
+void PrintfLog(FILE * logFile, char * scriptName, char * fmt, ...);
+
+#endif  /* _DEBUG_H_ */
+
+/* EOF */
+
diff --git a/stglibs/common.lib/stg_common.h b/stglibs/common.lib/stg_common.h
new file mode 100644 (file)
index 0000000..43a43d3
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *****************************************************************************
+ *
+ * File:        stg_common.h
+ *
+ * Description: çÌÏÂÁÌØÎÏÅ ÄÌÑ ×ÓÅÇÏ ÐÒÏÅËÔÁ STG
+ *
+ * $Id: stg_common.h,v 1.1.1.1 2005/09/29 11:33:18 boris Exp $
+ *
+ *****************************************************************************
+ */
+
+#ifndef _STG_COMMON_H_
+#define _STG_COMMON_H_
+
+
+#define LOGIN_LEN       (32)
+#define PASSWD_LEN      (32)
+
+#endif  /* _STG_COMMON_H_ */
+
+/* EOF */
+
diff --git a/stglibs/common.lib/stg_error.c b/stglibs/common.lib/stg_error.c
new file mode 100644 (file)
index 0000000..17aa912
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *****************************************************************************
+ *
+ * File:        stg_error.c
+ *
+ * Description: ëÏÄÙ ïÛÉÂÏË ÐÒÏÅËÔÁ StarGazer
+ *
+ * $Id: stg_error.c,v 1.1.1.1 2005/09/29 11:33:18 boris Exp $
+ *
+ *****************************************************************************
+ */
+
+#include "stg_error.h"
+//#include "debug.h"
+
+
+/*
+ *****************************************************************************
+ * -= ðÏÉÓË ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ ÐÏ ËÏÄÕ ÏÛÉÂËÉ =-
+ *****************************************************************************
+ */
+char * GetErrorString(RESULT_DATA res)
+{
+    char * errorString;
+
+    switch (res)
+    {
+        case SUCCESS:
+        {
+            errorString = "OK:   Work finished successfully";
+            break;
+        }
+        /* astat.cgi */
+        case ERROR_CONFIG_READ:
+        {
+            errorString = "FAIL: Read config file";
+            break;
+        }
+        case ERROR_PORT_NUM:
+        {
+            errorString = "FAIL: Port value incorrect";
+            break;
+        }
+        case ERROR_CLEAR_SID_DIR:
+        {
+            errorString = "FAIL: ClearSidDir() return fail";
+            break;
+        }
+        case ERROR_UNKNOWN_HTTP_METHOD:
+        {
+            errorString = "FAIL: Umknown HTTP method";
+            break;
+        }
+        case ERROR_NULL_HTTP_METHOD:
+        {
+            errorString = "FAIL: NULL HTTP method";
+            break;
+        }
+        case ERROR_UNKNOWN_QUERY:
+        {
+            errorString = "FAIL: Unknown query";
+            break;
+        }
+        case ERROR_LOGIN:
+        {
+            errorString = "FAIL: Login Error";
+            break;
+        }
+        case ERROR_PREPARE_USER_SELECTION_PAGE_0:
+        {
+            errorString = "FAIL: Prepare user selection page [0]";
+            break;
+        }
+        case ERROR_ADD_IFACE:
+        {
+            errorString = "FAIL: Add iface";
+            break;
+        }
+        case ERROR_ADD_TARIFF:
+        {
+            errorString = "FAIL: Add tariff";
+            break;
+        }
+        case ERROR_ADD_GROUP:
+        {
+            errorString = "FAIL: Add group";
+            break;
+        }
+        case ERROR_ADD_USER:
+        {
+            errorString = "FAIL: Add user";
+            break;
+        }
+        case ERROR_CREATE_SID:
+        {
+            errorString = "FAIL: Create sid";
+            break;
+        }
+        case ERROR_SET_SID:
+        {
+            errorString = "FAIL: Set sid";
+            break;
+        }
+        case ERROR_UPDATE_SID:
+        {
+            errorString = "FAIL: Update sid";
+            break;
+        }
+        case ERROR_READ_SID_DATA:
+        {
+            errorString = "FAIL: Read sid data";
+            break;
+        }
+        case ERROR_WRITE_SID_DATA:
+        {
+            errorString = "FAIL: Write sid data";
+            break;
+        }
+        case ERROR_REMOVE_EXPIRED_SID:
+        {
+            errorString = "FAIL: Remove expired sids";
+            break;
+        }
+        /* qParam.lib */
+        case ERROR_MEMORY_ALLOCATE:
+        {
+            errorString = "FAIL: Error memory allocation";
+            break;
+        }
+        case ERROR_MEMORY_DESPOSE:
+        {
+            errorString = "FAIL: Error memory depose";
+            break;
+        }
+        case ERROR_NULL_QUERY:
+        {
+            errorString = "FAIL: Query is NULL";
+            break;
+        }
+        case ERROR_QUERY:
+        {
+            errorString = "FAIL: Error query";
+            break;
+        }
+        /* diagram.lib */
+        case ERROR_ARC_DATA_FULL:
+        {
+            errorString = "FAIL: Arc data is full";
+            break;
+        }
+        case ERROR_ARC_PERCENT:
+        {
+            errorString = "FAIL: Arc percent != 100%";
+            break;
+        }
+        default:
+        {
+            errorString = "FAIL: Unknown error";
+        }
+    } /* switch (res) */
+
+    return (errorString);
+}/* GetErrorString() */
+
+/* EOF */
+
diff --git a/stglibs/common.lib/stg_error.h b/stglibs/common.lib/stg_error.h
new file mode 100644 (file)
index 0000000..39ae145
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *****************************************************************************
+ *
+ * File:        stg_error.h
+ *
+ * Description: ëÏÄÙ ÏÛÉÂÏË
+ *
+ * $Id: stg_error.h,v 1.1.1.1 2005/09/29 11:33:18 boris Exp $
+ *
+ *****************************************************************************
+ */
+
+#ifndef _STG_ERROR_H_
+#define _STG_ERROR_H_
+
+
+/* îÁÞÁÌÏ ÏÂÌÁÓÔÉ ÏÛÉÂÏË ÍÏÄÕÌÑ astat.cgi */
+#define ERROR_ASTAT_START   (100000)
+/* îÁÞÁÌÏ ÏÂÌÁÓÔÉ ÏÛÉÂÏË ÂÉÂÌÉÔÅËÉ qparam.lib */
+#define ERROR_QPARAM_START  (102000)
+/* îÁÞÁÌÏ ÏÂÌÁÓÔÉ ÏÛÉÂÏË ÂÉÂÌÉÔÅËÉ diagram.lib */
+#define ERROR_DIAGRAM_START (103000)
+
+
+typedef enum
+{
+    SUCCESS = 0,
+
+    ERROR_CONFIG_READ = ERROR_ASTAT_START,
+    ERROR_PORT_NUM,
+    ERROR_CLEAR_SID_DIR,
+    ERROR_UNKNOWN_HTTP_METHOD,
+    ERROR_NULL_HTTP_METHOD,
+    ERROR_UNKNOWN_QUERY,
+    ERROR_LOGIN,        // ÐÏËÁ ÞÔÏ ÏÄÎÁ ÏÛÉÂËÁ ÎÁ ÍÎÏÇÏ ÓÉÔÕÁÃÉÊ:
+                        //   * ÎÅ ×ÅÒÎÏÅ ÉÍÑ É ÐÁÒÏÌØ
+                        //   * ÎÅÔ Ó×ÑÚÉ Ó ÓÅÒ×ÅÒÏÍ
+                        //   * ....
+                        // ÜÔÏ Ó×ÑÚÁÎÏ Ó ËÏÄÁÍÉ ÏÛÉÂÏË ÍÏÄÕÌÑ srvconf.lib
+                        // × ÄÁÌØÎÅÊÛÅÍ ÎÁÄÏ ÐÅÒÅÄÁÌÁÔØ ×ÓÅ ÎÁ ÏÄÉÎ
+                        // enum ÏÛÉÂÏË
+    ERROR_PREPARE_USER_SELECTION_PAGE_0,
+    ERROR_ADD_IFACE,
+    ERROR_ADD_TARIFF,
+    ERROR_ADD_GROUP,
+    ERROR_ADD_USER,
+    ERROR_CREATE_SID,
+    ERROR_SET_SID,
+    ERROR_UPDATE_SID,
+    ERROR_READ_SID_DATA,
+    ERROR_WRITE_SID_DATA,
+    ERROR_REMOVE_EXPIRED_SID,
+
+    ERROR_MEMORY_ALLOCATE = ERROR_QPARAM_START,
+    ERROR_MEMORY_DESPOSE,
+    ERROR_NULL_QUERY,   // ÚÁÐÒÏÓ ÎÅ ÐÏÌÕÞÅÎ
+    ERROR_QUERY,        // ÏÛÉÂËÁ × ÚÁÐÒÏÓÅ - ÎÅÓÏÏÔ×ÅÔÓÔ×ÉÅ ÓÔÁÎÄÁÒÔÕ
+
+    ERROR_ARC_DATA_FULL = ERROR_DIAGRAM_START,
+    ERROR_ARC_PERCENT,
+    TODO
+} RESULT_DATA;
+
+
+char * GetErrorString(RESULT_DATA res);
+
+#endif  /* _STG_ERROR_H_ */
+
+/* EOF */
+
diff --git a/stglibs/common.lib/stg_strptime.cpp b/stglibs/common.lib/stg_strptime.cpp
new file mode 100644 (file)
index 0000000..0e1fde2
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * $Revision: 1.1 $
+ * $Date: 2007/05/17 08:25:58 $
+ *
+ * This file contain a replacement of commonly used function strptime
+ * Under some OS's it appears only with _XOPEN_SOURCE definition
+ *
+ */
+
+#define _XOPEN_SOURCE
+#include <time.h>
+
+char * stg_strptime(const char * a, const char * b, struct tm * tm)
+{
+return strptime(a, b, tm);
+}
+
diff --git a/stglibs/common.lib/test.cpp b/stglibs/common.lib/test.cpp
new file mode 100644 (file)
index 0000000..2d0cff7
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ *    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
+ */
+
+ /*
+ $Revision: 1.6 $
+ $Date: 2009/06/10 10:31:15 $
+ $Author: faust $
+ */
+
+#include <iostream>
+#include <limits.h>
+#include <arpa/inet.h>
+
+using namespace std;
+
+#include "common.h"
+#include "test.h"
+
+time_t stgTime;
+
+int main(void)
+{
+char buf1[256];
+BLOWFISH_CTX ctx;
+int functions = 0, ok = 0;
+
+cout << "Testing common.lib" << endl << "---------------\
+--------------------" << endl;
+
+if (!TestIntToKMG())
+    ok++;
+functions++;
+if (!Teststrtodouble2())
+    ok++;
+functions++;
+if (!TestIsDigit())
+    ok++;
+functions++;
+if (!TestIsAlpha())
+    ok++;
+functions++;
+if (!TestEncodeDecode())
+    ok++;
+functions++;
+if (!TestParseIPString())
+    ok++;
+functions++;
+if (!TestKOIToWIN())
+    ok++;
+functions++;
+if (!TestDaysInMonth())
+    ok++;
+functions++;
+if (!TestBlowfish())
+    ok++;
+functions++;
+if (!TestMin8())
+    ok++;
+functions++;
+if (!Testinet_ntostr())
+    ok++;
+functions++;
+if (!TestParseTariffTimeStr())
+    ok++;
+functions++;
+if (!TestStr2XX2Str())
+    ok++;
+functions++;
+
+cout << "------------------------------------" << endl;
+cout << "Functions: \t\t\t" << functions << endl;
+cout << "OK's: \t\t\t\t" << ok << endl;
+cout << "Fails: \t\t\t\t" << functions - ok << endl;
+
+return (functions != ok);
+}
+
+int TestIntToKMG()
+{
+int res = 1;
+cout << "Testing IntToKMG: \t\t";
+res = res && (strcmp(IntToKMG(LONG_LONG_MAX), TEST1_LLMAX) == 0);
+//cout << IntToKMG(LONG_LONG_MAX) << " " << TEST1_LLMAX << endl;
+
+res = res && (strcmp(IntToKMG(1024 * 1024 + 1), TEST1_1) == 0);
+//cout << IntToKMG(1024 * 1024 + 1) << " " << TEST1_1 << endl;
+
+res = res && (strcmp(IntToKMG(0), TEST1_0) == 0);
+//cout << IntToKMG(0) << " " << TEST1_0 << endl;
+
+res = res && (strcmp(IntToKMG(LONG_LONG_MIN), TEST1_LLMIN) == 0);
+//cout << IntToKMG(LONG_LONG_MIN) << " " << TEST1_LLMIN << endl;
+
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int Teststrtodouble2()
+{
+double a;
+int res = 1;
+cout << "Testing strtodouble2: \t\t";
+res = res && !strtodouble2("0.0", a);
+res = res && (a == 0.0);
+res = res && !strtodouble2("0.123456", a);
+res = res && (a == 0.123456);
+res = res && !strtodouble2("123456.0", a);
+res = res && (a == 123456.0);
+res = res && !strtodouble2("123456.123456", a);
+res = res && (a == 123456.123456);
+res = res && !strtodouble2("-0.123456", a);
+res = res && (a == -0.123456);
+res = res && !strtodouble2("-123456.0", a);
+res = res && (a == -123456.0);
+res = res && !strtodouble2("-123456.123456", a);
+res = res && (a == -123456.123456);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestIsDigit()
+{
+char a;
+int res = 1;
+cout << "Testing IsDigit: \t\t";
+for(a = '0'; a < '9'; a++)
+    res = res && IsDigit(a);
+for(a = 'a'; a < 'z'; a++)
+    res = res && !IsDigit(a);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestIsAlpha()
+{
+char a;
+int res = 1;
+cout << "Testing IsAlpha: \t\t";
+for(a = '0'; a < '9'; a++)
+    res = res && !IsAlpha(a);
+for(a = 'a'; a < 'z'; a++)
+    res = res && IsAlpha(a);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestEncodeDecode()
+{
+char enc[256], dec[512];
+int res = 1;
+cout << "Testing EncodeDecode: \t\t";
+Encode12(enc, TEST2_STRING, strlen(TEST2_STRING));
+Decode21(dec, enc);
+res = res && !strcmp(dec, TEST2_STRING);
+Encode12(enc, TEST2_STRING, 256); // Overflow
+Decode21(dec, enc);
+res = res && !strcmp(dec, TEST2_STRING);
+Encode12(enc, TEST2_STRING, 5); // Underflow
+Decode21(dec, enc);
+res = res && !strcmp(dec, TEST2_PART);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestParseIPString()
+{
+unsigned int ips[4];
+int res = 1;
+cout << "Testing ParseIPString: \t\t";
+res = res && (ParseIPString("127.0.0.1, 192.168.58.1, 10.0.0.1", ips, 4) == 0);
+res = res && ips[0] == 0x0100007F;
+res = res && ips[1] == 0x013AA8C0;
+res = res && ips[2] == 0x0100000A;
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestKOIToWIN()
+{
+char enc[256], dec[256];
+int res = 1;
+cout << "Testing KOIToWin: \t\t";
+KOIToWin(TEST3_STRING, enc, 256);
+WinToKOI(enc, dec, 256);
+res = res && !strcmp(dec, TEST3_STRING);
+KOIToWin(TEST3_STRING, enc, strlen(TEST3_STRING) - 5);
+WinToKOI(enc, dec, strlen(TEST3_STRING) - 5);
+res = res && !strcmp(dec, TEST3_STRING);
+KOIToWin(TEST3_STRING, enc, strlen(TEST3_STRING) + 5);
+WinToKOI(enc, dec, strlen(TEST3_STRING) + 5);
+res = res && !strcmp(dec, TEST3_STRING);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestDaysInMonth()
+{
+int res = 1;
+cout << "Testing DaysInMonth: \t\t";
+res = res && (DaysInMonth(2000, 0) == 31);
+res = res && (DaysInMonth(2000, 1) == 29);
+res = res && (DaysInMonth(2001, 1) == 28);
+res = res && (DaysInMonth(2100, 1) == 28);
+res = res && (DaysInMonth(2400, 1) == 29);
+res = res && (DaysInMonth(2000, 2) == 31);
+res = res && (DaysInMonth(2000, 3) == 30);
+res = res && (DaysInMonth(2000, 4) == 31);
+res = res && (DaysInMonth(2000, 5) == 30);
+res = res && (DaysInMonth(2000, 6) == 31);
+res = res && (DaysInMonth(2000, 7) == 31);
+res = res && (DaysInMonth(2000, 8) == 30);
+res = res && (DaysInMonth(2000, 9) == 31);
+res = res && (DaysInMonth(2000, 10) == 30);
+res = res && (DaysInMonth(2000, 11) == 31);
+res = res && (DaysInMonth(2000, 20) == 33);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestBlowfish()
+{
+BLOWFISH_CTX ctx;
+char enc[256], dec[256];
+int res = 1, i, len = strlen(TEST4_STRING);
+cout << "Testing Blowfish: \t\t";
+EnDecodeInit(TEST4_PASSWORD, strlen(TEST4_PASSWORD), &ctx);
+strcpy(dec, TEST4_STRING);
+for(i = 0; i < len; i += 8)
+    EncodeString(&enc[i], &dec[i], &ctx);
+for(i = 0; i < len; i += 8)
+    DecodeString(&dec[i], &enc[i], &ctx);
+res = res && !strcmp(dec, TEST4_STRING);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestMin8()
+{
+int res = 1;
+cout << "Testing Min8: \t\t\t";
+res = res && (Min8(INT_MAX) == INT_MAX + 1);
+res = res && (Min8(INT_MIN) == INT_MIN);
+res = res && (Min8(0) == 0);
+res = res && (Min8(7) == 8);
+res = res && (Min8(8) == 8);
+res = res && (Min8(9) == 16);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;;
+}
+
+int Testinet_ntostr()
+{
+unsigned long ip;
+char buf[32];
+int res = 1;
+cout << "Testing inet_ntostr: \t\t";
+res = res && (strcmp(inet_ntostr(inet_addr("127.0.0.1")), "127.0.0.1") == 0);
+res = res && (strcmp(inet_ntostr(inet_addr("255.255.255.255")), "255.255.255.255") == 0);
+res = res && (strcmp(inet_ntostr(inet_addr("0.0.0.0")), "0.0.0.0") == 0);
+res = res && (strcmp(inet_ntostr(inet_addr("10.0.0.1")), "10.0.0.1") == 0);
+res = res && (strcmp(inet_ntostr(inet_addr("192.168.58.240")), "192.168.58.240") == 0);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+
+int TestParseTariffTimeStr()
+{
+int h1, m1, h2, m2;
+int res = 1;
+cout << "Testing ParseTariffTimeStr: \t";
+res = res && !ParseTariffTimeStr("00:00-00:00", h1, m1, h2, m2);
+res = res && (h1 == 0 && m1 == 0 && h2 == 0 && m2 == 0);
+res = res && !ParseTariffTimeStr("0:0-0:0", h1, m1, h2, m2);
+res = res && (h1 == 0 && m1 == 0 && h2 == 0 && m2 == 0);
+res = res && !ParseTariffTimeStr("99:99-99:99", h1, m1, h2, m2);
+res = res && (h1 == 99 && m1 == 99 && h2 == 99 && m2 == 99);
+res = res && !ParseTariffTimeStr("12:34-56:78", h1, m1, h2, m2);
+res = res && (h1 == 12 && m1 == 34 && h2 == 56 && m2 == 78);
+if (res)
+    cout << "OK" << endl;
+else
+    cout << "Fail" << endl;
+return !res;
+}
+//-----------------------------------------------------------------------------
+int TestStr2XX2Str()
+{
+cout << "Testing Str2XX2Str: \t\t";
+
+# define INT8_MIN       (-128)
+# define INT16_MIN      (-32767-1)
+# define INT32_MIN      (-2147483647-1)
+# define INT64_MIN      (-__INT64_C(9223372036854775807)-1)
+# define INT8_MAX       (127)
+# define INT16_MAX      (32767)
+# define INT32_MAX      (2147483647)
+# define INT64_MAX      (__INT64_C(9223372036854775807))
+
+int xx;
+string s;
+for (int i = -5000000; i < 5000000; i+=10)
+{
+    x2str(i, s);
+    str2x(s, xx);
+    if (i != xx)
+    {
+    cout << "Fail" << endl;
+        return 1;
+    }
+}
+
+x2str(INT32_MIN, s);
+str2x(s, xx);
+if (xx != INT32_MIN)
+{
+    cout << INT32_MIN << " " << s << endl;
+    cout << INT32_MIN << " " << xx << endl;
+cout << "Fail" << endl;
+    return 1;
+}
+
+x2str(INT32_MAX, s);
+str2x(s, xx);
+if (xx != INT32_MAX)
+{
+cout << "Fail" << endl;
+    return 1;
+}
+cout << "OK" << endl;
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/common.lib/test.h b/stglibs/common.lib/test.h
new file mode 100644 (file)
index 0000000..31f0ba0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *    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
+ */
+
+ /*
+ $Revision: 1.4 $
+ $Date: 2007/12/02 18:52:05 $
+ $Author: nobunaga $
+ */
+
+#undef STG_TIME
+
+#define TEST1_LLMAX "8589934592.00 Gb"
+#define TEST1_LLMIN "-8589934592.00 Gb"
+#define TEST1_0 "0.00 kb"
+#define TEST1_1 "1.00 Mb"
+#define TEST2_STRING "This is a test string! 0123456789+-*/"
+#define TEST2_PART "This i"
+#define TEST3_STRING "üÔÏ ÔÅÓÔÏ×ÁÑ ÓÔÒÏËÁ! 0123456789+-*/"
+#define TEST3_PART "üÔÏ ÔÅÓÔÏ×ÁÑ ÓÔÒÏËÁ! 012345678"
+#define TEST4_STRING "Try to encode this using blowfish"
+#define TEST4_PASSWORD "Ha*yN).3zqL!"
+
+int TestIntToKMG();
+int Teststrtodouble2();
+int TestIsDigit();
+int TestIsAlpha();
+int TestEncodeDecode();
+int TestParseIPString();
+int TestKOIToWIN();
+int TestDaysInMonth();
+int TestBlowfish();
+int TestMin8();
+int Testinet_ntostr();
+int TestParseTariffTimeStr();
+int TestStr2XX2Str();
+
diff --git a/stglibs/common_settings.lib/Makefile b/stglibs/common_settings.lib/Makefile
new file mode 100644 (file)
index 0000000..7829e44
--- /dev/null
@@ -0,0 +1,12 @@
+###############################################################################
+# $Id: Makefile,v 1.3 2007/05/08 14:40:09 nobunaga Exp $
+###############################################################################
+
+LIB_NAME = common_settings
+PROG = lib$(LIB_NAME)
+
+SRCS = common_settings.cpp
+
+INCS = common_settings.h
+
+include ../Makefile.in
diff --git a/stglibs/common_settings.lib/common_settings.cpp b/stglibs/common_settings.lib/common_settings.cpp
new file mode 100644 (file)
index 0000000..53a61c1
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *    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: 29.03.2007
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+$Revision: 1.2 $
+$Date: 2007/04/07 13:29:07 $
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+
+using namespace std;
+
+#include "common_settings.h"
+#include "common.h"
+
+//-----------------------------------------------------------------------------
+COMMON_SETTINGS::COMMON_SETTINGS()
+{
+
+}
+//-----------------------------------------------------------------------------
+COMMON_SETTINGS::~COMMON_SETTINGS()
+{
+
+}
+//-----------------------------------------------------------------------------
+int COMMON_SETTINGS::ParseYesNo(const string & value, bool * val)
+{
+if (0 == strcasecmp(value.c_str(), "yes"))
+    {
+    *val = true;
+    return 0;
+    }
+if (0 == strcasecmp(value.c_str(), "no"))
+    {
+    *val = false;
+    return 0;
+    }
+
+strError = "Incorrect value \'" + value + "\'.";
+return -1;
+}
+//-----------------------------------------------------------------------------
+int COMMON_SETTINGS::ParseInt(const string & value, int * val)
+{
+char *res;
+*val = strtol(value.c_str(), &res, 10);
+if (*res != 0)
+    {
+    strError = "Cannot convert \'" + value + "\' to integer.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int COMMON_SETTINGS::ParseIntInRange(const string & value, int min, int max, int * val)
+{
+if (ParseInt(value, val) != 0)
+    return -1;
+
+if (*val < min || *val > max)
+    {
+    strError = "Value \'" + value + "\' out of range.";
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int COMMON_SETTINGS::ParseDouble(const std::string & value, double * val)
+{
+char *res;
+*val = strtod(value.c_str(), &res);
+if (*res != 0)
+    {
+    strError = "Cannot convert \'" + value + "\' to double.";
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+int COMMON_SETTINGS::ParseDoubleInRange(const std::string & value, double min, double max, double * val)
+{
+if (ParseDouble(value, val) != 0)
+    return -1;
+
+if (*val < min || *val > max)
+    {
+    strError = "Value \'" + value + "\' out of range.";
+    return -1;
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+string COMMON_SETTINGS::GetStrError() const
+{
+return strError;
+}
+//-----------------------------------------------------------------------------
+int COMMON_SETTINGS::Reload ()
+{
+return ReadSettings();
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/common_settings.lib/common_settings.h b/stglibs/common_settings.lib/common_settings.h
new file mode 100644 (file)
index 0000000..4a15910
--- /dev/null
@@ -0,0 +1,68 @@
+ /*
+ $Revision: 1.3 $
+ $Date: 2007/10/24 08:04:07 $
+ */
+
+/*
+ *    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: 29.03.2007
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.3 $
+ $Date: 2007/10/24 08:04:07 $
+ */
+
+
+#ifndef common_settingsh_h
+#define common_settingsh_h 1
+
+#include <sys/types.h>
+#include <vector>
+//#include <dotconfpp.h>
+
+#include "common.h"
+#include "base_settings.h"
+
+//-----------------------------------------------------------------------------
+class COMMON_SETTINGS
+{
+public:
+    COMMON_SETTINGS();
+    virtual ~COMMON_SETTINGS();
+    virtual int     Reload();
+    virtual int     ReadSettings() = 0;
+
+    virtual std::string  GetStrError() const;
+
+protected:
+
+    virtual int     ParseInt(const std::string & value, int * val);
+    virtual int     ParseIntInRange(const std::string & value, int min, int max, int * val);
+
+    virtual int     ParseDouble(const std::string & value, double * val);
+    virtual int     ParseDoubleInRange(const std::string & value, double min, double max, double * val);
+
+    virtual int     ParseYesNo(const std::string & value, bool * val);
+
+    mutable std::string strError;
+};
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/stglibs/conffiles.lib/Makefile b/stglibs/conffiles.lib/Makefile
new file mode 100644 (file)
index 0000000..2cd4fb3
--- /dev/null
@@ -0,0 +1,12 @@
+###############################################################################
+# $Id: Makefile,v 1.4 2007/05/08 14:29:19 faust Exp $
+###############################################################################
+
+LIB_NAME = conffiles
+PROG = lib$(LIB_NAME)
+
+SRCS = conffiles.cpp
+
+INCS = conffiles.h
+
+include ../Makefile.in
diff --git a/stglibs/conffiles.lib/conffiles.cpp b/stglibs/conffiles.lib/conffiles.cpp
new file mode 100644 (file)
index 0000000..549cb22
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ *    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@ua.fm>
+ */
+
+ /*
+ $Revision: 1.5 $
+ $Date: 2009/10/22 11:40:22 $
+ */
+
+//---------------------------------------------------------------------------
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fstream>
+#include <algorithm>
+#include "conffiles.h"
+#include "common.h"
+
+using namespace std;
+
+//---------------------------------------------------------------------------
+bool StringCaseCmp(const string & str1, const string & str2)
+{
+return (strcasecmp(str1.c_str(), str2.c_str()) < 0);
+}
+//---------------------------------------------------------------------------
+CONFIGFILE::CONFIGFILE(const string &fn):
+param_val(StringCaseCmp)
+{
+fileName = fn;
+f = fopen(fn.c_str(), "rt");
+
+error = 0;
+param_val.clear();
+
+if (!f)
+    {
+    error = -1;
+    return;
+    }
+
+string line, parameter, value;
+
+unsigned long pos;
+bool emptyLine;
+unsigned char c;
+
+while (!feof(f))
+    {
+    line.erase(line.begin(), line.end());
+
+    c = fgetc(f);
+    while (!feof(f))
+        {
+        //printf("%c", c);
+        if (c == '\n')
+            break;
+        line.push_back(c);
+        c = fgetc(f);
+        }
+
+    pos = line.find('#');
+    if (pos != string::npos)
+        line.resize(pos);
+
+    emptyLine = true;
+    for (unsigned int i = 0; i < line.size(); i++)
+        {
+        if (line[i] != ' ' && line[i] != '\t' && line[i] != '\n' && line[i] != '\r')
+            {
+            emptyLine = false;
+            break;
+            }
+        }
+    if (emptyLine)
+        {
+        continue;
+        }
+
+    pos = line.find("=");
+    if (pos == string::npos)
+        {
+        fclose(f);
+        error = -1;
+        //printf("%s find(=) error\n", __FILE__);
+        return;
+        }
+    parameter = line.substr(0, pos);
+    //transform(parameter.begin(), parameter.end(), parameter.begin(), tolower);
+    value = line.substr(pos + 1);
+    //cout << parameter << "==" << value << endl;
+    param_val[parameter] = value;
+    //cout << parameter << "==" << param_val[parameter] << endl;
+    }
+
+fclose(f);
+}
+//---------------------------------------------------------------------------
+CONFIGFILE::~CONFIGFILE()
+{
+
+}
+//---------------------------------------------------------------------------
+const string & CONFIGFILE::GetFileName() const
+{
+return fileName;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::Error()
+{
+int e = error;
+error = 0;
+return e;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::FindParameter(const string &parameter, string * value) const
+{
+it = param_val.find(parameter);
+if (it == param_val.end())
+    return -1;
+
+*value = param_val[parameter];
+return 0;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::Flush()
+{
+fstream f(fileName.c_str(), ios::out);
+if (!f.is_open())
+    {
+    error = EIO;
+    return EIO;
+    }
+
+it = param_val.begin();
+while (it != param_val.end())
+    {
+    f << it->first << "=" << it->second << endl;
+    it++;
+    }
+
+f.close();
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadString(const string & param, char * str, int * maxLen, const char * defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    strncpy(str, param_val[param].c_str(), *maxLen);
+    *maxLen = param_val[param].size();
+    return 0;
+    }
+
+strncpy(str, defaultVal, *maxLen);
+*maxLen = strlen(defaultVal);
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadString(const string & param, string * val, const string & defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    *val = param_val[param];
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::WriteString(const string & param, const char * val)
+{
+WriteString(param, string(val));
+return 0;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::WriteString(const string & param, const string &val)
+{
+param_val[param] = val;
+Flush();
+return 0;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadTime(const string & param, time_t * val, time_t defaultVal) const
+{
+it = param_val.find(param);
+
+if (it != param_val.end())
+    {
+    char *res;
+    *val = strtol(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadInt(const string & param, int * val, int defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtol(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadUInt(const string & param, unsigned int * val, unsigned int defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtoul(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadLongInt(const string & param, long int * val, long int defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtol(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadULongInt(const string & param, unsigned long int * val, unsigned long int defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtoul(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadLongLongInt(const string & param, int64_t * val, int64_t defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtoll(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadULongLongInt(const string & param, uint64_t * val, uint64_t defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtoull(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadShortInt(const string & param, short int * val, short int defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = (short)strtol(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadUShortInt(const string & param, unsigned short int * val, unsigned short int defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = (short)strtoul(param_val[param].c_str(), &res, 10);
+    if (*res != 0)
+        {
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::WriteInt(const string & param, int64_t val)
+{
+string s;
+//sprintf(s, "%lld", val);
+x2str(val, s);
+param_val[param] = s;
+Flush();
+return 0;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::ReadDouble(const string & param, double * val, double defaultVal) const
+{
+it = param_val.find(param);
+// îÁÛÌÉ ÎÕÖÎÕÀ ÐÅÒÅÍÅÎÎÕÀ
+
+if (it != param_val.end())
+    {
+    // þÔÏ-ÔÏ ÓÔÏÉÔ
+    char *res;
+    *val = strtod(param_val[param].c_str(), &res);
+    if (*res != 0)
+        {
+        //cout << param << "=" << param_val[param] << " Error!!!\n";
+        *val = defaultVal; //Error!
+        return EINVAL;
+        }
+    return 0;
+    }
+
+//cout << "îÉÞÅÇÏ ÎÅÔ!!!\n";
+
+*val = defaultVal;
+return -1;
+}
+//---------------------------------------------------------------------------
+int CONFIGFILE::WriteDouble(const string & param, double val)
+{
+char s[30];
+sprintf(s, "%f", val);
+param_val[param] = s;
+Flush();
+return 0;
+}
+//---------------------------------------------------------------------------
+
+
diff --git a/stglibs/conffiles.lib/conffiles.h b/stglibs/conffiles.lib/conffiles.h
new file mode 100644 (file)
index 0000000..ee575d6
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *    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@ua.fm>
+ */
+
+ /*
+ $Revision: 1.5 $
+ $Date: 2009/06/22 16:00:38 $
+ */
+
+//---------------------------------------------------------------------------
+
+#ifndef ConfFilesH
+#define ConfFilesH
+#include <sys/types.h>
+#include <stdio.h>
+#include <map>
+#include <string>
+
+#include "os_int.h"
+
+using namespace std;
+//---------------------------------------------------------------------------
+//#define CONF_STR_LEN    300
+//typedef char STRING[CONF_STR_LEN];
+
+typedef bool (*StringCaseCmp_t)(const string & str1, const string & str2);
+
+class CONFIGFILE
+{
+private:
+    mutable map<string, string, StringCaseCmp_t> param_val;
+    mutable map<string, string>::iterator it;
+
+    FILE * f;
+    int Flush();
+    //int ReadFile();
+    string fileName;
+    int error;
+
+public:
+    CONFIGFILE(const string &fn);
+    ~CONFIGFILE();
+    const string & GetFileName() const;
+
+    // 5 ÆÕÎËÃÉÉ Read* ×ÏÚ×ÒÁÝÁÀÔ 0 ÐÒÉ ÕÓÐÅÛÎÏÍ ÓÞÉÔÙ×ÁÎÉÉ
+    // É EINVAL ÐÒÉ ÏÔÓÕÔÓ×ÉÉ ÐÁÒÁÍÅÔÒÁ É ×ÙÓÔÁ×ÌÑÀÔ defaulValue
+    int ReadString(const string & param, char * val, int * maxLen, const char * defaultVal) const;
+    int ReadString(const string & param, string * val, const string & defaultVal) const;
+
+    int FindParameter(const string &parameter, string * value) const;
+
+    int ReadTime       (const string & param, time_t *,        time_t) const;
+
+    int ReadShortInt   (const string & param, short int *,     short int) const;
+    int ReadInt        (const string & param, int *,           int) const;
+    int ReadLongInt    (const string & param, long int *,      long int) const;
+    int ReadLongLongInt(const string & param, int64_t *, int64_t) const;
+
+    int ReadUShortInt   (const string & param, unsigned short int *,     unsigned short int) const;
+    int ReadUInt        (const string & param, unsigned int *,           unsigned int) const;
+    int ReadULongInt    (const string & param, unsigned long int *,      unsigned long int) const;
+    int ReadULongLongInt(const string & param, uint64_t *, uint64_t) const;
+
+    int ReadDouble (const string & param, double * val, double defaultVal) const;
+
+    int WriteString(const string & param, const char * val);
+    int WriteString(const string & param, const string & val);
+    int WriteInt   (const string & param, int64_t val);
+    int WriteDouble(const string & param, double val);
+
+    int Error();
+};
+//---------------------------------------------------------------------------
+#endif
diff --git a/stglibs/crypto.lib/Makefile b/stglibs/crypto.lib/Makefile
new file mode 100644 (file)
index 0000000..6fe383a
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.5 2009/10/09 07:15:48 nobunaga Exp $
+###############################################################################
+
+LIB_NAME = stg_crypto
+PROG = lib$(LIB_NAME)
+
+SRCS = ag_md5.cpp \
+       blowfish.cpp
+
+INCS = ag_md5.h \
+       blowfish.h
+
+include ../Makefile.in
diff --git a/stglibs/crypto.lib/ag_md5.cpp b/stglibs/crypto.lib/ag_md5.cpp
new file mode 100644 (file)
index 0000000..fef284a
--- /dev/null
@@ -0,0 +1,457 @@
+
+#ifdef WIN32
+#include <process.h>
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ag_md5.h"
+
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+    ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+
+int i64c(int i)
+{
+    if (i <= 0)
+        return ('.');
+
+    if (i == 1)
+        return ('/');
+
+    if (i >= 2 && i < 12)
+        return ('0' - 2 + i);
+
+    if (i >= 12 && i < 38)
+        return ('A' - 12 + i);
+
+    if (i >= 38 && i < 63)
+        return ('a' - 38 + i);
+
+    return ('z');
+}
+
+char * l64a_(long l)
+{
+    static  char    buf[8];
+    int i = 0;
+
+    if (l < 0L)
+        return ((char *) 0);
+
+    do {
+        buf[i++] = i64c ((int) (l % 64));
+        buf[i] = '\0';
+    } while (l /= 64L, l > 0 && i < 6);
+
+    return (buf);
+}
+
+char * crypt_make_salt(void)
+{
+
+    static char result[40];
+    #ifdef WIN32
+    unsigned int tsec;
+    #else
+    struct timeval tv;
+    #endif
+
+    result[0] = '\0';
+        strcpy(result, "$1$");  /* magic for the new MD5 crypt() */
+
+    /*
+     * Generate 8 chars of salt, the old crypt() will use only first 2.
+     */
+    #ifdef WIN32
+    strcat(result, l64a_(GetTickCount()));
+    tsec = time(NULL);
+    strcat(result, l64a_(tsec + getpid() + clock()));
+    #else
+    gettimeofday(&tv, (struct timezone *) 0);
+    strcat(result, l64a_(tv.tv_usec));
+    strcat(result, l64a_(tv.tv_sec + getpid() + clock()));
+    #endif
+
+    if (strlen(result) > 3 + 8)  /* magic+salt */
+        result[11] = '\0';
+
+    return result;
+}
+
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32_t t;
+    do {
+    t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+        ((unsigned) buf[1] << 8 | buf[0]);
+    *(uint32_t *) buf = t;
+    buf += 4;
+    } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, char const *buf, unsigned len)
+{
+    uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+    ctx->bits[1]++;     /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+    unsigned char *p = (unsigned char *) ctx->in + t;
+
+    t = 64 - t;
+    if (len < t) {
+        memcpy(p, buf, len);
+        return;
+    }
+    memcpy(p, buf, t);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    buf += t;
+    len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+    memcpy(ctx->in, buf, 64);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    buf += 64;
+    len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+    /* Two lots of padding:  Pad the first block to 64 bytes */
+    memset(p, 0, count);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+    /* Now fill the next block with 56 bytes */
+    memset(ctx->in, 0, 56);
+    } else {
+    /* Pad block to 56 bytes */
+    memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset((char *) ctx, 0, sizeof(ctx));   /* In case it's sensitive */
+}
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+    register uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
+static unsigned char itoa64[] =     /* 0 ... 63 => ascii - 64 */
+    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void
+to64(char *s, unsigned long v, int n)
+{
+    while (--n >= 0) {
+        *s++ = itoa64[v&0x3f];
+        v >>= 6;
+    }
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *
+libshadow_md5_crypt(const char *pw, const char *salt)
+{
+    static const char *magic = "$1$"; /*
+                         * This string is magic for
+                         * this algorithm.  Having
+                         * it this way, we can get
+                         * get better later on
+                         */
+    static char     passwd[120], *p;
+    static const char *sp,*ep;
+    unsigned char   final[16];
+    int sl,pl,i,j;
+    MD5_CTX ctx,ctx1;
+    unsigned long l;
+
+    /* Refine the Salt first */
+    sp = salt;
+
+    /* If it starts with the magic string, then skip that */
+    if(!strncmp(sp,magic,strlen(magic)))
+        sp += strlen(magic);
+
+    /* It stops at the first '$', max 8 chars */
+    for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+        continue;
+
+    /* get the length of the true salt */
+    sl = ep - sp;
+
+    MD5Init(&ctx);
+
+    /* The password first, since that is what is most unknown */
+    MD5Update(&ctx, pw, strlen(pw));
+
+    /* Then our magic string */
+    MD5Update(&ctx, magic, strlen(magic));
+
+    /* Then the raw salt */
+    MD5Update(&ctx, sp, sl);
+
+    /* Then just as many characters of the MD5(pw,salt,pw) */
+    MD5Init(&ctx1);
+    MD5Update(&ctx1,pw,strlen(pw));
+    MD5Update(&ctx1,sp,sl);
+    MD5Update(&ctx1,pw,strlen(pw));
+    MD5Final(final,&ctx1);
+    for(pl = strlen(pw); pl > 0; pl -= 16)
+        MD5Update(&ctx, (char*)final, pl>16 ? 16 : pl);
+
+    /* Don't leave anything around in vm they could use. */
+    memset(final,0,sizeof final);
+
+    /* Then something really weird... */
+    for (j=0,i = strlen(pw); i ; i >>= 1)
+        if(i&1)
+            MD5Update(&ctx, (char*)final+j, 1);
+        else
+            MD5Update(&ctx, pw+j, 1);
+
+    /* Now make the output string */
+    strcpy(passwd,magic);
+    strncat(passwd,sp,sl);
+    strcat(passwd,"$");
+
+    MD5Final(final,&ctx);
+
+    /*
+     * and now, just to make sure things don't run too fast
+     * On a 60 Mhz Pentium this takes 34 msec, so you would
+     * need 30 seconds to build a 1000 entry dictionary...
+         */
+        /*
+    for(i=0;i<1000;i++) {
+        MD5Init(&ctx1);
+        if(i & 1)
+            MD5Update(&ctx1,pw,strlen(pw));
+        else
+            MD5Update(&ctx1,final,16);
+
+        if(i % 3)
+            MD5Update(&ctx1,sp,sl);
+
+        if(i % 7)
+            MD5Update(&ctx1,pw,strlen(pw));
+
+        if(i & 1)
+            MD5Update(&ctx1,final,16);
+        else
+            MD5Update(&ctx1,pw,strlen(pw));
+        MD5Final(final,&ctx1);
+    }*/
+
+    p = passwd + strlen(passwd);
+
+    l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
+    l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
+    l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
+    l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
+    l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
+    l =                    final[11]                ; to64(p,l,2); p += 2;
+    *p = '\0';
+
+    /* Don't leave anything around in vm they could use. */
+    memset(final,0,sizeof final);
+
+    return passwd;
+}
+
+char *pw_encrypt(const char *clear, const char *salt) {
+
+    /*
+     * If the salt string from the password file or from crypt_make_salt()
+     * begins with the magic string, use the new algorithm.
+     */
+    if (strncmp(salt, "$1$", 3) == 0)
+            return(libshadow_md5_crypt(clear, salt));
+        else return(NULL);
+
+}
+/* AG MD5 functions */
+char *make_ag_hash(time_t salt, const char *clear) {
+    char salt_str[20];
+    char *res=NULL;
+    char *p;
+
+    unsigned long slt = salt;
+    sprintf(salt_str, "$1$%08lx", slt);
+    res=libshadow_md5_crypt(clear, salt_str);
+    p=strrchr(res, '$');
+    return(++p);
+}
+
+int check_ag_hash(time_t salt, const char *clear, const char *hash) {
+    return(strcmp(hash, make_ag_hash(salt, clear)));
+}
+
diff --git a/stglibs/crypto.lib/ag_md5.h b/stglibs/crypto.lib/ag_md5.h
new file mode 100644 (file)
index 0000000..3b54b50
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _MD5_H
+#define _MD5_H
+
+#include <time.h>
+
+#include "os_int.h"
+
+struct MD5Context {
+       uint32_t buf[4];
+       uint32_t bits[2];
+       unsigned char in[64];
+};
+
+typedef struct MD5Context MD5_CTX;
+
+char *crypt_make_salt(void);
+void byteReverse(unsigned char*, unsigned);
+void MD5Init(struct MD5Context *ctx);
+void MD5Update(struct MD5Context*, char const*, unsigned);
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
+void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+/* static void to64(char*, unsigned long, int); */
+char *libshadow_md5_crypt(const char*, const char*);
+char *pw_encrypt(const char*, const char*);
+
+/* AG functions */
+char *make_ag_hash(time_t salt, const char *clear);
+int check_ag_hash(time_t salt, const char *clear, const char *hash);
+
+#endif /* _MD5_H */
diff --git a/stglibs/crypto.lib/blowfish.cpp b/stglibs/crypto.lib/blowfish.cpp
new file mode 100644 (file)
index 0000000..ab3122b
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Author     :  Paul Kocher
+ * E-mail     :  pck@netcom.com
+ * Date       :  1997
+ * Description:  C implementation of the Blowfish algorithm.
+ */
+
+#include <string.h>
+
+#include "blowfish.h"
+#include "stg_const.h"
+
+/*typedef struct _BCoptions
+    {
+    unsigned char remove;
+    unsigned char standardout;
+    unsigned char compression;
+    unsigned char type;
+    uint32_t origsize;
+    unsigned char securedelete;
+    } BCoptions;*/
+
+#define ENCRYPT 0
+#define DECRYPT 1
+
+#define endianBig ((unsigned char) 0x45)
+#define endianLittle ((unsigned char) 0x54)
+
+#ifdef WIN32 /* Win32 doesn't have random() or lstat */
+    #define random() rand()
+    #define initstate(x,y,z) srand(x)
+    #define lstat(x,y) stat(x,y)
+#endif
+
+#ifndef S_ISREG
+    #define S_ISREG(x) ( ((x)&S_IFMT)==S_IFREG )
+#endif
+
+
+#define N               16
+
+static uint32_t F(BLOWFISH_CTX *ctx, uint32_t x);
+static const uint32_t ORIG_P[16 + 2] = {
+0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L,
+0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L,
+0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL,
+0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L,
+0x9216D5D9L, 0x8979FB1BL
+};
+
+static const uint32_t ORIG_S[4][256] = {
+{   0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L,
+    0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L,
+    0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L,
+    0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL,
+    0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL,
+    0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L,
+    0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL,
+    0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL,
+    0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L,
+    0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L,
+    0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL,
+    0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL,
+    0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL,
+    0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L,
+    0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L,
+    0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L,
+    0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L,
+    0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L,
+    0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL,
+    0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L,
+    0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L,
+    0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L,
+    0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L,
+    0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL,
+    0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L,
+    0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL,
+    0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL,
+    0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L,
+    0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL,
+    0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L,
+    0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL,
+    0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L,
+    0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L,
+    0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL,
+    0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L,
+    0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L,
+    0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL,
+    0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L,
+    0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL,
+    0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L,
+    0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L,
+    0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL,
+    0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L,
+    0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L,
+    0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L,
+    0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L,
+    0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L,
+    0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL,
+    0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL,
+    0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L,
+    0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L,
+    0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L,
+    0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L,
+    0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL,
+    0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L,
+    0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL,
+    0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL,
+    0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L,
+    0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L,
+    0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L,
+    0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L,
+    0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L,
+    0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L,
+    0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL},
+
+{   0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L,
+    0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L,
+    0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L,
+    0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL,
+    0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L,
+    0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L,
+    0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL,
+    0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L,
+    0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L,
+    0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L,
+    0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL,
+    0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL,
+    0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L,
+    0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L,
+    0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L,
+    0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L,
+    0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL,
+    0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL,
+    0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL,
+    0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L,
+    0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL,
+    0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L,
+    0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L,
+    0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL,
+    0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL,
+    0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L,
+    0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL,
+    0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L,
+    0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL,
+    0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL,
+    0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L,
+    0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L,
+    0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L,
+    0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L,
+    0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L,
+    0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L,
+    0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L,
+    0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL,
+    0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L,
+    0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL,
+    0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L,
+    0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L,
+    0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L,
+    0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L,
+    0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L,
+    0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L,
+    0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L,
+    0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L,
+    0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L,
+    0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L,
+    0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L,
+    0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L,
+    0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L,
+    0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L,
+    0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L,
+    0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L,
+    0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL,
+    0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL,
+    0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L,
+    0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL,
+    0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L,
+    0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L,
+    0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L,
+    0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L},
+
+{   0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L,
+    0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L,
+    0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL,
+    0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L,
+    0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L,
+    0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L,
+    0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL,
+    0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL,
+    0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL,
+    0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L,
+    0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L,
+    0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL,
+    0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L,
+    0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL,
+    0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L,
+    0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL,
+    0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L,
+    0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL,
+    0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L,
+    0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL,
+    0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L,
+    0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L,
+    0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL,
+    0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L,
+    0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L,
+    0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L,
+    0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L,
+    0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL,
+    0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L,
+    0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL,
+    0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L,
+    0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL,
+    0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L,
+    0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL,
+    0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL,
+    0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL,
+    0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L,
+    0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L,
+    0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL,
+    0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL,
+    0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL,
+    0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL,
+    0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL,
+    0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L,
+    0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L,
+    0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L,
+    0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L,
+    0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL,
+    0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL,
+    0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L,
+    0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L,
+    0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L,
+    0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L,
+    0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L,
+    0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L,
+    0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L,
+    0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L,
+    0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L,
+    0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L,
+    0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL,
+    0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L,
+    0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL,
+    0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L,
+    0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L},
+
+{   0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL,
+    0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL,
+    0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL,
+    0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L,
+    0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L,
+    0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L,
+    0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L,
+    0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L,
+    0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L,
+    0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L,
+    0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L,
+    0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L,
+    0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L,
+    0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L,
+    0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L,
+    0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL,
+    0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL,
+    0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L,
+    0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL,
+    0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL,
+    0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL,
+    0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L,
+    0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL,
+    0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL,
+    0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L,
+    0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L,
+    0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L,
+    0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L,
+    0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL,
+    0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL,
+    0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L,
+    0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L,
+    0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L,
+    0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL,
+    0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L,
+    0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L,
+    0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L,
+    0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL,
+    0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L,
+    0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L,
+    0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L,
+    0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL,
+    0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL,
+    0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L,
+    0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L,
+    0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L,
+    0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L,
+    0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL,
+    0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L,
+    0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL,
+    0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL,
+    0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L,
+    0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L,
+    0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL,
+    0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L,
+    0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL,
+    0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L,
+    0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL,
+    0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L,
+    0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L,
+    0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL,
+    0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L,
+    0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL,
+    0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L}
+};
+//-----------------------------------------------------------------------------
+uint32_t F(BLOWFISH_CTX *ctx, uint32_t x) 
+{
+unsigned short a, b, c, d;
+uint32_t  y = 0;
+//uint32_t  y1, y2;
+
+d = x & 0x00FF;
+x >>= 8;
+c = x & 0x00FF;
+x >>= 8;
+b = x & 0x00FF;
+x >>= 8;
+a = x & 0x00FF;
+
+/*y1 = ctx->S[0][a];
+y2 = ctx->S[1][b];
+y = y1+y2;*/
+
+y = ctx->S[0][a] + ctx->S[1][b];
+y = y ^ ctx->S[2][c];
+y = y + ctx->S[3][d];
+return y;
+}
+//-----------------------------------------------------------------------------
+void Blowfish_Encrypt(BLOWFISH_CTX *ctx, uint32_t *xl, uint32_t *xr)
+{
+uint32_t  Xl;
+uint32_t  Xr;
+uint32_t  temp;
+short   i;
+
+Xl = *xl;
+Xr = *xr;
+
+for (i = 0; i < N; ++i)
+    {
+    Xl = Xl ^ ctx->P[i];
+    Xr = F(ctx, Xl) ^ Xr;
+    temp = Xl;
+    Xl = Xr;
+    Xr = temp;
+    }
+
+temp = Xl;
+Xl = Xr;
+Xr = temp;
+Xr = Xr ^ ctx->P[N];
+Xl = Xl ^ ctx->P[N + 1];
+*xl = Xl;
+*xr = Xr;
+}
+//-----------------------------------------------------------------------------
+void Blowfish_Decrypt(BLOWFISH_CTX *ctx, uint32_t *xl, uint32_t *xr)
+{
+uint32_t  Xl;
+uint32_t  Xr;
+uint32_t  temp;
+short       i;
+
+Xl = *xl;
+Xr = *xr;
+
+for (i = N + 1; i > 1; --i)
+    {
+    Xl = Xl ^ ctx->P[i];
+    Xr = F(ctx, Xl) ^ Xr;
+    /* Exchange Xl and Xr */
+    temp = Xl;
+    Xl = Xr;
+    Xr = temp;
+    }
+
+/* Exchange Xl and Xr */
+temp = Xl;
+Xl = Xr;
+Xr = temp;
+Xr = Xr ^ ctx->P[1];
+Xl = Xl ^ ctx->P[0];
+*xl = Xl;
+*xr = Xr;
+}
+//-----------------------------------------------------------------------------
+void Blowfish_Init(BLOWFISH_CTX *ctx, unsigned char *key, int keyLen)
+{
+int i, j, k;
+uint32_t data, datal, datar;
+
+memset(ctx->S, 0, sizeof(ctx->S));
+
+for (i = 0; i < 4; i++)
+    {
+
+    for (j = 0; j < 256; j++)
+        ctx->S[i][j] = ORIG_S[i][j];
+    }
+
+j = 0;
+
+for (i = 0; i < N + 2; ++i)
+    {
+    data = 0x00000000;
+
+    for (k = 0; k < 4; ++k)
+        {
+        data = (data << 8) | key[j];
+        j = j + 1;
+        if (j >= keyLen)
+            j = 0;
+        }
+
+    ctx->P[i] = ORIG_P[i] ^ data;
+    }
+
+datal = 0x00000000;
+datar = 0x00000000;
+
+for (i = 0; i < N + 2; i += 2)
+    {
+    Blowfish_Encrypt(ctx, &datal, &datar);
+    ctx->P[i] = datal;
+    ctx->P[i + 1] = datar;
+    }
+
+for (i = 0; i < 4; ++i)
+    {
+
+    for (j = 0; j < 256; j += 2)
+        {
+        Blowfish_Encrypt(ctx, &datal, &datar);
+        ctx->S[i][j] = datal;
+        ctx->S[i][j + 1] = datar;
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void EnDecodeInit(const char * passwd, int, BLOWFISH_CTX *ctx)
+{
+unsigned char * keyL = NULL;//[PASSWD_LEN];  // ðÁÒÏÌØ ÄÌÑ ÛÉÆÒÏ×ËÉ
+
+keyL = new unsigned char[PASSWD_LEN];
+
+memset(keyL, 0, PASSWD_LEN);
+
+strncpy((char *)keyL, passwd, PASSWD_LEN);
+
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+
+delete[] keyL;
+}
+//-----------------------------------------------------------------------------
+// Note: swap bytes order for compatibility with OpenSSL
+uint32_t bytes2block(const char * c)
+{
+    uint32_t t = static_cast<unsigned char>(*c++);
+    t += static_cast<unsigned char>(*c++) << 8;
+    t += static_cast<unsigned char>(*c++) << 16;
+    t += static_cast<unsigned char>(*c) << 24;
+    return t;
+}
+//-----------------------------------------------------------------------------
+// Note: swap bytes order for compatibility with OpenSSL
+void block2bytes(uint32_t t, char * c)
+{
+    *c++ = t & 0x000000FF;
+    *c++ = t >> 8 & 0x000000FF;
+    *c++ = t >> 16 & 0x000000FF;
+    *c = t >> 24 & 0x000000FF;
+}
+//-----------------------------------------------------------------------------
+void DecodeString(char * d, const char * s, BLOWFISH_CTX *ctx)
+{
+uint32_t a = bytes2block(s);
+uint32_t b = bytes2block(s + 4);
+
+Blowfish_Decrypt(ctx, &a, &b);
+
+block2bytes(a, d);
+block2bytes(b, d + 4);
+}
+//-----------------------------------------------------------------------------
+void EncodeString(char * d, const char * s, BLOWFISH_CTX *ctx)
+{
+uint32_t a = bytes2block(s);
+uint32_t b = bytes2block(s + 4);
+
+Blowfish_Encrypt(ctx, &a, &b);
+
+block2bytes(a, d);
+block2bytes(b, d + 4);
+}
+//-----------------------------------------------------------------------------
diff --git a/stglibs/crypto.lib/blowfish.h b/stglibs/crypto.lib/blowfish.h
new file mode 100644 (file)
index 0000000..e0cf206
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Author     :  Paul Kocher
+ * E-mail     :  pck@netcom.com
+ * Date       :  1997
+ * Description:  C implementation of the Blowfish algorithm.
+ */
+
+#ifndef BLOWFISH_H
+#define BLOWFISH_H
+
+#include "os_int.h"
+
+#define MAXKEYBYTES 56          /* 448 bits */
+
+typedef struct {
+  uint32_t P[16 + 2];
+  uint32_t S[4][256];
+} BLOWFISH_CTX;
+
+void Blowfish_Init(BLOWFISH_CTX *ctx, unsigned char *key, int keyLen);
+void Blowfish_Encrypt(BLOWFISH_CTX *ctx, uint32_t *xl, uint32_t *xr);
+void Blowfish_Decrypt(BLOWFISH_CTX *ctx, uint32_t *xl, uint32_t *xr);
+
+void EnDecodeInit(const char * key, int passwdLen, BLOWFISH_CTX *ctx);
+void DecodeString(char * d, const char * s, BLOWFISH_CTX *ctx);
+void EncodeString(char * d, const char * s, BLOWFISH_CTX *ctx);
+
+#endif
+
diff --git a/stglibs/crypto.lib/crypto.bpf b/stglibs/crypto.lib/crypto.bpf
new file mode 100644 (file)
index 0000000..f5907ba
--- /dev/null
@@ -0,0 +1,9 @@
+//---------------------------------------------------------------------------\r
+\r
+#include <vcl.h>\r
+#pragma hdrstop\r
+#define Library\r
+\r
+// To add a file to the library use the Project menu 'Add to Project'.\r
+\r
\ No newline at end of file
diff --git a/stglibs/crypto.lib/crypto.bpr b/stglibs/crypto.lib/crypto.bpr
new file mode 100644 (file)
index 0000000..78be718
--- /dev/null
@@ -0,0 +1,144 @@
+<?xml version='1.0' encoding='utf-8' ?>\r
+<!-- C++Builder XML Project -->\r
+<PROJECT>\r
+  <MACROS>\r
+    <VERSION value="BCB.06.00"/>\r
+    <PROJECT value="..\..\lib\crypto.lib"/>\r
+    <OBJFILES value="obj\ag_md5.obj obj\blowfish.obj"/>\r
+    <RESFILES value=""/>\r
+    <IDLFILES value=""/>\r
+    <IDLGENFILES value=""/>\r
+    <DEFFILE value=""/>\r
+    <RESDEPEN value="$(RESFILES)"/>\r
+    <LIBFILES value=""/>\r
+    <LIBRARIES value=""/>\r
+    <PACKAGES value=""/>\r
+    <PATHCPP value=".;"/>\r
+    <PATHPAS value=".;"/>\r
+    <PATHRC value=".;"/>\r
+    <PATHASM value=".;"/>\r
+    <LINKER value="TLib"/>\r
+    <USERDEFINES value="_DEBUG;WIN32"/>\r
+    <SYSDEFINES value="_RTLDLL;NO_STRICT"/>\r
+    <MAINSOURCE value="crypto.bpf"/>\r
+    <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl;..\..\include"/>\r
+    <LIBPATH value="$(BCB)\lib\obj;$(BCB)\lib"/>\r
+    <WARNINGS value="-w-par"/>\r
+    <LISTFILE value=""/>\r
+    <OTHERFILES value=""/>\r
+  </MACROS>\r
+  <OPTIONS>\r
+    <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -I..\..\include -src_suffix cpp \r
+      -D_DEBUG -DWIN32 -boa"/>\r
+    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c \r
+      -tW -tWM"/>\r
+    <PFLAGS value="-N2obj -N0obj -$YD -$W -$O- -$A8 -v -JPHNE -M"/>\r
+    <AFLAGS value="/mx /w2 /zd"/>\r
+    <LFLAGS value=""/>\r
+    <OTHERFILES value=""/>\r
+  </OPTIONS>\r
+  <LINKER>\r
+    <ALLOBJ value="$(OBJFILES)"/>\r
+    <ALLLIB value=""/>\r
+    <OTHERFILES value=""/>\r
+  </LINKER>\r
+  <FILELIST>\r
+      <FILE FILENAME="crypto.bpf" FORMNAME="" UNITNAME="crypto" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/>\r
+      <FILE FILENAME="blowfish.h" FORMNAME="" UNITNAME="blowfish.h" CONTAINERID="" DESIGNCLASS="" LOCALCOMMAND=""/>\r
+      <FILE FILENAME="ag_md5.c" FORMNAME="" UNITNAME="ag_md5.c" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>\r
+      <FILE FILENAME="ag_md5.h" FORMNAME="" UNITNAME="ag_md5.h" CONTAINERID="" DESIGNCLASS="" LOCALCOMMAND=""/>\r
+      <FILE FILENAME="blowfish.cpp" FORMNAME="" UNITNAME="blowfish.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>\r
+  </FILELIST>\r
+  <BUILDTOOLS>\r
+  </BUILDTOOLS>\r
+\r
+  <IDEOPTIONS>\r
+[Version Info]\r
+IncludeVerInfo=0\r
+AutoIncBuild=0\r
+MajorVer=1\r
+MinorVer=0\r
+Release=0\r
+Build=0\r
+Debug=0\r
+PreRelease=0\r
+Special=0\r
+Private=0\r
+DLL=0\r
+Locale=1058\r
+CodePage=1251\r
+\r
+[Version Info Keys]\r
+CompanyName=\r
+FileDescription=\r
+FileVersion=1.0.0.0\r
+InternalName=\r
+LegalCopyright=\r
+LegalTrademarks=\r
+OriginalFilename=\r
+ProductName=\r
+ProductVersion=1.0.0.0\r
+Comments=\r
+\r
+[HistoryLists\hlIncludePath]\r
+Count=2\r
+Item0=$(BCB)\include;$(BCB)\include\vcl;..\..\include\r
+Item1=$(BCB)\include;$(BCB)\include\vcl\r
+\r
+[HistoryLists\hlLibraryPath]\r
+Count=1\r
+Item0=$(BCB)\lib\obj;$(BCB)\lib\r
+\r
+[HistoryLists\hlDebugSourcePath]\r
+Count=1\r
+Item0=$(BCB)\source\vcl\r
+\r
+[HistoryLists\hlConditionals]\r
+Count=2\r
+Item0=_DEBUG;WIN32\r
+Item1=_DEBUG\r
+\r
+[HistoryLists\hlIntOutputDir]\r
+Count=1\r
+Item0=obj\r
+\r
+[HistoryLists\hlFinalOutputDir]\r
+Count=2\r
+Item0=..\..\lib\\r
+Item1=..\..\lib\r
+\r
+[HistoryLists\hlTlibPageSize]\r
+Count=1\r
+Item0=0x0010\r
+\r
+[Debugging]\r
+DebugSourceDirs=$(BCB)\source\vcl\r
+\r
+[Parameters]\r
+RunParams=\r
+Launcher=\r
+UseLauncher=0\r
+DebugCWD=\r
+HostApplication=\r
+RemoteHost=\r
+RemotePath=\r
+RemoteLauncher=\r
+RemoteCWD=\r
+RemoteDebug=0\r
+\r
+[Compiler]\r
+ShowInfoMsgs=0\r
+LinkDebugVcl=0\r
+LinkCGLIB=0\r
+\r
+[CORBA]\r
+AddServerUnit=1\r
+AddClientUnit=1\r
+PrecompiledHeaders=1\r
+\r
+[Language]\r
+ActiveLang=\r
+ProjectLang=\r
+RootDir=\r
+  </IDEOPTIONS>\r
+</PROJECT>
\ No newline at end of file
diff --git a/stglibs/dotconfpp.lib/Makefile b/stglibs/dotconfpp.lib/Makefile
new file mode 100644 (file)
index 0000000..85e34a7
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.3 2007/05/08 14:29:19 faust Exp $
+###############################################################################
+
+LIB_NAME = dotconfpp
+PROG = lib$(LIB_NAME)
+
+SRCS = dotconfpp.cpp \
+       mempool.cpp
+
+INCS = dotconfpp.h \
+       mempool.h
+
+include ../Makefile.in
diff --git a/stglibs/dotconfpp.lib/dotconfpp.cpp b/stglibs/dotconfpp.lib/dotconfpp.cpp
new file mode 100644 (file)
index 0000000..b82ae81
--- /dev/null
@@ -0,0 +1,661 @@
+/*  Copyright (C) 2003 Aleksey Krivoshey <krivoshey@users.sourceforge.net>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation; either version 2 of the License, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with this program; if not, write to the Free Software
+*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <libgen.h> // dirname
+#include <glob.h> // glob
+#include <string>
+
+#include "dotconfpp.h"
+
+DOTCONFDocumentNode::DOTCONFDocumentNode():previousNode(NULL), nextNode(NULL), parentNode(NULL), childNode(NULL),
+    values(NULL), valuesCount(0), 
+    name(NULL), lineNum(0), fileName(NULL), closed(true)
+{
+}
+
+DOTCONFDocumentNode::~DOTCONFDocumentNode()
+{
+    free(name);
+    if(values != NULL){
+        for(int i = 0 ; i < valuesCount; i++){
+            free(values[i]);
+        }
+        free(values);
+    }
+}
+
+void DOTCONFDocumentNode::pushValue(char * _value)
+{
+    valuesCount++;
+    values = (char**)realloc(values, valuesCount*sizeof(char*));
+    values[valuesCount-1] = strdup(_value);
+}
+
+const char* DOTCONFDocumentNode::getValue(int index) const
+{
+    if(index >= valuesCount){
+        return NULL;
+    }
+    return values[index];
+}
+
+DOTCONFDocument::DOTCONFDocument(DOTCONFDocument::CaseSensitive caseSensitivity):
+    mempool(NULL),
+    curParent(NULL), curPrev(NULL), errorCallback(NULL), errorCallbackData(NULL),
+    curLine(0), file(NULL), fileName(NULL)
+{
+    if(caseSensitivity == CASESENSITIVE){
+        cmp_func = strcmp;
+    } else {
+        cmp_func = strcasecmp;
+    }
+
+    mempool = new AsyncDNSMemPool(1024);
+    mempool->initialize();
+}
+
+DOTCONFDocument::~DOTCONFDocument()
+{
+    for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i != nodeTree.end(); i++){
+        delete(*i);
+    }
+    for(std::list<char*>::iterator i = requiredOptions.begin(); i != requiredOptions.end(); i++){
+        free(*i);
+    }
+    for(std::list<char*>::iterator i = processedFiles.begin(); i != processedFiles.end(); i++){
+        free(*i);
+    }
+    free(fileName);
+    delete mempool;
+}
+
+int DOTCONFDocument::cleanupLine(char * line)
+{
+    char * start = line;
+    char * bg = line;
+    bool multiline = false;
+    bool concat = false;
+    char * word = NULL;
+
+    if(!words.empty() && quoted)
+        concat = true;
+
+    while(*line){
+        if((*line == '#' || *line == ';') && !quoted){
+            *bg = 0;
+            if(strlen(start)){
+                //printf("2start='%s'\n", start);
+                if(concat){
+                    word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
+                    strcpy(word, words.back());
+                    strcat(word, start);
+                    words.pop_back();
+                    concat = false;
+                } else {
+                    word = mempool->strdup(start);
+                }
+                words.push_back(word);
+            }
+            break;
+        }
+        if(*line == '=' && !quoted){ // 'parameter = value' is the same as 'parameter value' but do not replace with ' ' when used in quoted value
+            *line = ' ';continue;
+        }
+        if(*line == '\\' && (*(line+1) == '"' || *(line+1) == '\'')){
+            *bg++ = *(line+1); 
+            line+=2; continue;
+        }
+        if(*line == '\\' && *(line+1) == 'n'){
+            *bg++ = '\n'; 
+            line+=2; continue;
+        }
+        if(*line == '\\' && *(line+1) == 'r'){
+            *bg++ = '\r'; 
+            line+=2; continue;
+        }
+        if(*line == '\\' && (*(line+1) == '\n' || *(line+1) == '\r')){ //multiline
+            *bg = 0;
+            if(strlen(start)){
+                //printf("3start='%s'\n", start);
+                if(concat){
+                    word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
+                    strcpy(word, words.back());
+                    strcat(word, start);
+                    words.pop_back();
+                    concat = false;
+                } else {
+                    word = mempool->strdup(start);
+                }
+                words.push_back(word);
+            }
+            multiline = true;
+            break;
+        }
+        if(*line == '"' || *line == '\''){ //need to handle quotes because of spaces or = that may be between
+            quoted = !quoted;
+            line++; continue;
+        }
+        if(isspace(*line) && !quoted){
+            *bg++ = 0;
+            if(strlen(start)){
+                //printf("start='%s'\n", start);
+                if(concat){
+                    word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
+                    strcpy(word, words.back());
+                    strcat(word, start);
+                    words.pop_back();
+                    concat = false;
+                } else {
+                    word = mempool->strdup(start);
+                }
+                words.push_back(word);
+            }
+            start = bg;
+            while(isspace(*++line)) {};
+            continue;
+        }
+        *bg++ = *line++;
+    }    
+
+    if(quoted && !multiline){
+        error(curLine, fileName, "unterminated quote");
+        return -1;
+    }
+
+    return multiline?1:0;
+}
+
+int DOTCONFDocument::parseLine()
+{
+    char * word = NULL;
+    char * nodeName = NULL;
+    char * nodeValue = NULL;
+    DOTCONFDocumentNode * tagNode = NULL;
+    bool newNode = false;
+
+    for(std::list<char*>::iterator i = words.begin(); i != words.end(); i++) {
+        word = *i;
+
+        if(*word == '<'){
+            newNode = true;
+        }
+
+        if(newNode){
+            nodeValue = NULL;
+            nodeName = NULL;
+            newNode = false;
+        }
+
+        size_t wordLen = strlen(word);
+        if(word[wordLen-1] == '>'){
+            word[wordLen-1] = 0;
+            newNode = true;
+        }
+
+        if(nodeName == NULL){
+            nodeName = word;
+            bool closed = true; //if this not <> node then it is closed by default
+            if(*nodeName == '<'){
+                if(*(nodeName+1) != '/'){ //opening tag
+                    nodeName++;
+                    closed = false;
+                } else { //closing tag
+                    nodeName+=2;
+                    std::list<DOTCONFDocumentNode*>::reverse_iterator i=nodeTree.rbegin();
+                    for(; i!=nodeTree.rend(); i++){
+                        if(!cmp_func(nodeName, (*i)->name) && !(*i)->closed){
+                            (*i)->closed = true;
+                            curParent = (*i)->parentNode;
+                            curPrev = *i;
+                            break;
+                        }
+                    }
+                    if(i==nodeTree.rend()){
+                        error(curLine, fileName, "not matched closing tag </%s>", nodeName);
+                        return -1;
+                    }
+                    continue;
+                }
+            }
+            tagNode = new DOTCONFDocumentNode;
+            tagNode->name = strdup(nodeName);
+            tagNode->document = this;
+            tagNode->fileName = processedFiles.back();
+            tagNode->lineNum = curLine;
+            tagNode->closed = closed;
+            if(!nodeTree.empty()){
+                DOTCONFDocumentNode * prev = nodeTree.back();
+                if(prev->closed){
+
+                    curPrev->nextNode = tagNode;
+                    tagNode->previousNode = curPrev;
+                    tagNode->parentNode = curParent;
+
+                } else {
+                    prev->childNode = tagNode;
+                    tagNode->parentNode = prev;
+                    curParent = prev;
+                }
+            }
+            nodeTree.push_back(tagNode);
+            curPrev = tagNode;
+        } else {
+            nodeValue = word;
+            tagNode->pushValue(nodeValue);
+        }
+    }
+    
+    return 0;
+}
+int DOTCONFDocument::parseFile(DOTCONFDocumentNode * _parent)
+{
+    char str[512];
+    int ret = 0;
+    curLine = 0;
+    curParent = _parent;
+
+    quoted = false;
+    size_t slen = 0;
+
+    while(fgets(str, 511, file)){
+        curLine++;
+       slen = strlen(str);
+        if( slen >= 510 ){
+            error(curLine, fileName, "warning: line too long");
+        }
+       if(str[slen-1] != '\n'){
+           str[slen] = '\n';
+           str[slen+1] = 0;
+       }
+        if((ret = cleanupLine(str)) == -1){
+            break;
+        }
+        if(ret == 0){
+            if(!words.empty()){
+                ret = parseLine();
+                mempool->free();
+                words.clear();
+                if(ret == -1){
+                    break;
+                }
+            }            
+        }
+    }
+
+    return ret;
+}
+
+int DOTCONFDocument::checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from)
+{
+    int ret = 0;
+
+    DOTCONFDocumentNode * tagNode = NULL;
+    int vi = 0;
+    for(std::list<DOTCONFDocumentNode*>::iterator i = from; i != nodeTree.end(); i++){
+        tagNode = *i;
+        if(!tagNode->closed){
+            error(tagNode->lineNum, tagNode->fileName, "unclosed tag %s", tagNode->name);
+            ret = -1;
+            break;
+        }
+        vi = 0;
+        while( vi < tagNode->valuesCount ){
+            //if((tagNode->values[vi])[0] == '$' && (tagNode->values[vi])[1] == '{' && strchr(tagNode->values[vi], '}') ){
+            if(strstr(tagNode->values[vi], "${") && strchr(tagNode->values[vi], '}') ){
+                ret = macroSubstitute(tagNode, vi );
+                mempool->free();
+                if(ret == -1){
+                    break;
+                }
+            }
+            vi++;
+        }
+        if(ret == -1){
+            break;
+        }
+    }
+
+    return ret;
+}
+
+int DOTCONFDocument::setContent(const char * _fileName)
+{    
+    int ret = 0;
+    char realpathBuf[PATH_MAX];
+
+    if(realpath(_fileName, realpathBuf) == NULL){
+        error(0, NULL, "realpath(%s) failed: %s", _fileName, strerror(errno));
+        return -1;
+    }
+
+    fileName = strdup(realpathBuf);
+
+    char * forPathName = strdup(realpathBuf);
+
+    if (forPathName == NULL) {
+        error(0, NULL, "Not enought memory to duplicate realpath");
+        return -1;
+    }
+
+    char * _pathName = dirname(forPathName);
+
+    std::string pathName(_pathName);
+
+    free(forPathName); // From strdup
+
+    processedFiles.push_back(strdup(realpathBuf));
+
+    if(( file = fopen(fileName, "r")) == NULL){
+        error(0, NULL, "failed to open file '%s': %s", fileName, strerror(errno));
+        return -1;
+    }
+
+    ret = parseFile();
+    
+    (void) fclose(file);
+
+    if(!ret){
+    
+        if( (ret = checkConfig(nodeTree.begin())) == -1){
+            return -1;
+        }
+
+        std::list<DOTCONFDocumentNode*>::iterator from;
+        DOTCONFDocumentNode * tagNode = NULL;
+        int vi = 0;
+        for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); i++){
+            tagNode = *i;
+            if(!cmp_func("IncludeFile", tagNode->name)){
+                vi = 0;
+                while( vi < tagNode->valuesCount ){
+                    glob_t globBuf;
+                    std::string nodeFilePath;
+                    if (*tagNode->values[vi] != '/') {
+                        // Relative path
+                        nodeFilePath = pathName + "/" + tagNode->values[vi];
+                    } else {
+                        // Absolute path
+                       nodeFilePath = tagNode->values[vi];
+                    }
+                    int res = glob(nodeFilePath.c_str(), 0, NULL, &globBuf);
+                    if (res) {
+                        switch (res) {
+                            case GLOB_NOSPACE:
+                                error(tagNode->lineNum, tagNode->fileName, "glob call failed for '%s': no free space", nodeFilePath.c_str());
+                                return -1;
+                            case GLOB_ABORTED:
+                                // printf("Read error\n");
+                                // Ignore that error
+                                break;
+                            case GLOB_NOMATCH:
+                                // printf("No match\n");
+                                // Ignore that error
+                                break;
+                            default:
+                                error(tagNode->lineNum, tagNode->fileName, "glob call failed for '%s': unknown error", nodeFilePath.c_str());
+                                return -1;
+                        }
+                    }
+                    if (!res) {
+                        for (size_t i = 0; i < globBuf.gl_pathc; ++i) {
+                            std::string nodeFilePath(globBuf.gl_pathv[i]);
+                            if(access(nodeFilePath.c_str(), R_OK) == -1){
+                                error(tagNode->lineNum, tagNode->fileName, "%s: %s", nodeFilePath.c_str(), strerror(errno));
+                                continue;
+                            }
+                            if(realpath(nodeFilePath.c_str(), realpathBuf) == NULL){
+                                error(tagNode->lineNum, tagNode->fileName, "realpath(%s) failed: %s", nodeFilePath.c_str(), strerror(errno));
+                                continue;
+                            }
+
+                            bool processed = false;
+                            for(std::list<char*>::const_iterator itInode = processedFiles.begin(); itInode != processedFiles.end(); itInode++){
+                                if(!strcmp(*itInode, realpathBuf)){
+                                    processed = true;
+                                    break;
+                                }
+                            }
+                            if(processed){
+                                break;
+                            }
+
+                            processedFiles.push_back(strdup(realpathBuf));
+
+                            file = fopen(nodeFilePath.c_str(), "r");
+                            if(file == NULL){
+                                error(tagNode->lineNum, fileName, "failed to open file '%s': %s", nodeFilePath.c_str(), strerror(errno));
+                                continue;
+                            }
+                            //free(fileName);
+                            fileName = strdup(realpathBuf);
+                            from = nodeTree.end(); from--;
+                            
+                            if(tagNode->parentNode){
+                                DOTCONFDocumentNode * nd = tagNode->parentNode->childNode;
+                                while(nd){
+                                    if(!nd->nextNode)
+                                        break;
+                                    nd = nd->nextNode;
+                                }
+
+                                curPrev = nd;
+                            }
+                            ret = parseFile(tagNode->parentNode);
+                            
+                            //ret = parseFile(tagNode->parentNode);
+                            (void) fclose(file);
+                            if(ret == -1)
+                                continue;
+                            if(checkConfig(++from) == -1){
+                                continue;
+                            }
+                        }
+                    }
+                    globfree(&globBuf);
+                    vi++;
+                }
+            }
+        }
+        /*
+        if( (ret = checkConfig(nodeTree.begin())) == -1){
+            return -1;
+        }
+        */
+
+        if(!requiredOptions.empty())
+            ret = checkRequiredOptions();
+    }
+
+    return ret;
+}
+
+int DOTCONFDocument::checkRequiredOptions()
+{
+    for(std::list<char*>::const_iterator ci = requiredOptions.begin(); ci != requiredOptions.end(); ci++){
+        bool matched = false;
+        for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); i++){            
+            if(!cmp_func((*i)->name, *ci)){
+                matched = true;
+                break;
+            }
+        }
+        if(!matched){
+            error(0, NULL, "required option '%s' not specified", *ci);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+void DOTCONFDocument::error(int lineNum, const char * fileName, const char * fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+
+    size_t len = (lineNum!=0?strlen(fileName):0) + strlen(fmt) + 50;
+    char * buf = (char*)mempool->alloc(len);
+
+    if(lineNum)
+        (void) snprintf(buf, len, "DOTCONF++: file '%s', line %d: %s\n", fileName, lineNum, fmt);
+    else
+        (void) snprintf(buf, len, "DOTCONF++: %s\n", fmt);
+
+    if (errorCallback) {
+        errorCallback(errorCallbackData, buf);
+    } else {
+        (void) vfprintf(stderr, buf, args);
+    }
+
+    va_end(args);
+}
+
+char * DOTCONFDocument::getSubstitution(char * macro, int lineNum)
+{
+    char * buf = NULL;
+    char * variable = macro+2;
+
+    char * endBr = strchr(macro, '}');
+
+    if(!endBr){
+        error(lineNum, fileName, "unterminated '{'");
+        return NULL;
+    }
+    *endBr = 0;
+
+    char * defaultValue = strchr(variable, ':');
+
+    if(defaultValue){
+        *defaultValue++ = 0;
+        if(*defaultValue != '-'){
+            error(lineNum, fileName, "incorrect macro substitution syntax");
+            return NULL;
+        }
+        defaultValue++;
+        if(*defaultValue == '"' || *defaultValue == '\''){
+            defaultValue++;
+            defaultValue[strlen(defaultValue)-1] = 0;
+        }
+    } else {
+        defaultValue = NULL;
+    }
+
+    char * subs = getenv(variable);
+    if( subs ){
+        buf = mempool->strdup(subs);
+    } else {
+        std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin();
+        DOTCONFDocumentNode * tagNode = NULL;
+        for(; i!=nodeTree.end(); i++){            
+            tagNode = *i;
+            if(!cmp_func(tagNode->name, variable)){
+                if(tagNode->valuesCount != 0){
+                    buf = mempool->strdup(tagNode->values[0]);
+                    break;
+                }
+            }
+        }
+        if( i == nodeTree.end() ){
+            if( defaultValue ){
+                buf = mempool->strdup(defaultValue);
+            } else {
+                error(lineNum, fileName, "substitution not found and default value not given");
+                return NULL;
+            }
+        }
+    }
+    return buf;
+}
+
+int DOTCONFDocument::macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex)
+{
+    int ret = 0;
+    char * macro = tagNode->values[valueIndex];
+    size_t valueLen = strlen(tagNode->values[valueIndex])+1;
+    char * value = (char*)mempool->alloc(valueLen);
+    char * v = value;
+    char * subs = NULL;
+
+    while(*macro){
+        if(*macro == '$' && *(macro+1) == '{'){
+            char * m = strchr(macro, '}');
+            subs = getSubstitution(macro, tagNode->lineNum);
+            if(subs == NULL){
+                ret = -1;
+                break;
+            }
+            macro = m + 1;
+            *v = 0;
+            v = (char*)mempool->alloc(strlen(value)+strlen(subs)+valueLen);
+            strcpy(v, value);
+            value = strcat(v, subs);
+            v = value + strlen(value);
+            continue;
+        }
+        *v++ = *macro++;
+    }
+    *v = 0;
+
+    free(tagNode->values[valueIndex]);
+    tagNode->values[valueIndex] = strdup(value);
+    return ret;
+}
+
+const DOTCONFDocumentNode * DOTCONFDocument::getFirstNode() const
+{
+    if ( !nodeTree.empty() ) {
+        return *nodeTree.begin();
+    } else {
+        return NULL;
+    }
+}
+
+const DOTCONFDocumentNode * DOTCONFDocument::findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode, const DOTCONFDocumentNode * startNode) const
+{
+    //printf("nodeName=%s, cont=%s, start=%s\n", nodeName, containingNode!=NULL?containingNode->name:"NULL", startNode!=NULL?startNode->name:"NULL");
+    
+    std::list<DOTCONFDocumentNode*>::const_iterator i = nodeTree.begin();
+
+    if(startNode == NULL)
+        startNode = parentNode;
+
+    if(startNode != NULL){
+        while( i != nodeTree.end() && (*i) != startNode ){
+            i++;
+        }
+        if( i != nodeTree.end() ) i++;
+    }
+
+    for(; i!=nodeTree.end(); i++){
+        //if(parentNode != NULL && (*i)->parentNode != parentNode){
+       if((*i)->parentNode != parentNode){
+            continue;
+        }
+        if(!cmp_func(nodeName, (*i)->name)){
+            return *i;
+        }
+    }
+    return NULL;
+}
+
+void DOTCONFDocument::setRequiredOptionNames(const char ** requiredOptionNames)
+{
+    while(*requiredOptionNames){
+        requiredOptions.push_back(strdup( *requiredOptionNames ));
+        requiredOptionNames++;
+    }
+}
+
diff --git a/stglibs/dotconfpp.lib/dotconfpp.h b/stglibs/dotconfpp.lib/dotconfpp.h
new file mode 100644 (file)
index 0000000..c068640
--- /dev/null
@@ -0,0 +1,122 @@
+/*  Copyright (C) 2003 Aleksey Krivoshey <voodoo@foss.kharkov.ua>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation; either version 2 of the License, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with this program; if not, write to the Free Software
+*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#ifndef DOTCONFPP_H
+#define DOTCONFPP_H
+
+#include <list>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "os_int.h"
+#include "mempool.h"
+
+typedef void (* DOTCONFCallback) (void * data, const char * buf);
+
+class DOTCONFDocument;
+
+class DOTCONFDocumentNode
+{
+friend class DOTCONFDocument;
+private:
+    DOTCONFDocumentNode * previousNode;
+    DOTCONFDocumentNode * nextNode;
+    DOTCONFDocumentNode * parentNode;
+    DOTCONFDocumentNode * childNode;
+    char ** values;
+    int valuesCount;
+    char * name;
+    const DOTCONFDocument * document;
+    int lineNum;
+    char * fileName;
+    bool closed;
+
+    void pushValue(char * _value);
+
+public:
+    DOTCONFDocumentNode();
+    ~DOTCONFDocumentNode();
+
+    const char * getConfigurationFileName() const { return fileName; }
+    int getConfigurationLineNumber() const { return lineNum; }
+
+    const DOTCONFDocumentNode * getNextNode() const { return nextNode; }
+    const DOTCONFDocumentNode * getPreviuosNode() const { return previousNode; }
+    const DOTCONFDocumentNode * getParentNode() const { return parentNode; }
+    const DOTCONFDocumentNode * getChildNode() const { return childNode; }
+    const char * getValue(int index = 0) const;
+    const char * getName() const { return name; }
+    const DOTCONFDocument * getDocument() const { return document; }
+};
+
+class DOTCONFDocument
+{
+public:
+    enum CaseSensitive { CASESENSITIVE, CASEINSENSITIVE };
+protected:
+    AsyncDNSMemPool * mempool;    
+private:
+    DOTCONFDocumentNode * curParent;
+    DOTCONFDocumentNode * curPrev;
+    DOTCONFCallback errorCallback;
+    void * errorCallbackData;
+    int curLine;
+    bool quoted;
+    std::list<DOTCONFDocumentNode *> nodeTree;
+    std::list<char *> requiredOptions;
+    std::list<char *> processedFiles;
+    FILE * file;
+    char * fileName;
+    std::list<char *> words;
+    int (* cmp_func)(const char *, const char *);
+
+    int checkRequiredOptions();
+    int parseLine();
+    int parseFile(DOTCONFDocumentNode * _parent = NULL);
+    int checkConfig(const std::list<DOTCONFDocumentNode *>::iterator & from);
+    int cleanupLine(char * line);
+    char * getSubstitution(char * macro, int lineNum);
+    int macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex);
+
+protected:
+    virtual void error(int lineNum, const char * fileName, const char * fmt, ...);
+
+public:
+    DOTCONFDocument(CaseSensitive caseSensitivity = CASESENSITIVE);
+    virtual ~DOTCONFDocument();
+
+    void setErrorCallback(DOTCONFCallback _callback, void * _data) { errorCallback = _callback; errorCallbackData = _data; };
+
+    int setContent(const char * _fileName);
+
+    void setRequiredOptionNames(const char ** requiredOptionNames); // !TERMINATE ARRAY WITH NULL
+    const DOTCONFDocumentNode * getFirstNode() const;    
+    const DOTCONFDocumentNode * findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode = NULL, const DOTCONFDocumentNode * startNode = NULL) const;
+};
+
+#endif
diff --git a/stglibs/dotconfpp.lib/mempool.cpp b/stglibs/dotconfpp.lib/mempool.cpp
new file mode 100644 (file)
index 0000000..3469418
--- /dev/null
@@ -0,0 +1,116 @@
+/*  Copyright (C) 2003 Aleksey Krivoshey <voodoo@foss.kharkov.ua>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation; either version 2 of the License, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with this program; if not, write to the Free Software
+*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#include "mempool.h"
+
+AsyncDNSMemPool::PoolChunk::PoolChunk(size_t _size):
+    pool(NULL), pos(0), size(_size)
+{
+    pool = ::malloc(size);
+}
+
+AsyncDNSMemPool::PoolChunk::~PoolChunk()
+{
+    ::free(pool);
+}
+
+AsyncDNSMemPool::AsyncDNSMemPool(size_t _defaultSize):
+    chunks(NULL), chunksCount(0), defaultSize(_defaultSize),
+    poolUsage(0), poolUsageCounter(0)
+{
+}
+
+AsyncDNSMemPool::~AsyncDNSMemPool()
+{    
+    for(size_t i = 0; i<chunksCount; i++){
+        delete chunks[i];
+    }
+    ::free(chunks);
+}
+
+int AsyncDNSMemPool::initialize()
+{
+    chunksCount = 1;
+    chunks = (PoolChunk**)::malloc(sizeof(PoolChunk*));
+    if(chunks == NULL)
+        return -1;
+
+    chunks[chunksCount-1] = new PoolChunk(defaultSize);
+
+    return 0;
+}
+
+void AsyncDNSMemPool::addNewChunk(size_t size)
+{
+    chunksCount++;
+    chunks = (PoolChunk**)::realloc(chunks, chunksCount*sizeof(PoolChunk*));
+    if(size <= defaultSize)
+        chunks[chunksCount-1] = new PoolChunk(defaultSize);
+    else
+        chunks[chunksCount-1] = new PoolChunk(size);
+}
+
+void * AsyncDNSMemPool::alloc(size_t size)
+{
+    PoolChunk * chunk = NULL;
+    for(size_t i = 0; i<chunksCount; i++){
+        chunk = chunks[i];
+        if((chunk->size - chunk->pos) >= size){
+            chunk->pos += size;
+            return ((u_int8_t*)chunk->pool) + chunk->pos - size;
+        }
+    }
+    addNewChunk(size);
+    chunks[chunksCount-1]->pos = size;
+    return chunks[chunksCount-1]->pool;
+}
+
+void AsyncDNSMemPool::free()
+{    
+    size_t pu = 0;
+    size_t psz = 0;
+    poolUsageCounter++;
+
+    for(size_t i = 0; i<chunksCount; i++){
+        pu += chunks[i]->pos;
+        psz += chunks[i]->size;
+        chunks[i]->pos = 0;
+    }
+    poolUsage=(poolUsage>pu)?poolUsage:pu;
+
+    if(poolUsageCounter >= 10 && chunksCount > 1){
+        psz -= chunks[chunksCount-1]->size;
+        if(poolUsage < psz){
+            chunksCount--;
+            delete chunks[chunksCount];
+        }
+        poolUsage = 0;
+        poolUsageCounter = 0;
+    }
+}
+
+void * AsyncDNSMemPool::calloc(size_t size)
+{
+    return ::memset(this->alloc(size), 0, size);
+}
+
+char * AsyncDNSMemPool::strdup(const char *str)
+{
+    return ::strcpy((char*)this->alloc(strlen(str)+1), str);
+}
+
diff --git a/stglibs/dotconfpp.lib/mempool.h b/stglibs/dotconfpp.lib/mempool.h
new file mode 100644 (file)
index 0000000..73b3c4c
--- /dev/null
@@ -0,0 +1,60 @@
+/*  Copyright (C) 2003 Aleksey Krivoshey <voodoo@foss.kharkov.ua>
+*
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation; either version 2 of the License, or
+*   (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with this program; if not, write to the Free Software
+*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#ifndef ASYNC_DNS_MEMPOOL_H
+#define ASYNC_DNS_MEMPOOL_H
+
+#include "os_int.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+class AsyncDNSMemPool
+{
+private:
+    struct PoolChunk {
+        void * pool;
+        size_t pos;
+        size_t size;
+
+        PoolChunk(size_t _size);
+        ~PoolChunk();
+    };
+    PoolChunk ** chunks;
+    size_t chunksCount;
+    size_t defaultSize;
+
+    size_t poolUsage;
+    size_t poolUsageCounter;
+
+    void addNewChunk(size_t size);
+
+public:
+    AsyncDNSMemPool(size_t _defaultSize = 4096);
+    virtual ~AsyncDNSMemPool();
+
+    int initialize();
+    void free();
+    void * alloc(size_t size);
+    void * calloc(size_t size);
+    char * strdup(const char *str);
+};
+
+#endif
+
diff --git a/stglibs/hostallow.lib/Makefile b/stglibs/hostallow.lib/Makefile
new file mode 100644 (file)
index 0000000..97f9c0c
--- /dev/null
@@ -0,0 +1,12 @@
+###############################################################################
+# $Id: Makefile,v 1.3 2007/05/08 14:29:20 faust Exp $
+###############################################################################
+
+LIB_NAME = hostallow
+PROG = lib$(LIB_NAME)
+
+SRCS = hostallow.cpp
+
+INCS = hostallow.h
+
+include ../Makefile.in
diff --git a/stglibs/hostallow.lib/hostallow.cpp b/stglibs/hostallow.lib/hostallow.cpp
new file mode 100644 (file)
index 0000000..9fedbbf
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *    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@ua.fm>
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <algorithm>
+#include <functional>
+
+#include "hostallow.h"
+//-----------------------------------------------------------------------------
+HOSTALLOW::HOSTALLOW()
+{
+
+}
+//-----------------------------------------------------------------------------
+int HOSTALLOW::ParseHosts(const char * str, int hostsType)
+{
+/*
+ðÒÏÉÚ×ÏÄÉÍ ÒÁÚÂÏÒ ÓÔÒÏËÉ ×ÉÄÁ host host host ...
+ÇÄÅ host ÍÏÖÅÔ ÉÍÅÔØ ×ÉÄ a.b.c.d ÉÌÉ a.b.c.d/e
+ÉÌÉ all.
+ÐÒÉÞÅÍ × ÓÌÕÞÁÅ ÓÅÔÉ ÍÁÓËÁ É ÁÄÒÅÓ ÄÏÌÖÎÙ ÂÙÔØ 
+ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÍÉ ÄÒÕÇ ÄÒÕÇÕ.
+
+òÅÚÕÌØÔÁÔÙ ÚÁÎÏÓÉÍ × ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÓÐÉÓÏË 
+ * */
+
+int len;
+char *s;
+char * tok;
+uint32_t ip;
+uint32_t mask;
+//INETADDR inetAddr;
+
+if (strcasecmp(str, "all") == 0)
+    {
+    if (hostsType == hostsAllow)
+        hostAllowList.push_back(INETADDR());
+    else
+        hostDenyList.push_back(INETADDR());
+    return 0;
+    }
+else
+    {
+    len = strlen(str);
+
+    s = new char[len + 1];
+
+    strcpy(s, str);
+
+    tok = strtok(s, " ");
+
+    while (tok)
+        {
+        if (ParseIPMask(tok, &ip, &mask) != 0)
+            {
+            return -1;
+            delete[] s;
+            }
+        //printfd(__FILE__, "ParseHosts tok %s\n", tok);
+        tok = strtok(NULL, " ");
+        if (hostsType == hostsAllow)
+            {
+            //printfd(__FILE__, "ParseHosts APPEND allow %X %X\n", ip, mask);
+            hostAllowList.push_back(INETADDR(ip, mask));
+            }
+        else
+            {
+            //printfd(__FILE__, "ParseHosts APPEND deny  %X %X\n", ip, mask);
+            hostDenyList.push_back(INETADDR(ip, mask));
+            }
+        }
+    }
+
+delete[] s;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int HOSTALLOW::ParseIPMask(const char * s, uint32_t * ip, uint32_t * mask)
+{
+/*
+òÁÚÂÏÒ ÓÔÒÏËÉ ×ÉÄÁ a.b.c.d/e ÉÌÉ a.b.c.d
+
+123.123.123.123/30
+ * */
+int len;
+char * host;
+
+int i = 0, msk;
+
+len = strlen(s);
+host = new char[len + 1];
+
+while (s[i] != 0 && s[i] != '/')
+    {
+    host[i] = s[i];
+    i++;
+    }
+
+host[i] = 0;
+
+if (inet_addr(host) == INADDR_NONE)
+    {
+    delete[] host;
+    sprintf(errMsg, "Icorrect IP address %s", host);
+    return -1;
+    }
+
+*ip = inet_addr(host);
+
+char *res;
+
+if (s[i] == '/')
+    {
+    msk = strtol(&s[i+1], &res, 10);
+    if (*res != 0)
+        {
+        sprintf(errMsg, "Icorrect mask %s", &s[i+1]);
+        delete[] host;
+        return -1;
+        }
+
+    if (msk < 0 || msk > 32)
+        {
+        sprintf(errMsg, "Icorrect mask %s", &s[i+1]);
+        delete[] host;
+        *mask = 0;
+        return 0;
+        }
+
+    uint32_t m = 0;
+    m = htonl(0xFFffFFff<<(32 - msk));
+
+    *mask = m;
+    }
+else
+    {
+    *mask = 0xFFffFFff;
+    }
+
+if ((*ip & *mask) != *ip)
+    {
+    sprintf(errMsg, "Address does'n match mask.\n");
+    delete[] host;
+    return -1;
+    }
+
+delete[] host;
+return 0;  
+}
+//-----------------------------------------------------------------------------
+int HOSTALLOW::ParseOrder(const char * str)
+{
+/*
+ÐÒÏÉÚ×ÏÄÉÍ ÒÁÚÂÏÒ ÓÔÒÏËÉ ×ÉÄÁ allow deny ÉÌÉ deny allow
+ */
+
+if (strcasecmp(str, "allow,deny") == 0)
+    {
+    order = orderAllow;
+    return 0;
+    }
+
+if (strcasecmp(str, "deny,allow") == 0)
+    {
+    order = orderDeny;
+    return 0;
+    }
+
+sprintf(errMsg, "Parameter \'order\' must be \'allow,deny\' or \'deny,allow\'");
+return -1;
+}
+//-----------------------------------------------------------------------------
+int HOSTALLOW::GetError()
+{
+/*
+÷ÏÚ×ÒÁÝÁÅÍ ËÏÄ ÏÛÉÂËÉ É ÓÂÒÁÓÙ×ÁÅÍ ÅÅ.
+ * */
+return 0;
+}
+//-----------------------------------------------------------------------------
+bool HOSTALLOW::HostAllowed(uint32_t ip)
+{
+/*
+ðÒÏ×ÅÒÑÅÍ Ñ×ÌÑÅÔÓÑ ÌÉ éð ÒÁÚÒÅÛÅÎÎÙÍ ÉÌÉ ÎÅÔ
+ * */
+
+if (order == orderDeny)
+    {
+    if (IsHostInDeniedList(ip))
+        {
+        return false;
+        }
+
+    if (IsHostInAllowedList(ip))
+        {
+        return true;
+        }
+    }
+else
+    {
+    if (IsHostInAllowedList(ip))
+        {
+        return true;
+        }
+
+    if (IsHostInDeniedList(ip))
+        {
+        return false;
+        }
+    }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+int HOSTALLOW::IsIPInSubnet(uint32_t checkedIP, INETADDR &ia)
+{
+//uint32_t checkedIP;
+if ((ia.mask & checkedIP) == (ia.ip))
+    return true;
+return false;
+}
+//-----------------------------------------------------------------------------
+bool HOSTALLOW::IsHostInAllowedList(uint32_t ip)
+{
+/*
+îÁÈÏÄÉÔÓÑ ÌÉ éð × ÓÐÉÓËÅ ÒÁÚÒÅÛÅÎÎÙÈ
+ * */
+list<INETADDR>::iterator li;
+
+li = hostAllowList.begin();
+
+while(li != hostAllowList.end())
+    {
+    if (IsIPInSubnet(ip, *li))
+        return true;
+    }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+bool HOSTALLOW::IsHostInDeniedList(uint32_t ip)
+{
+/*
+îÁÈÏÄÉÔÓÑ ÌÉ éð × ÓÐÉÓËÅ ÚÁÐÒÅÝÅÎÎÙÈ
+ * */
+list<INETADDR>::iterator li;
+
+li = hostDenyList.begin();
+
+while(li != hostDenyList.end())
+    {
+    if (IsIPInSubnet(ip, *li))
+        return true;
+    }
+
+return false;
+}
+//-----------------------------------------------------------------------------
+const char * HOSTALLOW::GetStrError()
+{
+/*
+÷ÏÚ×ÒÁÝÁÅÍ ÔÅËÓÔÏ×ÏÅ ÏÐÉÓÁÎÉÅ ÏÛÉÂËÉ.
+ * */
+return errMsg;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/hostallow.lib/hostallow.h b/stglibs/hostallow.lib/hostallow.h
new file mode 100644 (file)
index 0000000..034cdb3
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *    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@ua.fm>
+ */
+
+
+#ifndef HOSTALLOW_H
+#define HOSTALLOW_H
+
+#include "os_int.h"
+
+#include <list>
+
+using namespace std;
+
+#define HA_ERR_MSG_LEN  (255)
+//-----------------------------------------------------------------------------
+enum ORDER 
+{
+    orderAllow = 0,
+    orderDeny
+};
+//-----------------------------------------------------------------------------
+enum 
+{
+    hostsAllow = 0,
+    hostsDeny
+};
+//-----------------------------------------------------------------------------
+struct INETADDR
+{
+    INETADDR(uint32_t i, uint8_t m) {ip = i; mask = m;};
+    INETADDR() {ip = 0; mask = 0;};
+    uint32_t ip;
+    uint8_t  mask;
+};
+//-----------------------------------------------------------------------------
+class HOSTALLOW
+{
+public:
+    HOSTALLOW();
+    int ParseHosts(const char *, int hostsType);
+    int ParseOrder(const char *);
+    int GetError();
+    bool HostAllowed(uint32_t ip);
+    const char * GetStrError();
+
+private:
+    int ParseIPMask(const char * s, uint32_t * ip, uint32_t * mask);
+    bool IsHostInDeniedList(uint32_t ip);
+    bool IsHostInAllowedList(uint32_t ip);
+    //int  IsIPInSubnet(INETADDR &ia);
+    int  IsIPInSubnet(uint32_t checkedIP, INETADDR &ia);
+    list<INETADDR> hostAllowList;
+    list<INETADDR> hostDenyList;
+    char errMsg[HA_ERR_MSG_LEN];
+    int order;
+    char src[16 + 1];
+    char dst[16 + 1];
+
+};
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/stglibs/ia_auth_c.lib/Makefile b/stglibs/ia_auth_c.lib/Makefile
new file mode 100644 (file)
index 0000000..fb49f94
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# $Id: Makefile,v 1.11 2010/08/18 07:47:03 faust Exp $
+###############################################################################
+
+LIB_NAME = ia_auth_c
+PROG = lib$(LIB_NAME)
+
+SRCS = ia_auth_c.cpp
+
+INCS = ia_auth_c.h
+
+STGLIBS = -lstg_common \
+         -lstg_crypto
+LIBS = $(LIB_THREAD)
+
+include ../Makefile.in
diff --git a/stglibs/ia_auth_c.lib/ia_auth_c.bpf b/stglibs/ia_auth_c.lib/ia_auth_c.bpf
new file mode 100644 (file)
index 0000000..e3c42ce
--- /dev/null
@@ -0,0 +1,9 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+#define Library
+
+// To add a file to the library use the Project menu 'Add to Project'.
+
\ No newline at end of file
diff --git a/stglibs/ia_auth_c.lib/ia_auth_c.bpr b/stglibs/ia_auth_c.lib/ia_auth_c.bpr
new file mode 100644 (file)
index 0000000..c80bf51
--- /dev/null
@@ -0,0 +1,129 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+  <MACROS>
+    <VERSION value="BCB.06.00"/>
+    <PROJECT value="..\..\lib\ia_auth_c.lib"/>
+    <OBJFILES value="ia_auth_c.obj"/>
+    <RESFILES value=""/>
+    <IDLFILES value=""/>
+    <IDLGENFILES value=""/>
+    <DEFFILE value=""/>
+    <RESDEPEN value="$(RESFILES)"/>
+    <LIBFILES value=""/>
+    <LIBRARIES value=""/>
+    <PACKAGES value=""/>
+    <PATHCPP value=".;"/>
+    <PATHPAS value=".;"/>
+    <PATHRC value=".;"/>
+    <PATHASM value=".;"/>
+    <LINKER value="TLib"/>
+    <USERDEFINES value="_DEBUG;WIN32"/>
+    <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
+    <MAINSOURCE value="ia_auth_c.bpf"/>
+    <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl;..\..\include"/>
+    <LIBPATH value="$(BCB)\lib\obj;$(BCB)\lib"/>
+    <WARNINGS value="-w-par"/>
+    <LISTFILE value=""/>
+    <OTHERFILES value=""/>
+  </MACROS>
+  <OPTIONS>
+    <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -I..\..\include -src_suffix cpp 
+      -D_DEBUG -DWIN32 -boa"/>
+    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c 
+      -tW -tWM"/>
+    <PFLAGS value="-$YD -$W -$O- -$A8 -v -JPHNE -M"/>
+    <AFLAGS value="/mx /w2 /zd"/>
+    <LFLAGS value=""/>
+    <OTHERFILES value=""/>
+  </OPTIONS>
+  <LINKER>
+    <ALLOBJ value="$(OBJFILES)"/>
+    <ALLLIB value=""/>
+    <OTHERFILES value=""/>
+  </LINKER>
+  <FILELIST>
+      <FILE FILENAME="ia_auth_c.bpf" FORMNAME="" UNITNAME="ia_auth_c" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="packet.h" FORMNAME="" UNITNAME="packet.h" CONTAINERID="" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="ia_auth_c.h" FORMNAME="" UNITNAME="ia_auth_c.h" CONTAINERID="" DESIGNCLASS="" LOCALCOMMAND=""/>
+      <FILE FILENAME="ia_auth_c.cpp" FORMNAME="" UNITNAME="ia_auth_c.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+  </FILELIST>
+  <BUILDTOOLS>
+  </BUILDTOOLS>
+
+  <IDEOPTIONS>
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1049
+CodePage=1251
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include;$(BCB)\include\vcl;..\..\include
+Item1=$(BCB)\include;$(BCB)\include\vcl
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[HistoryLists\hlConditionals]
+Count=2
+Item0=_DEBUG;WIN32
+Item1=_DEBUG
+
+[HistoryLists\hlFinalOutputDir]
+Count=1
+Item0=..\..\lib
+
+[Debugging]
+DebugSourceDirs=$(BCB)\source\vcl
+
+[Parameters]
+RunParams=
+Launcher=
+UseLauncher=0
+DebugCWD=
+HostApplication=
+RemoteHost=
+RemotePath=
+RemoteLauncher=
+RemoteCWD=
+RemoteDebug=0
+
+[Compiler]
+ShowInfoMsgs=0
+LinkDebugVcl=0
+LinkCGLIB=0
+
+[CORBA]
+AddServerUnit=1
+AddClientUnit=1
+PrecompiledHeaders=1
+  </IDEOPTIONS>
+</PROJECT>
\ No newline at end of file
diff --git a/stglibs/ia_auth_c.lib/ia_auth_c.cpp b/stglibs/ia_auth_c.lib/ia_auth_c.cpp
new file mode 100644 (file)
index 0000000..d97692e
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+** 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ $Author: faust $
+ $Revision: 1.15 $
+ $Date: 2010/04/16 11:28:03 $
+*/
+
+/*
+* Author :
+* Boris Mikhailenko <stg34@stargazer.dp.ua>
+* Andrey Rakhmanov <andrey_rakhmanov@yahoo.com> - èñïðàâëåíèå äâóõ áàãîâ.
+*/
+
+//---------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#ifdef WIN32
+    #include <winsock2.h>
+    #include <windows.h>
+    #include <winbase.h>
+    #include <winnt.h>
+#else
+    #include <fcntl.h>
+    #include <sys/types.h>
+    #include <sys/socket.h>
+    #include <netdb.h>
+    #include <netinet/in.h>
+    #include <arpa/inet.h>
+    #include <unistd.h>
+#endif
+
+#include "common.h"
+#include "ia_auth_c.h"
+
+#define IA_NONE            (0)
+#define IA_CONNECT         (1)
+#define IA_DISCONNECT      (2)
+
+#define IA_DEBUGPROTO   1
+
+#define IA_ID "00100"
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+#ifndef WIN32
+#include <sys/time.h>
+void * RunL(void * data)
+{
+
+IA_CLIENT_PROT * c = (IA_CLIENT_PROT *)data;
+static int a = 0;
+
+if (a == 0)
+    {
+    usleep(50000);
+    a = 1;
+    }
+
+while (c->GetNonstop())
+    {
+    c->Run();
+    }
+return NULL;
+}
+//---------------------------------------------------------------------------
+void Sleep(int ms)
+{
+usleep(ms * 1000);
+}
+//---------------------------------------------------------------------------
+long GetTickCount()
+{
+struct timeval tv;
+gettimeofday(&tv, NULL);
+return tv.tv_sec*1000 + tv.tv_usec/1000;
+}
+#else
+//---------------------------------------------------------------------------
+unsigned long WINAPI RunW(void * data)
+{
+IA_CLIENT_PROT * c = (IA_CLIENT_PROT *)data;
+while (c->GetNonstop())
+    c->Run();
+return 0;
+}
+//---------------------------------------------------------------------------
+#endif
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+IA_CLIENT_PROT::IA_CLIENT_PROT(const string & sn, unsigned short p, uint16_t localPort)
+    : stat(),
+      action(IA_NONE),
+      phase(1),
+      phaseTime(0),
+      messageText(),
+      infoText(),
+      strError(),
+      codeError(0),
+      nonstop(true),
+      isNetPrepared(false),
+      proxyMode(false),
+      password(),
+      login(),
+      serverName(sn),
+      port(p),
+      ip(0),
+      localPort(localPort),
+      firstConnect(true),
+      reconnect(0),
+      sockr(0),
+      protNum(0),
+      userTimeout(60),
+      aliveTimeout(5),
+      rnd(0),
+      pStatusChangedCb(NULL),
+      pStatChangedCb(NULL),
+      pInfoCb(NULL),
+      pErrorCb(NULL),
+      pDirNameCb(NULL),
+      statusChangedCbData(NULL),
+      statChangedCbData(NULL),
+      infoCbData(NULL),
+      errorCbData(NULL),
+      dirNameCbData(NULL),
+      packetTypes(),
+      connSyn8(NULL),
+      connSynAck8(NULL),
+      connAck8(NULL),
+      aliveSyn8(NULL),
+      aliveAck8(NULL),
+      disconnSyn8(NULL),
+      disconnSynAck8(NULL),
+      disconnAck8(NULL),
+      err(),
+      info(NULL)
+{
+memset(&stat, 0, sizeof(stat));
+
+#ifdef WIN32
+WSAStartup(MAKEWORD(2, 0), &wsaData);
+#endif
+
+packetTypes["CONN_SYN"] = CONN_SYN_N;
+packetTypes["CONN_SYN_ACK"] = CONN_SYN_ACK_N;
+packetTypes["CONN_ACK"] = CONN_ACK_N;
+packetTypes["ALIVE_SYN"] = ALIVE_SYN_N;
+packetTypes["ALIVE_ACK"] = ALIVE_ACK_N;
+packetTypes["DISCONN_SYN"] = DISCONN_SYN_N;
+packetTypes["DISCONN_SYN_ACK"] = DISCONN_SYN_ACK_N;
+packetTypes["DISCONN_ACK"] = DISCONN_ACK_N;
+packetTypes["FIN"] = FIN_N;
+packetTypes["ERR"] = ERROR_N;
+packetTypes["INFO"] = INFO_N;
+packetTypes["INFO_7"] = INFO_7_N;
+packetTypes["INFO_8"] = INFO_8_N;
+
+unsigned char key[IA_PASSWD_LEN];
+memset(key, 0, IA_LOGIN_LEN);
+strncpy((char *)key, "pr7Hhen", 8);
+Blowfish_Init(&ctxHdr, key, IA_PASSWD_LEN);
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::PrepareNet()
+{
+struct hostent * phe;
+unsigned long ip;
+
+ip = inet_addr(serverName.c_str());
+if (ip == INADDR_NONE)
+    {
+    phe = gethostbyname(serverName.c_str());
+    if (phe)
+        {
+        ip = *((unsigned long*)phe->h_addr_list[0]);
+        }
+    else
+        {
+        strError = string("Unknown host ") + "\'" + serverName + "\'";
+        codeError = IA_GETHOSTBYNAME_ERROR;
+        if (pErrorCb != NULL)
+            pErrorCb(messageText, IA_GETHOSTBYNAME_ERROR, errorCbData);
+        }
+    }
+
+#ifndef WIN32
+close(sockr);
+#else
+closesocket(sockr);
+#endif
+
+sockr = socket(AF_INET, SOCK_DGRAM, 0);  // Cîêåò ÷åðåç êîòîðûé øëåì è ïðèíèìàåì
+
+localAddrS.sin_family = AF_INET;
+localAddrS.sin_port = htons(port);
+localAddrS.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+localAddrR.sin_family = AF_INET;
+
+if (localPort)
+    localAddrR.sin_port = htons(localPort);
+else
+    localAddrR.sin_port = htons(port);
+localAddrR.sin_addr.s_addr = inet_addr("0.0.0.0");
+
+servAddr.sin_family = AF_INET;
+servAddr.sin_port = htons(port);
+servAddr.sin_addr.s_addr = ip;
+
+int res = bind(sockr, (struct sockaddr*)&localAddrR, sizeof(localAddrR));
+if (res == -1)
+    {
+    strError = "bind error";
+    codeError = IA_BIND_ERROR;
+    if (pErrorCb != NULL)
+        pErrorCb(messageText, IA_BIND_ERROR, errorCbData);
+    return;
+    }
+
+#ifdef WIN32
+unsigned long arg = 1;
+res = ioctlsocket(sockr, FIONBIO, &arg);
+#else
+if (0 != fcntl(sockr, F_SETFL, O_NONBLOCK))
+    {
+    strError = "fcntl error";
+    codeError = IA_FCNTL_ERROR;
+    if (pErrorCb != NULL)
+        pErrorCb(messageText, IA_FCNTL_ERROR, errorCbData);
+    }
+#endif
+
+}
+//---------------------------------------------------------------------------
+IA_CLIENT_PROT::~IA_CLIENT_PROT()
+{
+#ifndef WIN32
+close(sockr);
+#else
+closesocket(sockr);
+WSACleanup();
+#endif
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::DeterminatePacketType(const char * buffer)
+{
+map<string, int>::iterator pi;
+pi = packetTypes.find(buffer);
+if (pi == packetTypes.end())
+    {
+    return -1;
+    }
+else
+    {
+    return pi->second;
+    }
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::FillHdr8(char * buffer, unsigned long)
+{
+strncpy(buffer, IA_ID, 6);
+buffer[IA_MAGIC_LEN] = 0;
+buffer[IA_MAGIC_LEN + 1] = IA_PROTO_VER;
+strncpy(buffer + sizeof(HDR_8), login.c_str(), IA_LOGIN_LEN);
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Send(char * buffer, int len)
+{
+if (!isNetPrepared)
+    {
+    PrepareNet();
+    isNetPrepared = true;
+    }
+
+// Øèôðóåì LoginS
+int db = sizeof(HDR_8);
+for (int i = 0; i < IA_LOGIN_LEN/8; i++)
+    {
+    Blowfish_Encrypt(&ctxHdr, (uint32_t*)(buffer + db + i*8), (uint32_t*)(buffer + db + i*8 + 4));
+    }
+
+// Øèôðóåì âñ¸ îñòàëüíîå
+db += IA_LOGIN_LEN;
+int encLen = (len - sizeof(HDR_8) - IA_LOGIN_LEN)/8;
+for (int i = 0; i < encLen; i++)
+    {
+    Blowfish_Encrypt(&ctxPass, (uint32_t*)(buffer + db), (uint32_t*)(buffer + db + 4));
+    db += 8;
+    }
+
+return sendto(sockr, buffer, len, 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Recv(char * buffer, int len)
+{
+#ifdef WIN32
+int fromLen;
+#else
+socklen_t fromLen;
+#endif
+
+struct sockaddr_in addr;
+fromLen = sizeof(addr);
+int res = recvfrom(sockr, buffer, len, 0, (struct sockaddr*)&addr, &fromLen);
+
+if (res == -1)
+    return res;
+
+if (strcmp(buffer + 4 + sizeof(HDR_8), "ERR"))
+    {
+    for (int i = 0; i < len/8; i++)
+        Blowfish_Decrypt(&ctxPass, (uint32_t*)(buffer + i*8), (uint32_t*)(buffer + i*8 + 4));
+    }
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::NetSend(int n)
+{
+char buffer[2048];
+int msgLen;
+
+memset(buffer, 0, 2048);
+
+switch (n)
+    {
+    case CONN_SYN_N:
+        msgLen = Prepare_CONN_SYN_8(buffer);
+        break;
+
+    case CONN_ACK_N:
+        msgLen = Prepare_CONN_ACK_8(buffer);
+        break;
+
+    case ALIVE_ACK_N:
+        msgLen = Prepare_ALIVE_ACK_8(buffer);
+        break;
+
+    case DISCONN_SYN_N:
+        msgLen = Prepare_DISCONN_SYN_8(buffer);
+        break;
+
+    case DISCONN_ACK_N:
+        msgLen = Prepare_DISCONN_ACK_8(buffer);
+        break;
+
+    default:
+        return -1;
+    }
+
+FillHdr8(buffer, 0);
+Send(buffer, msgLen);
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::NetRecv()
+{
+char buffer[2048];
+
+if (Recv(buffer, sizeof(buffer)) < 0)
+    return -1;
+
+char packetName[20];
+strncpy(packetName, buffer + 12, sizeof(packetName));
+packetName[sizeof(packetName) - 1] = 0;
+int pn = DeterminatePacketType(buffer + 12);
+
+int ret;
+switch (pn)
+    {
+    case CONN_SYN_ACK_N:
+        ret = Process_CONN_SYN_ACK_8(buffer);
+        break;
+
+    case ALIVE_SYN_N:
+        ret = Process_ALIVE_SYN_8(buffer);
+        break;
+
+    case DISCONN_SYN_ACK_N:
+        ret = Process_DISCONN_SYN_ACK_8(buffer);
+        break;
+
+    case FIN_N:
+        ret = Process_FIN_8(buffer);
+        break;
+
+    case INFO_8_N:
+        ret = Process_INFO_8(buffer);
+        break;
+
+    case ERROR_N:
+        ret = Process_ERROR(buffer);
+        break;
+
+    default:
+        ret = -1;
+    }
+return ret;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::Start()
+{
+#ifdef WIN32
+unsigned long pt;
+CreateThread(NULL, 16384, RunW, this, 0, &pt);
+#else
+pthread_create(&thread, NULL, RunL, this);
+#endif
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::Stop()
+{
+nonstop = false;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::Run()
+{
+NetRecv();
+
+switch (phase)
+    {
+    case 1:
+        if (action == IA_CONNECT)
+            {
+            action = IA_NONE;
+            NetSend(CONN_SYN_N);
+            phase = 2;
+            phaseTime = GetTickCount();
+            }
+        if (reconnect && !firstConnect)
+            {
+            action = IA_CONNECT;
+            }
+        break;
+
+    case 2:
+        if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
+            {
+            phase = 1;
+            phaseTime = GetTickCount();
+            if (pStatusChangedCb != NULL)
+                pStatusChangedCb(0, statusChangedCbData);
+            }
+
+        if (action == IA_DISCONNECT)
+            {
+            action = IA_NONE;
+            NetSend(DISCONN_SYN_N);
+            phase = 4;
+            phaseTime = GetTickCount();
+            }
+
+        break;
+
+    case 3:
+        if ((int)(GetTickCount() - phaseTime)/1000 > userTimeout)
+            {
+            phase = 1;
+            phaseTime = GetTickCount();
+            if (pStatusChangedCb != NULL)
+                pStatusChangedCb(0, statusChangedCbData);
+            firstConnect = false;
+            }
+
+        if (action == IA_DISCONNECT)
+            {
+            action = IA_NONE;
+            NetSend(DISCONN_SYN_N);
+            phase = 4;
+            phaseTime = GetTickCount();
+            }
+
+        break;
+
+    case 4:
+        if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
+            {
+            phase=1;
+            phaseTime = GetTickCount();
+            if (pStatusChangedCb != NULL)
+                pStatusChangedCb(0, statusChangedCbData);
+            }
+
+        if (action == IA_CONNECT)
+            {
+            action = IA_NONE;
+            NetSend(CONN_SYN_N);
+            phase = 2;
+            phaseTime = GetTickCount();
+            }
+
+        break;
+
+    case 5:
+        if ((int)(GetTickCount() - phaseTime)/1000 > aliveTimeout)
+            {
+            phase = 1;
+            phaseTime = GetTickCount();
+            if (pStatusChangedCb != NULL)
+                pStatusChangedCb(0, statusChangedCbData);
+            }
+
+        if (action == IA_CONNECT)
+            {
+            action = IA_NONE;
+            NetSend(CONN_SYN_N);
+            phase = 2;
+            phaseTime = GetTickCount();
+            }
+
+        break;
+    }
+Sleep(20);
+return;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::GetStat(LOADSTAT * ls)
+{
+memcpy(ls, &stat, sizeof(stat));
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetServer(const string & sn, unsigned short p)
+{
+serverName = sn;
+port = p;
+PrepareNet();
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetLogin(const string & l)
+{
+login = l;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetPassword(const string & p)
+{
+password = p;
+
+unsigned char keyL[IA_PASSWD_LEN];
+memset(keyL, 0, IA_PASSWD_LEN);
+strncpy((char *)keyL, password.c_str(), IA_PASSWD_LEN);
+Blowfish_Init(&ctxPass, keyL, IA_PASSWD_LEN);
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetEnabledDirs(const bool * selectedDirs)
+{
+memcpy(IA_CLIENT_PROT::selectedDirs, selectedDirs, sizeof(bool) * DIR_NUM);
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Connect()
+{
+action = IA_CONNECT;
+return 0;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Disconnect()
+{
+firstConnect = true;
+action = IA_DISCONNECT;
+return 0;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::GetStrError(string * error) const
+{
+int ret = codeError;
+*error = strError;
+strError = "";
+codeError = 0;
+return ret;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Process_CONN_SYN_ACK_8(const char * buffer)
+{
+vector<string> dirNames;
+connSynAck8 = (CONN_SYN_ACK_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(connSynAck8->len);
+SwapBytes(connSynAck8->rnd);
+SwapBytes(connSynAck8->userTimeOut);
+SwapBytes(connSynAck8->aliveDelay);
+#endif
+
+rnd = connSynAck8->rnd;
+userTimeout = connSynAck8->userTimeOut;
+aliveTimeout = connSynAck8->aliveDelay;
+
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    dirNames.push_back((const char*)connSynAck8->dirName[i]);
+    }
+
+if (pDirNameCb != NULL)
+    pDirNameCb(dirNames, dirNameCbData);
+
+NetSend(CONN_ACK_N);
+phase = 3;
+phaseTime = GetTickCount();
+
+return CONN_SYN_ACK_N;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Process_ALIVE_SYN_8(const char * buffer)
+{
+aliveSyn8 = (ALIVE_SYN_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(aliveSyn8->len);
+SwapBytes(aliveSyn8->rnd);
+SwapBytes(aliveSyn8->cash);
+SwapBytes(aliveSyn8->status);
+for (int i = 0; i < DIR_NUM; ++i)
+    {
+    SwapBytes(aliveSyn8->mu[i]);
+    SwapBytes(aliveSyn8->md[i]);
+    SwapBytes(aliveSyn8->su[i]);
+    SwapBytes(aliveSyn8->sd[i]);
+    }
+#endif
+
+rnd = aliveSyn8->rnd;
+memcpy(&stat, (char*)aliveSyn8->mu, sizeof(stat));
+
+if (pStatChangedCb != NULL)
+    pStatChangedCb(stat, statChangedCbData);
+
+if (pStatusChangedCb != NULL)
+    pStatusChangedCb(1, statusChangedCbData);
+NetSend(ALIVE_ACK_N);
+phaseTime = GetTickCount();
+
+return ALIVE_SYN_N;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Process_DISCONN_SYN_ACK_8(const char * buffer)
+{
+disconnSynAck8 = (DISCONN_SYN_ACK_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(disconnSynAck8->len);
+SwapBytes(disconnSynAck8->rnd);
+#endif
+
+rnd = disconnSynAck8->rnd;
+
+NetSend(DISCONN_ACK_N);
+phase = 5;
+phaseTime = GetTickCount();
+
+return DISCONN_SYN_ACK_N;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Process_FIN_8(const char *)
+{
+phase = 1;
+phaseTime = GetTickCount();
+if (pStatusChangedCb != NULL)
+    pStatusChangedCb(0, statusChangedCbData);
+
+return FIN_N;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Process_INFO_8(const char * buffer)
+{
+info = (INFO_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(info->len);
+SwapBytes(info->sendTime);
+#endif
+
+if (pInfoCb != NULL)
+    pInfoCb((char*)info->text, info->infoType, info->showTime, info->sendTime, infoCbData);
+return INFO_8_N;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Process_ERROR(const char * buffer)
+{
+memcpy(&err, buffer, sizeof(err));
+
+#ifdef ARCH_BE
+SwapBytes(err.len);
+#endif
+
+KOIToWin((const char*)err.text, &messageText);
+if (pErrorCb != NULL)
+    pErrorCb(messageText, IA_SERVER_ERROR, errorCbData);
+phase = 1;
+phaseTime = GetTickCount();
+codeError = IA_SERVER_ERROR;
+
+return ERROR_N;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Prepare_CONN_SYN_8(char * buffer)
+{
+connSyn8 = (CONN_SYN_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(connSyn8->len);
+#endif
+
+connSyn8->len = sizeof(CONN_SYN_8);
+#ifdef IA_DEBUGPROTO
+if (sizeof(CONN_SYN_8) != Min8(sizeof(CONN_SYN_8)))
+    {
+    int * a = NULL;
+    *a = 0;
+    }
+#endif
+
+strncpy((char*)connSyn8->type, "CONN_SYN", IA_MAX_TYPE_LEN);
+strncpy((char*)connSyn8->login, login.c_str(), IA_LOGIN_LEN);
+connSyn8->dirs = 0;
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    connSyn8->dirs |= (selectedDirs[i] << i);
+    }
+return connSyn8->len;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Prepare_CONN_ACK_8(char * buffer)
+{
+connAck8 = (CONN_ACK_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(connAck8->len);
+SwapBytes(connAck8->rnd);
+#endif
+
+#ifdef IA_DEBUGPROTO
+if (sizeof(CONN_ACK_8) != Min8(sizeof(CONN_ACK_8)))
+    {
+    int * a = NULL;
+    *a = 0;
+    }
+#endif
+
+connAck8->len = sizeof(CONN_ACK_8);
+strncpy((char*)connAck8->loginS, login.c_str(), IA_LOGIN_LEN);
+strncpy((char*)connAck8->type, "CONN_ACK", IA_MAX_TYPE_LEN);
+rnd++;
+connAck8->rnd = rnd;
+
+return connAck8->len;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Prepare_ALIVE_ACK_8(char * buffer)
+{
+aliveAck8 = (ALIVE_ACK_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(aliveAck8->len);
+SwapBytes(aliveAck8->rnd);
+#endif
+
+#ifdef IA_DEBUGPROTO
+if (Min8(sizeof(ALIVE_ACK_8)) != sizeof(ALIVE_ACK_8))
+    {
+    int * a = NULL;
+    *a = 0;
+    }
+#endif
+
+aliveAck8 = (ALIVE_ACK_8*)buffer;
+aliveAck8->len = sizeof(ALIVE_ACK_8);
+strncpy((char*)aliveAck8->loginS, login.c_str(), IA_LOGIN_LEN);
+strncpy((char*)aliveAck8->type, "ALIVE_ACK", IA_MAX_TYPE_LEN);
+aliveAck8->rnd = ++rnd;
+return aliveAck8->len;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Prepare_DISCONN_SYN_8(char * buffer)
+{
+disconnSyn8 = (DISCONN_SYN_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(disconnSyn8->len);
+#endif
+
+#ifdef IA_DEBUGPROTO
+if (Min8(sizeof(DISCONN_SYN_8)) != sizeof(DISCONN_SYN_8))
+    {
+    int * a = NULL;
+    *a = 0;
+    }
+#endif
+
+disconnSyn8->len = sizeof(DISCONN_SYN_8);
+strncpy((char*)disconnSyn8->loginS, login.c_str(), IA_LOGIN_LEN);
+strncpy((char*)disconnSyn8->type, "DISCONN_SYN", IA_MAX_TYPE_LEN);
+strncpy((char*)disconnSyn8->login, login.c_str(), IA_LOGIN_LEN);
+return disconnSyn8->len;
+}
+//---------------------------------------------------------------------------
+int IA_CLIENT_PROT::Prepare_DISCONN_ACK_8(char * buffer)
+{
+disconnAck8 = (DISCONN_ACK_8*)buffer;
+
+#ifdef ARCH_BE
+SwapBytes(disconnAck8->len);
+SwapBytes(disconnAck8->rnd);
+#endif
+
+#ifdef IA_DEBUGPROTO
+if (Min8(sizeof(DISCONN_ACK_8)) != sizeof(DISCONN_ACK_8))
+    {
+    int * a = NULL;
+    *a = 0;
+    }
+#endif
+
+disconnAck8->len = Min8(sizeof(DISCONN_ACK_8));
+disconnAck8->rnd = rnd + 1;
+strncpy((char*)disconnAck8->loginS, login.c_str(), IA_LOGIN_LEN);
+strncpy((char*)disconnAck8->type, "DISCONN_ACK", IA_MAX_TYPE_LEN);
+return disconnAck8->len;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetStatusChangedCb(tpStatusChangedCb p, void * data)
+{
+pStatusChangedCb = p;
+statusChangedCbData = data;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetStatChangedCb(tpStatChangedCb p, void * data)
+{
+pStatChangedCb = p;
+statChangedCbData = data;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetInfoCb(tpCallBackInfoFn p, void * data)
+{
+pInfoCb = p;
+infoCbData = data;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetDirNameCb(tpCallBackDirNameFn p, void * data)
+{
+pDirNameCb = p;
+dirNameCbData = data;
+}
+//---------------------------------------------------------------------------
+void IA_CLIENT_PROT::SetErrorCb(tpCallBackErrorFn p, void * data)
+{
+pErrorCb = p;
+errorCbData = data;
+}
+//---------------------------------------------------------------------------
diff --git a/stglibs/ia_auth_c.lib/ia_auth_c.h b/stglibs/ia_auth_c.lib/ia_auth_c.h
new file mode 100644 (file)
index 0000000..2e88cf7
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+** 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ $Author: faust $
+ $Revision: 1.10 $
+ $Date: 2010/03/15 12:57:24 $
+*/
+
+/*
+* Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+*/
+//---------------------------------------------------------------------------
+#ifndef IA_AUTH_C_H
+#define IA_AUTH_C_H
+
+#ifndef WIN32
+#include <netinet/in.h>
+#include <pthread.h>
+#else
+#include <winsock2.h>
+#endif
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "blowfish.h"
+#include "ia_packets.h"
+
+#define IA_BIND_ERROR           (1)
+#define IA_SERVER_ERROR         (2)
+#define IA_FCNTL_ERROR          (3)
+#define IA_GETHOSTBYNAME_ERROR  (4)
+
+#define IA_PROTO_VER            (8)
+#define IA_PROTO_PROXY_VER      (101)
+
+using namespace std;
+
+typedef void (*tpStatusChangedCb)(int status, void * data);
+typedef void (*tpStatChangedCb)(const LOADSTAT & stat, void * data);
+typedef void (*tpCallBackInfoFn)(const string & message, int infoType, int showTime, int sendTime, void * data);
+typedef void (*tpCallBackErrorFn)(const string & message, int netError, void * data);
+typedef void (*tpCallBackDirNameFn)(const vector<string> & dirName, void * data);
+
+//---------------------------------------------------------------------------
+class IA_CLIENT_PROT
+{
+#ifdef WIN32
+friend unsigned long WINAPI RunW(void * data);
+#else
+friend void * RunL(void * data);
+#endif
+
+public:
+    IA_CLIENT_PROT(const string & sn, uint16_t p, uint16_t localPort = 0);
+    ~IA_CLIENT_PROT();
+
+    void        Start();
+    void        Stop();
+    void        GetStat(LOADSTAT * ls);
+
+    void        SetServer(const string & sn, unsigned short port);
+    void        SetLogin(const string & login);
+    void        SetPassword(const string & password);
+    void        SetEnabledDirs(const bool * selectedDirs);
+
+    void        SetStatusChangedCb(tpStatusChangedCb p, void * data);
+    void        SetStatChangedCb(tpStatChangedCb p, void * data);
+    void        SetInfoCb(tpCallBackInfoFn p, void * data);
+    void        SetErrorCb(tpCallBackErrorFn p, void * data);
+    void        SetDirNameCb(tpCallBackDirNameFn p, void * data);
+
+    int         Connect();
+    int         Disconnect();
+    int         GetAuthorized() const { return phase == 3 || phase == 4; };   // Ìû ïîäêëþ÷åíû èëè íåò?
+    int         GetPhase() const { return phase; };
+    int         GetStatus() const;
+    int         GetReconnect() const { return reconnect; };
+    void        SetReconnect(int r) { reconnect = r; };
+    char        GetProtoVer() const { return proxyMode ? IA_PROTO_PROXY_VER : IA_PROTO_VER; };
+    void        GetMessageText(string * text) const { *text = messageText; };
+    void        GetInfoText(string * text) const { *text = infoText; };
+    int         GetStrError(string * error) const;
+
+    void        SetProxyMode(bool on) { proxyMode = on; };
+    bool        GetProxyMode() const { return proxyMode; };
+
+    void        SetIP(uint32_t ip) { IA_CLIENT_PROT::ip = ip; };
+    uint32_t    GetIP() const { return ip; };
+
+private:
+    void            Run();
+    int             NetRecv();
+    int             NetSend(int n);
+    bool            GetNonstop() const { return nonstop; };
+    void            PrepareNet();
+    int             DeterminatePacketType(const char * buffer);
+
+    int             Process_CONN_SYN_ACK_8(const char * buffer);
+    int             Process_ALIVE_SYN_8(const char * buffer);
+    int             Process_DISCONN_SYN_ACK_8(const char * buffer);
+    int             Process_FIN_8(const char * buffer);
+    int             Process_INFO_8(const char * buffer);
+    int             Process_ERROR(const char * buffer);
+
+    int             Prepare_CONN_SYN_8(char * buffer);
+    int             Prepare_CONN_ACK_8(char * buffer);
+    int             Prepare_ALIVE_ACK_8(char * buffer);
+    int             Prepare_DISCONN_SYN_8(char * buffer);
+    int             Prepare_DISCONN_ACK_8(char * buffer);
+
+    void            FillHdr8(char * buffer, unsigned long ip);
+    int             Send(char * buffer, int len);
+    int             Recv(char * buffer, int len);
+
+    LOADSTAT        stat;
+    int             action;
+    int             phase;
+    int             phaseTime;                  // Âðåìÿ âõîäà â ôàçó
+    string          messageText;                // Ñîîáùåíèå îá îøèáêå
+    string          infoText;
+    mutable string  strError;
+    mutable int     codeError;
+    bool            nonstop;
+    bool            isNetPrepared;
+    bool            proxyMode;
+
+    BLOWFISH_CTX    ctxPass;
+    BLOWFISH_CTX    ctxHdr;
+
+    bool            selectedDirs[DIR_NUM];
+
+    string          password;
+    string          login;
+
+    #ifdef WIN32
+    WSADATA wsaData;
+    #else
+    pthread_t thread;
+    #endif
+
+    string          serverName;                     // Èìÿ ñåðâåðà
+    uint16_t        port;                           // Ïîðò ñåðâåðà
+    uint32_t        ip;                             // Proxy IP
+    uint32_t        localPort;
+
+    struct sockaddr_in  localAddrS;      // Íàø àäðåñ
+    struct sockaddr_in  localAddrR;      // Íàø àäðåñ
+    struct sockaddr_in  servAddr;        // àäðåñ ñåðâåðà
+
+    bool            firstConnect;
+    int             reconnect;
+    int             sockr;
+    int             protNum;                    // ×èñëî, êîòîðîå ó÷àñòâóåò â îáìåíå ñîîáùåíèÿìèa
+    int             userTimeout;
+    int             aliveTimeout;
+    unsigned int    rnd;
+
+    tpStatusChangedCb   pStatusChangedCb;
+    tpStatChangedCb     pStatChangedCb;
+    tpCallBackInfoFn    pInfoCb;
+    tpCallBackErrorFn   pErrorCb;
+    tpCallBackDirNameFn pDirNameCb;
+
+    void              * statusChangedCbData;
+    void              * statChangedCbData;
+    void              * infoCbData;
+    void              * errorCbData;
+    void              * dirNameCbData;
+
+    map<string, int>    packetTypes;
+
+    CONN_SYN_8        * connSyn8;
+    CONN_SYN_ACK_8    * connSynAck8;
+    CONN_ACK_8        * connAck8;
+    ALIVE_SYN_8       * aliveSyn8;
+    ALIVE_ACK_8       * aliveAck8;
+    DISCONN_SYN_8     * disconnSyn8;
+    DISCONN_SYN_ACK_8 * disconnSynAck8;
+    DISCONN_ACK_8     * disconnAck8;
+    ERR_8               err;
+    INFO_8            * info;
+};
+//---------------------------------------------------------------------------
+#ifdef WIN32
+unsigned long WINAPI RunW(void *);
+#else
+void * RunW(void *);
+#endif
+
+//---------------------------------------------------------------------------
+#endif //IA_AUTH_C_H
+
+
diff --git a/stglibs/ibpp.lib/Makefile b/stglibs/ibpp.lib/Makefile
new file mode 100644 (file)
index 0000000..0c605ed
--- /dev/null
@@ -0,0 +1,37 @@
+###############################################################################
+# $Id: Makefile,v 1.6 2009/03/03 15:50:15 faust Exp $
+###############################################################################
+
+LIB_NAME = ibpp
+PROG = lib$(LIB_NAME)
+
+SRCS = array.cpp \
+       blob.cpp \
+       database.cpp \
+       date.cpp \
+       dbkey.cpp \
+       _dpb.cpp \
+       events.cpp \
+       exception.cpp \
+       _ibpp.cpp \
+       _ibs.cpp \
+       _rb.cpp \
+       row.cpp \
+       service.cpp \
+       _spb.cpp \
+       statement.cpp \
+       time.cpp \
+       _tpb.cpp \
+       transaction.cpp \
+       user.cpp
+
+INCS = ibpp.h 
+
+ADD_CXXFLAGS_1 = -DIBPP_LINUX
+
+LIBS = -lfbclient
+       
+include ../Makefile.in
+
+
+
diff --git a/stglibs/ibpp.lib/_dpb.cpp b/stglibs/ibpp.lib/_dpb.cpp
new file mode 100644 (file)
index 0000000..4729cd3
--- /dev/null
@@ -0,0 +1,120 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _dpb.cpp,v 1.2 2009/03/19 20:00:27 faust Exp $\r
+//     Subject : IBPP, internal DPB class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * DPB == Database Parameter Block/Buffer, see Interbase 6.0 C-API\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+const int DPB::BUFFERINCR = 128;\r
+\r
+void DPB::Grow(int needed)\r
+{\r
+       if (mBuffer == 0) ++needed;     // Initial alloc will require one more byte\r
+       if ((mSize + needed) > mAlloc)\r
+       {\r
+               // We need to grow the buffer. We use increments of BUFFERINCR bytes.\r
+               needed = (needed / BUFFERINCR + 1) * BUFFERINCR;\r
+               char* newbuffer = new char[mAlloc + needed];\r
+               if (mBuffer == 0)\r
+               {\r
+                       // Initial allocation, initialize the version tag\r
+                       newbuffer[0] = isc_dpb_version1;\r
+                       mSize = 1;\r
+               }\r
+               else\r
+               {\r
+                       // Move the old buffer content to the new one\r
+                       memcpy(newbuffer, mBuffer, mSize);\r
+                       delete [] mBuffer;\r
+               }\r
+               mBuffer = newbuffer;\r
+               mAlloc += needed;\r
+       }\r
+}\r
+\r
+void DPB::Insert(char type, const char* data)\r
+{\r
+       int len = (int)strlen(data);\r
+       Grow(len + 2);\r
+    mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = char(len);\r
+    strncpy(&mBuffer[mSize], data, len);\r
+    mSize += len;\r
+}\r
+\r
+void DPB::Insert(char type, int16_t data)\r
+{\r
+       Grow(2 + 2);\r
+    mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = char(2);\r
+    *(int16_t*)&mBuffer[mSize] = int16_t((*gds.Call()->m_vax_integer)((char*)&data, 2));\r
+    mSize += 2;\r
+}\r
+\r
+void DPB::Insert(char type, bool data)\r
+{\r
+       Grow(2 + 1);\r
+    mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = char(1);\r
+    mBuffer[mSize++] = char(data ? 1 : 0);\r
+}\r
+\r
+void DPB::Insert(char type, char data)\r
+{\r
+       Grow(2 + 1);\r
+    mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = char(1);\r
+    mBuffer[mSize++] = data;\r
+}\r
+\r
+void DPB::Reset()\r
+{\r
+       if (mAlloc != 0)\r
+    {\r
+       delete [] mBuffer;\r
+        mBuffer = 0;\r
+        mSize = 0;\r
+               mAlloc = 0;\r
+    }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/_ibpp.cpp b/stglibs/ibpp.lib/_ibpp.cpp
new file mode 100644 (file)
index 0000000..3374b96
--- /dev/null
@@ -0,0 +1,367 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _ibpp.cpp,v 1.3 2009/03/19 20:00:27 faust Exp $\r
+//     Subject : IBPP, Initialization of the library\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <limits>\r
+\r
+#ifdef IBPP_WINDOWS\r
+// New (optional) Registry Keys introduced by Firebird Server 1.5\r
+#define REG_KEY_ROOT_INSTANCES "SOFTWARE\\Firebird Project\\Firebird Server\\Instances"\r
+#define FB_DEFAULT_INSTANCE            "DefaultInstance"\r
+#endif\r
+\r
+namespace ibpp_internals\r
+{\r
+       const double consts::dscales[19] = {\r
+                 1, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,\r
+                 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15,\r
+                 1E16, 1E17, 1E18 };\r
+\r
+       const int consts::Dec31_1899 = 693595;\r
+\r
+// Many compilers confuses those following min/max with macros min and max !\r
+#undef min\r
+#undef max\r
+\r
+#ifdef __DMC__ // Needs to break-down the declaration else compiler crash (!)\r
+       const std::numeric_limits<int16_t> i16_limits;\r
+       const std::numeric_limits<int32_t> i32_limits;\r
+       const int16_t consts::min16 = i16_limits.min();\r
+       const int16_t consts::max16 = i16_limits.max();\r
+       const int32_t consts::min32 = i32_limits.min();\r
+       const int32_t consts::max32 = i32_limits.max();\r
+#else\r
+       const int16_t consts::min16 = std::numeric_limits<int16_t>::min();\r
+       const int16_t consts::max16 = std::numeric_limits<int16_t>::max();\r
+       const int32_t consts::min32 = std::numeric_limits<int32_t>::min();\r
+       const int32_t consts::max32 = std::numeric_limits<int32_t>::max();\r
+#endif\r
+\r
+       GDS gds;        // Global unique GDS instance\r
+\r
+#ifdef IBPP_WINDOWS\r
+       std::string AppPath;    // Used by GDS::Call() below\r
+#endif\r
+\r
+#ifdef _DEBUG\r
+       std::ostream& operator<< (std::ostream& a, flush_debug_stream_type)\r
+       {\r
+               if (std::stringstream* p = dynamic_cast<std::stringstream*>(&a))\r
+               {\r
+#ifdef IBPP_WINDOWS\r
+                       ::OutputDebugString(("IBPP: " + p->str() + "\n").c_str());\r
+#endif\r
+                       p->str("");\r
+               }\r
+               return a;\r
+       }\r
+#endif // _DEBUG\r
+\r
+}\r
+\r
+using namespace ibpp_internals;\r
+\r
+GDS* GDS::Call()\r
+{\r
+       // Let's load the CLIENT library, if it is not already loaded.\r
+       // The load is guaranteed to be done only once per application.\r
+\r
+       if (! mReady)\r
+       {\r
+#ifdef IBPP_WINDOWS\r
+\r
+               // Let's load the FBCLIENT.DLL or GDS32.DLL, we will never release it.\r
+               // Windows will do that for us when the executable will terminate.\r
+\r
+               char fbdll[MAX_PATH];\r
+               HKEY hkey_instances;\r
+\r
+               // Try to load FBCLIENT.DLL from each of the additional optional paths\r
+               // that may have been specified through ClientLibSearchPaths().\r
+               // We also want to actually update the environment PATH so that it references\r
+               // the specific path from where we attempt the load. This is useful because\r
+               // it directs the system to attempt finding dependencies (like the C/C++\r
+               // runtime libraries) from the same location where FBCLIENT is found.\r
+\r
+               mHandle = 0;\r
+\r
+               std::string SysPath(getenv("PATH"));\r
+               std::string::size_type pos = 0;\r
+               while (pos < mSearchPaths.size())\r
+               {\r
+                       std::string::size_type newpos = mSearchPaths.find(';', pos);\r
+\r
+                       std::string path;\r
+                       if (newpos == std::string::npos) path = mSearchPaths.substr(pos);\r
+                       else path = mSearchPaths.substr(pos, newpos-pos);\r
+\r
+                       if (path.size() >= 1)\r
+                       {\r
+                               if (path[path.size()-1] != '\\') path += '\\';\r
+\r
+                               AppPath.assign("PATH=");\r
+                               AppPath.append(path).append(";").append(SysPath);\r
+                               putenv(AppPath.c_str());\r
+\r
+                               path.append("fbclient.dll");\r
+                               mHandle = LoadLibrary(path.c_str());\r
+                               if (mHandle != 0 || newpos == std::string::npos) break;\r
+                       }\r
+                       pos = newpos + 1;\r
+               }\r
+\r
+               if (mHandle == 0)\r
+               {\r
+                       // Try to load FBCLIENT.DLL from the current application location.  This\r
+                       // is a usefull step for applications using the embedded version of FB\r
+                       // or a local copy (for whatever reasons) of the dll.\r
+\r
+                       if (! AppPath.empty())\r
+                       {\r
+                               // Restores the original system path\r
+                               AppPath.assign("PATH=");\r
+                               AppPath.append(SysPath);\r
+                               putenv(AppPath.c_str());\r
+                       }\r
+\r
+                       int len = GetModuleFileName(NULL, fbdll, sizeof(fbdll));\r
+                       if (len != 0)\r
+                       {\r
+                               // Get to the last '\' (this one precedes the filename part).\r
+                               // There is always one after a success call to GetModuleFileName().\r
+                               char* p = fbdll + len;\r
+                               do {--p;} while (*p != '\\');\r
+                               *p = '\0';\r
+                               lstrcat(fbdll, "\\fbembed.dll");// Local copy could be named fbembed.dll\r
+                               mHandle = LoadLibrary(fbdll);\r
+                               if (mHandle == 0)\r
+                               {\r
+                                       *p = '\0';\r
+                                       lstrcat(fbdll, "\\fbclient.dll");       // Or possibly renamed fbclient.dll\r
+                                       mHandle = LoadLibrary(fbdll);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if (mHandle == 0)\r
+               {\r
+                       // Try to locate FBCLIENT.DLL through the optional FB registry key.\r
+\r
+                       if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY_ROOT_INSTANCES, 0,\r
+                               KEY_READ, &hkey_instances) == ERROR_SUCCESS)\r
+                       {\r
+                               DWORD keytype;\r
+                               DWORD buflen = sizeof(fbdll);\r
+                               if (RegQueryValueEx(hkey_instances, FB_DEFAULT_INSTANCE, 0,\r
+                                               &keytype, reinterpret_cast<UCHAR*>(fbdll),\r
+                                                       &buflen) == ERROR_SUCCESS && keytype == REG_SZ)\r
+                               {\r
+                                       lstrcat(fbdll, "bin\\fbclient.dll");\r
+                                       mHandle = LoadLibrary(fbdll);\r
+                               }\r
+                               RegCloseKey(hkey_instances);\r
+                       }\r
+               }\r
+\r
+               if (mHandle == 0)\r
+               {\r
+                       // Let's try from the PATH and System directories\r
+                       mHandle = LoadLibrary("fbclient.dll");\r
+                       if (mHandle == 0)\r
+                       {\r
+                               // Not found. Last try : attemps loading gds32.dll from PATH and\r
+                               // System directories\r
+                               mHandle = LoadLibrary("gds32.dll");\r
+                               if (mHandle == 0)\r
+                                       throw LogicExceptionImpl("GDS::Call()",\r
+                                               _("Can't find or load FBCLIENT.DLL or GDS32.DLL"));\r
+                       }\r
+               }\r
+#endif\r
+\r
+               mGDSVersion = 60;\r
+\r
+               // Get the entry points that we need\r
+\r
+#ifdef IBPP_WINDOWS\r
+#define IB_ENTRYPOINT(X) \\r
+                       if ((m_##X = (proto_##X*)GetProcAddress(mHandle, "isc_"#X)) == 0) \\r
+                               throw LogicExceptionImpl("GDS:gds()", _("Entry-point isc_"#X" not found"))\r
+#endif\r
+#ifdef IBPP_UNIX\r
+/* TODO : perform a late-bind on unix --- not so important, well I think (OM) */\r
+#define IB_ENTRYPOINT(X) m_##X = (proto_##X*)isc_##X\r
+#endif\r
+\r
+               IB_ENTRYPOINT(create_database);\r
+               IB_ENTRYPOINT(attach_database);\r
+               IB_ENTRYPOINT(detach_database);\r
+               IB_ENTRYPOINT(drop_database);\r
+               IB_ENTRYPOINT(database_info);\r
+               IB_ENTRYPOINT(open_blob2);\r
+               IB_ENTRYPOINT(create_blob2);\r
+               IB_ENTRYPOINT(close_blob);\r
+               IB_ENTRYPOINT(cancel_blob);\r
+               IB_ENTRYPOINT(get_segment);\r
+               IB_ENTRYPOINT(put_segment);\r
+               IB_ENTRYPOINT(blob_info);\r
+               IB_ENTRYPOINT(array_lookup_bounds);\r
+               IB_ENTRYPOINT(array_get_slice);\r
+               IB_ENTRYPOINT(array_put_slice);\r
+               IB_ENTRYPOINT(vax_integer);\r
+               IB_ENTRYPOINT(sqlcode);\r
+               IB_ENTRYPOINT(sql_interprete);\r
+               IB_ENTRYPOINT(interprete);\r
+               IB_ENTRYPOINT(que_events);\r
+               IB_ENTRYPOINT(cancel_events);\r
+               IB_ENTRYPOINT(start_multiple);\r
+               IB_ENTRYPOINT(commit_transaction);\r
+               IB_ENTRYPOINT(commit_retaining);\r
+               IB_ENTRYPOINT(rollback_transaction);\r
+               IB_ENTRYPOINT(rollback_retaining);\r
+               IB_ENTRYPOINT(dsql_execute_immediate);\r
+               IB_ENTRYPOINT(dsql_allocate_statement);\r
+               IB_ENTRYPOINT(dsql_describe);\r
+               IB_ENTRYPOINT(dsql_describe_bind);\r
+               IB_ENTRYPOINT(dsql_prepare);\r
+               IB_ENTRYPOINT(dsql_execute);\r
+               IB_ENTRYPOINT(dsql_execute2);\r
+               IB_ENTRYPOINT(dsql_fetch);\r
+               IB_ENTRYPOINT(dsql_free_statement);\r
+               IB_ENTRYPOINT(dsql_set_cursor_name);\r
+               IB_ENTRYPOINT(dsql_sql_info);\r
+\r
+               IB_ENTRYPOINT(service_attach);\r
+               IB_ENTRYPOINT(service_detach);\r
+               IB_ENTRYPOINT(service_start);\r
+               IB_ENTRYPOINT(service_query);\r
+\r
+               mReady = true;\r
+       }\r
+\r
+       return this;\r
+}\r
+\r
+namespace IBPP\r
+{\r
+\r
+       bool CheckVersion(uint32_t AppVersion)\r
+       {\r
+               //(void)gds.Call();             // Just call it to trigger the initialization\r
+               return (AppVersion & 0xFFFFFF00) ==\r
+                               (IBPP::Version & 0xFFFFFF00) ? true : false;\r
+       }\r
+\r
+       int GDSVersion()\r
+       {\r
+               return gds.Call()->mGDSVersion;\r
+       }\r
+\r
+#ifdef IBPP_WINDOWS\r
+       void ClientLibSearchPaths(const std::string& paths)\r
+       {\r
+               gds.mSearchPaths.assign(paths);\r
+       }\r
+#else\r
+       void ClientLibSearchPaths(const std::string&)\r
+       {\r
+       }\r
+#endif\r
+\r
+       //      Factories for our Interface objects\r
+\r
+       Service ServiceFactory(const std::string& ServerName,\r
+                               const std::string& UserName, const std::string& UserPassword)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new ServiceImpl(ServerName, UserName, UserPassword);\r
+       }\r
+\r
+       Database DatabaseFactory(const std::string& ServerName,\r
+               const std::string& DatabaseName, const std::string& UserName,\r
+               const std::string& UserPassword, const std::string& RoleName,\r
+               const std::string& CharSet, const std::string& CreateParams)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new DatabaseImpl(ServerName, DatabaseName, UserName,\r
+                                                               UserPassword, RoleName, CharSet, CreateParams);\r
+       }\r
+\r
+       Transaction TransactionFactory(Database db, TAM am,\r
+                                       TIL il, TLR lr, TFF flags)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new TransactionImpl(     dynamic_cast<DatabaseImpl*>(db.intf()),\r
+                                                                       am, il, lr, flags);\r
+       }\r
+\r
+       Statement StatementFactory(Database db, Transaction tr,\r
+               const std::string& sql)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new StatementImpl(       dynamic_cast<DatabaseImpl*>(db.intf()),\r
+                                                                       dynamic_cast<TransactionImpl*>(tr.intf()),\r
+                                                                       sql);\r
+       }\r
+\r
+       Blob BlobFactory(Database db, Transaction tr)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new BlobImpl(dynamic_cast<DatabaseImpl*>(db.intf()),\r
+                                                       dynamic_cast<TransactionImpl*>(tr.intf()));\r
+       }\r
+\r
+       Array ArrayFactory(Database db, Transaction tr)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new ArrayImpl(dynamic_cast<DatabaseImpl*>(db.intf()),\r
+                                                       dynamic_cast<TransactionImpl*>(tr.intf()));\r
+       }\r
+\r
+       Events EventsFactory(Database db)\r
+       {\r
+               (void)gds.Call();                       // Triggers the initialization, if needed\r
+               return new EventsImpl(dynamic_cast<DatabaseImpl*>(db.intf()));\r
+       }\r
+\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
+\r
diff --git a/stglibs/ibpp.lib/_ibpp.h b/stglibs/ibpp.lib/_ibpp.h
new file mode 100644 (file)
index 0000000..e7af2ea
--- /dev/null
@@ -0,0 +1,1414 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _ibpp.h,v 1.2 2007/05/17 08:37:05 faust Exp $\r
+//     Subject : IBPP internal declarations\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//\r
+//     * 'Internal declarations' means everything used to implement ibpp. This\r
+//       file and its contents is NOT needed by users of the library. All those\r
+//       declarations are wrapped in a namespace : 'ibpp_internals'.\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef __INTERNAL_IBPP_H__\r
+#define __INTERNAL_IBPP_H__\r
+\r
+#include "ibpp.h"\r
+\r
+#if defined(__BCPLUSPLUS__) || defined(_MSC_VER) || defined(__DMC__)\r
+#define HAS_HDRSTOP\r
+#endif\r
+\r
+#if (defined(__GNUC__) && defined(IBPP_WINDOWS))\r
+//     Setting flags for ibase.h -- using GCC/Cygwin/MinGW on Win32\r
+#ifndef _MSC_VER\r
+#define _MSC_VER 1299\r
+#endif\r
+#ifndef _WIN32\r
+#define _WIN32   1\r
+#endif\r
+#endif\r
+\r
+#include "ibase.h"             // From Firebird 1.x or InterBase 6.x installation\r
+\r
+#if (defined(__GNUC__) && defined(IBPP_WINDOWS))\r
+//     UNSETTING flags used above for ibase.h -- Huge conflicts with libstdc++ !\r
+#undef _MSC_VER\r
+#undef _WIN32\r
+#endif\r
+\r
+#ifdef IBPP_WINDOWS\r
+#include <windows.h>\r
+#endif\r
+\r
+//#include <limits>\r
+#include <string>\r
+#include <vector>\r
+#include <sstream>\r
+#include <cstdarg>\r
+\r
+#ifdef _DEBUG\r
+#define ASSERTION(x)   {if (!(x)) {throw LogicExceptionImpl("ASSERTION", \\r
+                                                       "'"#x"' is not verified at %s, line %d", \\r
+                                                               __FILE__, __LINE__);}}\r
+#else\r
+#define ASSERTION(x)   /* x */\r
+#endif\r
+\r
+// Fix to famous MSVC 6 variable scope bug\r
+#if defined(_MSC_VER) && (_MSC_VER < 1300)     // MSVC 6 should be < 1300\r
+#define for if(true)for\r
+#endif\r
+\r
+namespace ibpp_internals\r
+{\r
+\r
+enum flush_debug_stream_type {fds};\r
+\r
+#ifdef _DEBUG\r
+\r
+struct DebugStream : public std::stringstream\r
+{\r
+       // next two operators fix some g++ and vc++ related problems\r
+       std::ostream& operator<< (const char* p)\r
+               { static_cast<std::stringstream&>(*this)<< p; return *this; }\r
+\r
+       std::ostream& operator<< (const std::string& p)\r
+               { static_cast<std::stringstream&>(*this)<< p; return *this; }\r
+\r
+       DebugStream& operator=(const DebugStream&) {return *this;}\r
+       DebugStream(const DebugStream&) {}\r
+       DebugStream() {}\r
+};\r
+std::ostream& operator<< (std::ostream& a, flush_debug_stream_type);\r
+\r
+#else\r
+\r
+struct DebugStream\r
+{\r
+       template<class T> DebugStream& operator<< (const T&) { return *this; }\r
+       // for manipulators\r
+       DebugStream& operator<< (std::ostream&(*)(std::ostream&)) { return *this; }\r
+};\r
+\r
+#endif // _DEBUG\r
+\r
+class DatabaseImpl;\r
+class TransactionImpl;\r
+class StatementImpl;\r
+class BlobImpl;\r
+class ArrayImpl;\r
+class EventsImpl;\r
+\r
+//     Native data types\r
+typedef enum {ivArray, ivBlob, ivDate, ivTime, ivTimestamp, ivString,\r
+                       ivInt16, ivInt32, ivInt64, ivFloat, ivDouble,\r
+                       ivBool, ivDBKey, ivByte} IITYPE;\r
+\r
+//\r
+//     Those are the Interbase C API prototypes that we use\r
+//     Taken 'asis' from IBASE.H, prefix 'isc_' replaced with 'proto_',\r
+//     and 'typedef' preprended...\r
+//\r
+\r
+typedef ISC_STATUS ISC_EXPORT proto_create_database (ISC_STATUS *,\r
+                                           short,\r
+                                           char *,\r
+                                           isc_db_handle *,\r
+                                           short,\r
+                                           char *,\r
+                                           short);\r
+\r
+typedef ISC_STATUS ISC_EXPORT proto_attach_database (ISC_STATUS *,\r
+                                           short,\r
+                                           char *,\r
+                                           isc_db_handle *,\r
+                                           short,\r
+                                           char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_detach_database (ISC_STATUS *,\r
+                                           isc_db_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_drop_database (ISC_STATUS *,\r
+                                         isc_db_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_database_info (ISC_STATUS *,\r
+                                         isc_db_handle *,\r
+                                         short,\r
+                                         char *,\r
+                                         short,\r
+                                         char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_execute_immediate (ISC_STATUS *,\r
+                                                  isc_db_handle *,\r
+                                                  isc_tr_handle *,\r
+                                                  unsigned short,\r
+                                                  char *,\r
+                                                  unsigned short,\r
+                                                  XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_open_blob2 (ISC_STATUS *,\r
+                                      isc_db_handle *,\r
+                                      isc_tr_handle *,\r
+                                      isc_blob_handle *,\r
+                                      ISC_QUAD *,\r
+                                      short,\r
+                                      char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_create_blob2 (ISC_STATUS *,\r
+                                       isc_db_handle *,\r
+                                       isc_tr_handle *,\r
+                                       isc_blob_handle *,\r
+                                       ISC_QUAD *,\r
+                                       short,\r
+                                       char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_close_blob (ISC_STATUS *,\r
+                                      isc_blob_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_cancel_blob (ISC_STATUS *,\r
+                                       isc_blob_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_get_segment (ISC_STATUS *,\r
+                                       isc_blob_handle *,\r
+                                       unsigned short *,\r
+                                       unsigned short,\r
+                                       char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_put_segment (ISC_STATUS *,\r
+                                       isc_blob_handle *,\r
+                                       unsigned short,\r
+                                       char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_blob_info (ISC_STATUS *,\r
+                                     isc_blob_handle *,\r
+                                     short,\r
+                                     char *,\r
+                                     short,\r
+                                     char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_array_lookup_bounds (ISC_STATUS *,\r
+                                               isc_db_handle *,\r
+                                               isc_tr_handle *,\r
+                                               char *,\r
+                                               char *,\r
+                                               ISC_ARRAY_DESC *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_array_get_slice (ISC_STATUS *,\r
+                                           isc_db_handle *,\r
+                                           isc_tr_handle *,\r
+                                           ISC_QUAD *,\r
+                                           ISC_ARRAY_DESC *,\r
+                                           void *,\r
+                                           ISC_LONG *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_array_put_slice (ISC_STATUS *,\r
+                                           isc_db_handle *,\r
+                                           isc_tr_handle *,\r
+                                           ISC_QUAD *,\r
+                                           ISC_ARRAY_DESC *,\r
+                                           void *,\r
+                                           ISC_LONG *);\r
+\r
+typedef ISC_LONG    ISC_EXPORT proto_vax_integer (char *,\r
+                                       short);\r
+\r
+typedef ISC_LONG    ISC_EXPORT proto_sqlcode (ISC_STATUS *);\r
+\r
+typedef void        ISC_EXPORT proto_sql_interprete (short,\r
+                                          char *,\r
+                                          short);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_interprete (char *,\r
+                                      ISC_STATUS * *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_que_events (ISC_STATUS *,\r
+                                      isc_db_handle *,\r
+                                      ISC_LONG *,\r
+                                      short,\r
+                                      char *,\r
+                                      isc_callback,\r
+                                      void *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_cancel_events (ISC_STATUS *,\r
+                                         isc_db_handle *,\r
+                                         ISC_LONG *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_start_multiple (ISC_STATUS *,\r
+                                          isc_tr_handle *,\r
+                                          short,\r
+                                          void *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_commit_transaction (ISC_STATUS *,\r
+                                              isc_tr_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_commit_retaining (ISC_STATUS *,\r
+                                            isc_tr_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_rollback_transaction (ISC_STATUS *,\r
+                                                isc_tr_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_rollback_retaining (ISC_STATUS *,\r
+                                                isc_tr_handle *);\r
+\r
+///////////\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_allocate_statement (ISC_STATUS *,\r
+                                                   isc_db_handle *,\r
+                                                   isc_stmt_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_describe (ISC_STATUS *,\r
+                                         isc_stmt_handle *,\r
+                                         unsigned short,\r
+                                         XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_describe_bind (ISC_STATUS *,\r
+                                              isc_stmt_handle *,\r
+                                              unsigned short,\r
+                                              XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_execute (ISC_STATUS *,\r
+                                        isc_tr_handle *,\r
+                                        isc_stmt_handle *,\r
+                                        unsigned short,\r
+                                        XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_execute2 (ISC_STATUS *,\r
+                                         isc_tr_handle *,\r
+                                         isc_stmt_handle *,\r
+                                         unsigned short,\r
+                                         XSQLDA *,\r
+                                         XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_fetch (ISC_STATUS *,\r
+                                      isc_stmt_handle *,\r
+                                      unsigned short,\r
+                                      XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_free_statement (ISC_STATUS *,\r
+                                               isc_stmt_handle *,\r
+                                               unsigned short);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_prepare (ISC_STATUS *,\r
+                                        isc_tr_handle *,\r
+                                        isc_stmt_handle *,\r
+                                        unsigned short,\r
+                                        char *,\r
+                                        unsigned short,\r
+                                        XSQLDA *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_set_cursor_name (ISC_STATUS *,\r
+                                                isc_stmt_handle *,\r
+                                                char *,\r
+                                                unsigned short);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_dsql_sql_info (ISC_STATUS *,\r
+                                         isc_stmt_handle *,\r
+                                         short,\r
+                                         char *,\r
+                                         short,\r
+                                         char *);\r
+\r
+typedef void        ISC_EXPORT proto_decode_date (ISC_QUAD *,\r
+                                       void *);\r
+\r
+typedef void        ISC_EXPORT proto_encode_date (void *,\r
+                                       ISC_QUAD *);\r
+\r
+typedef int                    ISC_EXPORT proto_add_user (ISC_STATUS *, USER_SEC_DATA *);\r
+typedef int                    ISC_EXPORT proto_delete_user (ISC_STATUS *, USER_SEC_DATA *);\r
+typedef int                    ISC_EXPORT proto_modify_user (ISC_STATUS *, USER_SEC_DATA *);\r
+\r
+//\r
+//     Those API are only available in versions 6.x of the GDS32.DLL\r
+//\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_service_attach (ISC_STATUS *,\r
+                                          unsigned short,\r
+                                          char *,\r
+                                          isc_svc_handle *,\r
+                                          unsigned short,\r
+                                          char *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_service_detach (ISC_STATUS *,\r
+                                          isc_svc_handle *);\r
+\r
+typedef ISC_STATUS  ISC_EXPORT proto_service_query (ISC_STATUS *,\r
+                                         isc_svc_handle *,\r
+                                         isc_resv_handle *,\r
+                                         unsigned short,\r
+                                         char *,\r
+                                         unsigned short,\r
+                                         char *,\r
+                                         unsigned short,\r
+                                         char *);\r
+\r
+typedef ISC_STATUS ISC_EXPORT proto_service_start (ISC_STATUS *,\r
+                                        isc_svc_handle *,\r
+                                        isc_resv_handle *,\r
+                                        unsigned short,\r
+                                        char*);\r
+\r
+typedef void        ISC_EXPORT proto_decode_sql_date (ISC_DATE *,\r
+                                       void *);\r
+\r
+typedef void        ISC_EXPORT proto_decode_sql_time (ISC_TIME *,\r
+                                       void *);\r
+\r
+typedef void        ISC_EXPORT proto_decode_timestamp (ISC_TIMESTAMP *,\r
+                                       void *);\r
+\r
+typedef void        ISC_EXPORT proto_encode_sql_date (void *,\r
+                                       ISC_DATE *);\r
+\r
+typedef void        ISC_EXPORT proto_encode_sql_time (void *,\r
+                                       ISC_TIME *);\r
+\r
+typedef void        ISC_EXPORT proto_encode_timestamp (void *,\r
+                                       ISC_TIMESTAMP *);\r
+\r
+//\r
+//     Internal binding structure to the GDS32 DLL\r
+//\r
+\r
+struct GDS\r
+{\r
+       // Attributes\r
+       bool mReady;\r
+       int mGDSVersion;                // Version of the GDS32.DLL (50 for 5.0, 60 for 6.0)\r
+\r
+#ifdef IBPP_WINDOWS\r
+       HMODULE mHandle;                        // The GDS32.DLL HMODULE\r
+       std::string mSearchPaths;       // Optional additional search paths\r
+#endif\r
+\r
+       GDS* Call();\r
+\r
+       // GDS32 Entry Points\r
+       proto_create_database*                  m_create_database;\r
+       proto_attach_database*                  m_attach_database;\r
+       proto_detach_database*                  m_detach_database;\r
+       proto_drop_database*                    m_drop_database;\r
+       proto_database_info*                    m_database_info;\r
+       proto_dsql_execute_immediate*   m_dsql_execute_immediate;\r
+       proto_open_blob2*                               m_open_blob2;\r
+       proto_create_blob2*                             m_create_blob2;\r
+       proto_close_blob*                               m_close_blob;\r
+       proto_cancel_blob*                              m_cancel_blob;\r
+       proto_get_segment*                              m_get_segment;\r
+       proto_put_segment*                              m_put_segment;\r
+       proto_blob_info*                                m_blob_info;\r
+       proto_array_lookup_bounds*              m_array_lookup_bounds;\r
+       proto_array_get_slice*                  m_array_get_slice;\r
+       proto_array_put_slice*                  m_array_put_slice;\r
+\r
+       proto_vax_integer*                              m_vax_integer;\r
+       proto_sqlcode*                                  m_sqlcode;\r
+       proto_sql_interprete*                   m_sql_interprete;\r
+       proto_interprete*                               m_interprete;\r
+       proto_que_events*                               m_que_events;\r
+       proto_cancel_events*                    m_cancel_events;\r
+       proto_start_multiple*                   m_start_multiple;\r
+       proto_commit_transaction*               m_commit_transaction;\r
+       proto_commit_retaining*                 m_commit_retaining;\r
+       proto_rollback_transaction*             m_rollback_transaction;\r
+       proto_rollback_retaining*               m_rollback_retaining;\r
+       proto_dsql_allocate_statement*  m_dsql_allocate_statement;\r
+       proto_dsql_describe*                    m_dsql_describe;\r
+       proto_dsql_describe_bind*               m_dsql_describe_bind;\r
+       proto_dsql_prepare*                             m_dsql_prepare;\r
+       proto_dsql_execute*                             m_dsql_execute;\r
+       proto_dsql_execute2*                    m_dsql_execute2;\r
+       proto_dsql_fetch*                               m_dsql_fetch;\r
+       proto_dsql_free_statement*              m_dsql_free_statement;\r
+       proto_dsql_set_cursor_name*             m_dsql_set_cursor_name;\r
+       proto_dsql_sql_info*                    m_dsql_sql_info;\r
+       //proto_decode_date*                            m_decode_date;\r
+       //proto_encode_date*                            m_encode_date;\r
+       //proto_add_user*                                       m_add_user;\r
+       //proto_delete_user*                            m_delete_user;\r
+       //proto_modify_user*                            m_modify_user;\r
+\r
+       proto_service_attach*                   m_service_attach;\r
+       proto_service_detach*                   m_service_detach;\r
+       proto_service_start*                    m_service_start;\r
+       proto_service_query*                    m_service_query;\r
+       //proto_decode_sql_date*                        m_decode_sql_date;\r
+       //proto_decode_sql_time*                        m_decode_sql_time;\r
+       //proto_decode_timestamp*                       m_decode_timestamp;\r
+       //proto_encode_sql_date*                        m_encode_sql_date;\r
+       //proto_encode_sql_time*                        m_encode_sql_time;\r
+       //proto_encode_timestamp*                       m_encode_timestamp;\r
+\r
+       // Constructor (No need for a specific destructor)\r
+       GDS()\r
+       {\r
+               mReady = false;\r
+               mGDSVersion = 0;\r
+#ifdef IBPP_WINDOWS\r
+               mHandle = 0;\r
+#endif\r
+       };\r
+};\r
+\r
+extern GDS gds;\r
+\r
+//\r
+//     Service Parameter Block (used to define a service)\r
+//\r
+\r
+class SPB\r
+{\r
+       static const int BUFFERINCR;\r
+\r
+       char* mBuffer;                          // Dynamically allocated SPB structure\r
+       int mSize;                              // Its used size in bytes\r
+       int mAlloc;                                     // Its allocated size in bytes\r
+\r
+       void Grow(int needed);          // Alloc or grow the mBuffer\r
+\r
+public:\r
+       void Insert(char);                      // Insert a single byte code\r
+       void InsertString(char, int, const char*);      // Insert a string, len can be defined as 1 or 2 bytes\r
+       void InsertByte(char type, char data);\r
+       void InsertQuad(char type, int32_t data);\r
+       void Reset();                   // Clears the SPB\r
+       char* Self() { return mBuffer; }\r
+       short Size() { return (short)mSize; }\r
+\r
+       SPB() : mBuffer(0), mSize(0), mAlloc(0) { }\r
+       ~SPB() { Reset(); }\r
+};\r
+\r
+//\r
+//     Database Parameter Block (used to define a database)\r
+//\r
+\r
+class DPB\r
+{\r
+       static const int BUFFERINCR;\r
+\r
+       char* mBuffer;                          // Dynamically allocated DPB structure\r
+       int mSize;                              // Its used size in bytes\r
+       int mAlloc;                                     // Its allocated size in bytes\r
+\r
+       void Grow(int needed);          // Allocate or grow the mBuffer, so that\r
+                                                               // 'needed' bytes can be written (at least)\r
+\r
+public:\r
+       void Insert(char, const char*); // Insert a new char* 'cluster'\r
+       void Insert(char, int16_t);             // Insert a new int16_t 'cluster'\r
+       void Insert(char, bool);                // Insert a new bool 'cluster'\r
+       void Insert(char, char);                // Insert a new byte 'cluster'\r
+       void Reset();                           // Clears the DPB\r
+       char* Self() { return mBuffer; }\r
+       short Size() { return (short)mSize; }\r
+\r
+       DPB() : mBuffer(0), mSize(0), mAlloc(0) { }\r
+       ~DPB() { Reset(); }\r
+};\r
+\r
+//\r
+//     Transaction Parameter Block (used to define a transaction)\r
+//\r
+\r
+class TPB\r
+{\r
+       static const int BUFFERINCR;\r
+\r
+       char* mBuffer;                                  // Dynamically allocated TPB structure\r
+       int mSize;                                              // Its used size in bytes\r
+       int mAlloc;                                             // Its allocated size\r
+\r
+       void Grow(int needed);                  // Alloc or re-alloc the mBuffer\r
+\r
+public:\r
+       void Insert(char);                              // Insert a flag item\r
+       void Insert(const std::string& data); // Insert a string (typically table name)\r
+       void Reset();                           // Clears the TPB\r
+       char* Self() { return mBuffer; }\r
+       int Size() { return mSize; }\r
+\r
+       TPB() : mBuffer(0), mSize(0), mAlloc(0) { }\r
+       ~TPB() { Reset(); }\r
+};\r
+\r
+//\r
+//     Used to receive (and process) a results buffer in various API calls\r
+//\r
+\r
+class RB\r
+{\r
+       char* mBuffer;\r
+       int mSize;\r
+\r
+       char* FindToken(char token);\r
+       char* FindToken(char token, char subtoken);\r
+\r
+public:\r
+       void Reset();\r
+       int GetValue(char token);\r
+       int GetCountValue(char token);\r
+       int GetValue(char token, char subtoken);\r
+       bool GetBool(char token);\r
+       int GetString(char token, std::string& data);\r
+\r
+       char* Self() { return mBuffer; }\r
+       short Size() { return (short)mSize; }\r
+\r
+       RB();\r
+       RB(int Size);\r
+       ~RB();\r
+};\r
+\r
+//\r
+//     Used to receive status info from API calls\r
+//\r
+\r
+class IBS\r
+{\r
+       mutable ISC_STATUS mVector[20];\r
+       mutable std::string mMessage;\r
+\r
+public:\r
+       ISC_STATUS* Self() { return mVector; }\r
+       bool Errors() { return (mVector[0] == 1 && mVector[1] > 0) ? true : false; }\r
+       const char* ErrorMessage() const;\r
+       int SqlCode() const;\r
+       int EngineCode() const { return (mVector[0] == 1) ? (int)mVector[1] : 0; }\r
+       void Reset();\r
+\r
+       IBS();\r
+       IBS(IBS&);      // Copy Constructor\r
+       ~IBS();\r
+};\r
+\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     Implementation of the "hidden" classes associated with their public\r
+//     counterparts. Their private data and methods can freely change without\r
+//     breaking the compatibility of the DLL. If they receive new public methods,\r
+//     and those methods are reflected in the public class, then the compatibility\r
+//     is broken.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+//\r
+// Hidden implementation of Exception classes.\r
+//\r
+\r
+/*\r
+                         std::exception\r
+                                |\r
+                         IBPP::Exception\r
+                       /                 \\r
+                      /                   \\r
+  IBPP::LogicException    ExceptionBase    IBPP::SQLException\r
+        |        \         /   |     \     /\r
+        |   LogicExceptionImpl |   SQLExceptionImpl\r
+        |                      |\r
+    IBPP::WrongType            |\r
+               \               |\r
+              IBPP::WrongTypeImpl\r
+*/\r
+\r
+class ExceptionBase\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+protected:\r
+       std::string mContext;                   // Exception context ("IDatabase::Drop")\r
+       std::string mWhat;                              // Full formatted message\r
+\r
+       void buildErrorMessage(const char* message);\r
+       void raise(const std::string& context, const char* message, va_list argptr);\r
+\r
+public:\r
+       // The following constructors are small and could be inlined, but for object\r
+       // code compacity of the library it is much better to have them non-inlined.\r
+       // The amount of code generated by compilers for a throw is well-enough.\r
+\r
+       ExceptionBase() throw();\r
+       ExceptionBase(const ExceptionBase& copied) throw();\r
+       ExceptionBase& operator=(const ExceptionBase& copied) throw();\r
+       ExceptionBase(const std::string& context, const char* message = 0, ...) throw();\r
+\r
+       virtual ~ExceptionBase() throw();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+    virtual const char* Origin() const throw();\r
+    virtual const char* ErrorMessage() const throw();\r
+       virtual const char* what() const throw();\r
+};\r
+\r
+class LogicExceptionImpl : public IBPP::LogicException, public ExceptionBase\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+public:\r
+       // The following constructors are small and could be inlined, but for object\r
+       // code compacity of the library it is much better to have them non-inlined.\r
+       // The amount of code generated by compilers for a throw is well-enough.\r
+\r
+       LogicExceptionImpl() throw();\r
+       LogicExceptionImpl(const LogicExceptionImpl& copied) throw();\r
+       LogicExceptionImpl& operator=(const LogicExceptionImpl& copied) throw();\r
+       LogicExceptionImpl(const std::string& context, const char* message = 0, ...) throw();\r
+\r
+       virtual ~LogicExceptionImpl() throw ();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+       //\r
+       //      The object public interface is partly implemented by inheriting from\r
+       //      the ExceptionBase class.\r
+\r
+public:\r
+    virtual const char* Origin() const throw();\r
+    virtual const char* ErrorMessage() const throw();\r
+       virtual const char* what() const throw();\r
+};\r
+\r
+class SQLExceptionImpl : public IBPP::SQLException, public ExceptionBase\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       int mSqlCode;\r
+       int mEngineCode;\r
+\r
+public:\r
+       // The following constructors are small and could be inlined, but for object\r
+       // code compacity of the library it is much better to have them non-inlined.\r
+       // The amount of code generated by compilers for a throw is well-enough.\r
+\r
+       SQLExceptionImpl() throw();\r
+       SQLExceptionImpl(const SQLExceptionImpl& copied) throw();\r
+       SQLExceptionImpl& operator=(const SQLExceptionImpl& copied) throw();\r
+       SQLExceptionImpl(const IBS& status, const std::string& context,\r
+                                               const char* message = 0, ...) throw();\r
+\r
+       virtual ~SQLExceptionImpl() throw ();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+       //\r
+       //      The object public interface is partly implemented by inheriting from\r
+       //      the ExceptionBase class.\r
+\r
+public:\r
+    virtual const char* Origin() const throw();\r
+    virtual const char* ErrorMessage() const throw();\r
+       virtual const char* what() const throw();\r
+       virtual int SqlCode() const throw();\r
+       virtual int EngineCode() const throw();\r
+};\r
+\r
+class WrongTypeImpl : public IBPP::WrongType, public ExceptionBase\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+public:\r
+       // The following constructors are small and could be inlined, but for object\r
+       // code compacity of the library it is much better to have them non-inlined.\r
+       // The amount of code generated by compilers for a throw is well-enough.\r
+\r
+       WrongTypeImpl() throw();\r
+       WrongTypeImpl(const WrongTypeImpl& copied) throw();\r
+       WrongTypeImpl& operator=(const WrongTypeImpl& copied) throw();\r
+       WrongTypeImpl(const std::string& context, int sqlType, IITYPE varType,\r
+                                       const char* message = 0, ...) throw();\r
+\r
+       virtual ~WrongTypeImpl() throw ();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+       //\r
+       //      The object public interface is partly implemented by inheriting from\r
+       //      the ExceptionBase class.\r
+\r
+public:\r
+    virtual const char* Origin() const throw();\r
+    virtual const char* ErrorMessage() const throw();\r
+       virtual const char* what() const throw();\r
+};\r
+\r
+class ServiceImpl : public IBPP::IService\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       int mRefCount;                          // Reference counter\r
+    isc_svc_handle mHandle;            // InterBase API Service Handle\r
+       std::string mServerName;        // Nom du serveur\r
+    std::string mUserName;             // Nom de l'utilisateur\r
+    std::string mUserPassword; // Mot de passe de l'utilisateur\r
+       std::string mWaitMessage;       // Progress message returned by WaitMsg()\r
+\r
+       isc_svc_handle* GetHandlePtr() { return &mHandle; }\r
+       void SetServerName(const char*);\r
+       void SetUserName(const char*);\r
+       void SetUserPassword(const char*);\r
+\r
+public:\r
+       isc_svc_handle GetHandle() { return mHandle; }\r
+\r
+       ServiceImpl(const std::string& ServerName, const std::string& UserName,\r
+                                       const std::string& UserPassword);\r
+    ~ServiceImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+    void Connect();\r
+       bool Connected() { return mHandle == 0 ? false : true; }\r
+       void Disconnect();\r
+\r
+       void GetVersion(std::string& version);\r
+\r
+       void AddUser(const IBPP::User&);\r
+       void GetUser(IBPP::User&);\r
+       void GetUsers(std::vector<IBPP::User>&);\r
+       void ModifyUser(const IBPP::User&);\r
+       void RemoveUser(const std::string& username);\r
+\r
+       void SetPageBuffers(const std::string& dbfile, int buffers);\r
+       void SetSweepInterval(const std::string& dbfile, int sweep);\r
+       void SetSyncWrite(const std::string& dbfile, bool);\r
+       void SetReadOnly(const std::string& dbfile, bool);\r
+       void SetReserveSpace(const std::string& dbfile, bool);\r
+\r
+       void Shutdown(const std::string& dbfile, IBPP::DSM mode, int sectimeout);\r
+       void Restart(const std::string& dbfile);\r
+       void Sweep(const std::string& dbfile);\r
+       void Repair(const std::string& dbfile, IBPP::RPF flags);\r
+\r
+       void StartBackup(const std::string& dbfile, const std::string& bkfile,\r
+               IBPP::BRF flags = IBPP::BRF(0));\r
+       void StartRestore(const std::string& bkfile, const std::string& dbfile,\r
+               int pagesize, IBPP::BRF flags = IBPP::BRF(0));\r
+\r
+       const char* WaitMsg();\r
+       void Wait();\r
+\r
+       IBPP::IService* AddRef();\r
+       void Release();\r
+};\r
+\r
+class DatabaseImpl : public IBPP::IDatabase\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+       int mRefCount;                          // Reference counter\r
+    isc_db_handle mHandle;             // InterBase API Session Handle\r
+       std::string mServerName;        // Server name\r
+    std::string mDatabaseName; // Database name (path/file)\r
+    std::string mUserName;             // User name\r
+    std::string mUserPassword; // User password\r
+    std::string mRoleName;             // Role used for the duration of the connection\r
+       std::string mCharSet;           // Character Set used for the connection\r
+       std::string mCreateParams;      // Other parameters (creation only)\r
+\r
+       int mDialect;                                                   // 1 if IB5, 1 or 3 if IB6/FB1\r
+       std::vector<TransactionImpl*> mTransactions;// Table of Transaction*\r
+       std::vector<StatementImpl*> mStatements;// Table of Statement*\r
+       std::vector<BlobImpl*> mBlobs;                  // Table of Blob*\r
+       std::vector<ArrayImpl*> mArrays;                // Table of Array*\r
+       std::vector<EventsImpl*> mEvents;               // Table of Events*\r
+\r
+public:\r
+       isc_db_handle* GetHandlePtr() { return &mHandle; }\r
+       isc_db_handle GetHandle() { return mHandle; }\r
+\r
+       void AttachTransactionImpl(TransactionImpl*);\r
+       void DetachTransactionImpl(TransactionImpl*);\r
+       void AttachStatementImpl(StatementImpl*);\r
+       void DetachStatementImpl(StatementImpl*);\r
+       void AttachBlobImpl(BlobImpl*);\r
+       void DetachBlobImpl(BlobImpl*);\r
+       void AttachArrayImpl(ArrayImpl*);\r
+       void DetachArrayImpl(ArrayImpl*);\r
+       void AttachEventsImpl(EventsImpl*);\r
+       void DetachEventsImpl(EventsImpl*);\r
+\r
+       DatabaseImpl(const std::string& ServerName, const std::string& DatabaseName,\r
+                               const std::string& UserName, const std::string& UserPassword,\r
+                               const std::string& RoleName, const std::string& CharSet,\r
+                               const std::string& CreateParams);\r
+    ~DatabaseImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+       const char* ServerName() const          { return mServerName.c_str(); }\r
+       const char* DatabaseName() const        { return mDatabaseName.c_str(); }\r
+       const char* Username() const            { return mUserName.c_str(); }\r
+       const char* UserPassword() const        { return mUserPassword.c_str(); }\r
+       const char* RoleName() const            { return mRoleName.c_str(); }\r
+       const char* CharSet() const                     { return mCharSet.c_str(); }\r
+       const char* CreateParams() const        { return mCreateParams.c_str(); }\r
+\r
+       void Info(int* ODSMajor, int* ODSMinor,\r
+               int* PageSize, int* Pages, int* Buffers, int* Sweep,\r
+               bool* SyncWrites, bool* Reserve);\r
+       void Statistics(int* Fetches, int* Marks, int* Reads, int* Writes);\r
+       void Counts(int* Insert, int* Update, int* Delete,\r
+               int* ReadIdx, int* ReadSeq);\r
+       void Users(std::vector<std::string>& users);\r
+       int Dialect() { return mDialect; }\r
+\r
+    void Create(int dialect);\r
+       void Connect();\r
+       bool Connected() { return mHandle == 0 ? false : true; }\r
+       void Inactivate();\r
+       void Disconnect();\r
+    void Drop();\r
+\r
+       IBPP::IDatabase* AddRef();\r
+       void Release();\r
+};\r
+\r
+class TransactionImpl : public IBPP::ITransaction\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       int mRefCount;                                  // Reference counter\r
+    isc_tr_handle mHandle;                     // Transaction InterBase\r
+\r
+       std::vector<DatabaseImpl*> mDatabases;          // Tableau de IDatabase*\r
+       std::vector<StatementImpl*> mStatements;        // Tableau de IStatement*\r
+       std::vector<BlobImpl*> mBlobs;                          // Tableau de IBlob*\r
+       std::vector<ArrayImpl*> mArrays;                        // Tableau de Array*\r
+       std::vector<TPB*> mTPBs;                                        // Tableau de TPB\r
+\r
+       void Init();                    // A usage exclusif des constructeurs\r
+\r
+public:\r
+       isc_tr_handle* GetHandlePtr() { return &mHandle; }\r
+       isc_tr_handle GetHandle() { return mHandle; }\r
+\r
+       void AttachStatementImpl(StatementImpl*);\r
+       void DetachStatementImpl(StatementImpl*);\r
+       void AttachBlobImpl(BlobImpl*);\r
+       void DetachBlobImpl(BlobImpl*);\r
+       void AttachArrayImpl(ArrayImpl*);\r
+       void DetachArrayImpl(ArrayImpl*);\r
+    void AttachDatabaseImpl(DatabaseImpl* dbi, IBPP::TAM am = IBPP::amWrite,\r
+                       IBPP::TIL il = IBPP::ilConcurrency,\r
+                       IBPP::TLR lr = IBPP::lrWait, IBPP::TFF flags = IBPP::TFF(0));\r
+    void DetachDatabaseImpl(DatabaseImpl* dbi);\r
+\r
+       TransactionImpl(DatabaseImpl* db, IBPP::TAM am = IBPP::amWrite,\r
+               IBPP::TIL il = IBPP::ilConcurrency,\r
+               IBPP::TLR lr = IBPP::lrWait, IBPP::TFF flags = IBPP::TFF(0));\r
+    ~TransactionImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+    void AttachDatabase(IBPP::Database db, IBPP::TAM am = IBPP::amWrite,\r
+                       IBPP::TIL il = IBPP::ilConcurrency,\r
+                       IBPP::TLR lr = IBPP::lrWait, IBPP::TFF flags = IBPP::TFF(0));\r
+    void DetachDatabase(IBPP::Database db);\r
+       void AddReservation(IBPP::Database db,\r
+                       const std::string& table, IBPP::TTR tr);\r
+\r
+    void Start();\r
+       bool Started() { return mHandle == 0 ? false : true; }\r
+    void Commit();\r
+    void Rollback();\r
+    void CommitRetain();\r
+       void RollbackRetain();\r
+\r
+       IBPP::ITransaction* AddRef();\r
+       void Release();\r
+};\r
+\r
+class RowImpl : public IBPP::IRow\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       int mRefCount;                                  // Reference counter\r
+\r
+       XSQLDA* mDescrArea;                             // XSQLDA descriptor itself\r
+       std::vector<double> mNumerics;  // Temporary storage for Numerics\r
+       std::vector<float> mFloats;             // Temporary storage for Floats\r
+       std::vector<int64_t> mInt64s;   // Temporary storage for 64 bits\r
+       std::vector<int32_t> mInt32s;   // Temporary storage for 32 bits\r
+       std::vector<int16_t> mInt16s;   // Temporary storage for 16 bits\r
+       std::vector<char> mBools;               // Temporary storage for Bools\r
+       std::vector<std::string> mStrings;      // Temporary storage for Strings\r
+       std::vector<bool> mUpdated;             // Which columns where updated (Set()) ?\r
+\r
+       int mDialect;                                   // Related database dialect\r
+       DatabaseImpl* mDatabase;                // Related Database (important for Blobs, ...)\r
+       TransactionImpl* mTransaction;  // Related Transaction (same remark)\r
+\r
+       void SetValue(int, IITYPE, const void* value, int = 0);\r
+       void* GetValue(int, IITYPE, void* = 0);\r
+\r
+public:\r
+       void Free();\r
+       short AllocatedSize() { return mDescrArea->sqln; }\r
+       void Resize(int n);\r
+       void AllocVariables();\r
+       bool MissingValues();           // Returns wether one of the mMissing[] is true\r
+       XSQLDA* Self() { return mDescrArea; }\r
+\r
+       RowImpl& operator=(const RowImpl& copied);\r
+       RowImpl(const RowImpl& copied);\r
+       RowImpl(int dialect, int size, DatabaseImpl* db, TransactionImpl* tr);\r
+    ~RowImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+       void SetNull(int);\r
+       void Set(int, bool);\r
+       void Set(int, const char*);                             // c-strings\r
+       void Set(int, const void*, int);                // byte buffers\r
+       void Set(int, const std::string&);\r
+       void Set(int, int16_t);\r
+       void Set(int, int32_t);\r
+       void Set(int, int64_t);\r
+       void Set(int, float);\r
+       void Set(int, double);\r
+       void Set(int, const IBPP::Timestamp&);\r
+       void Set(int, const IBPP::Date&);\r
+       void Set(int, const IBPP::Time&);\r
+       void Set(int, const IBPP::DBKey&);\r
+       void Set(int, const IBPP::Blob&);\r
+       void Set(int, const IBPP::Array&);\r
+\r
+       bool IsNull(int);\r
+       bool Get(int, bool&);\r
+       bool Get(int, char*);           // c-strings, len unchecked\r
+       bool Get(int, void*, int&);     // byte buffers\r
+       bool Get(int, std::string&);\r
+       bool Get(int, int16_t&);\r
+       bool Get(int, int32_t&);\r
+       bool Get(int, int64_t&);\r
+       bool Get(int, float&);\r
+       bool Get(int, double&);\r
+       bool Get(int, IBPP::Timestamp&);\r
+       bool Get(int, IBPP::Date&);\r
+       bool Get(int, IBPP::Time&);\r
+       bool Get(int, IBPP::DBKey&);\r
+       bool Get(int, IBPP::Blob&);\r
+       bool Get(int, IBPP::Array&);\r
+\r
+       bool IsNull(const std::string&);\r
+       bool Get(const std::string&, bool&);\r
+       bool Get(const std::string&, char*);    // c-strings, len unchecked\r
+       bool Get(const std::string&, void*, int&);      // byte buffers\r
+       bool Get(const std::string&, std::string&);\r
+       bool Get(const std::string&, int16_t&);\r
+       bool Get(const std::string&, int32_t&);\r
+       bool Get(const std::string&, int64_t&);\r
+       bool Get(const std::string&, float&);\r
+       bool Get(const std::string&, double&);\r
+       bool Get(const std::string&, IBPP::Timestamp&);\r
+       bool Get(const std::string&, IBPP::Date&);\r
+       bool Get(const std::string&, IBPP::Time&);\r
+       bool Get(const std::string&, IBPP::DBKey&);\r
+       bool Get(const std::string&, IBPP::Blob&);\r
+       bool Get(const std::string&, IBPP::Array&);\r
+\r
+       int ColumnNum(const std::string&);\r
+       const char* ColumnName(int);\r
+       const char* ColumnAlias(int);\r
+       const char* ColumnTable(int);\r
+       IBPP::SDT ColumnType(int);\r
+       int ColumnSubtype(int);\r
+       int ColumnSize(int);\r
+       int ColumnScale(int);\r
+       int Columns();\r
+\r
+       bool ColumnUpdated(int);\r
+       bool Updated();\r
+\r
+       IBPP::Database DatabasePtr() const;\r
+       IBPP::Transaction TransactionPtr() const;\r
+\r
+       IBPP::IRow* Clone();\r
+       IBPP::IRow* AddRef();\r
+       void Release();\r
+};\r
+\r
+class StatementImpl : public IBPP::IStatement\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       friend class TransactionImpl;\r
+\r
+       int mRefCount;                          // Reference counter\r
+       isc_stmt_handle mHandle;        // Statement Handle\r
+\r
+       DatabaseImpl* mDatabase;                // Attached database\r
+       TransactionImpl* mTransaction;  // Attached transaction\r
+       RowImpl* mInRow;\r
+       //bool* mInMissing;                     // Quels paramètres n'ont pas été spécifiés\r
+       RowImpl* mOutRow;\r
+       bool mResultSetAvailable;       // Executed and result set is available\r
+       bool mCursorOpened;                     // dsql_set_cursor_name was called\r
+       IBPP::STT mType;                        // Type de requète\r
+       std::string mSql;                       // Last SQL statement prepared or executed\r
+\r
+       // Internal Methods\r
+       void CursorFree();\r
+\r
+public:\r
+       // Properties and Attributes Access Methods\r
+       isc_stmt_handle GetHandle() { return mHandle; }\r
+\r
+       void AttachDatabaseImpl(DatabaseImpl*);\r
+       void DetachDatabaseImpl();\r
+       void AttachTransactionImpl(TransactionImpl*);\r
+       void DetachTransactionImpl();\r
+\r
+       StatementImpl(DatabaseImpl*, TransactionImpl*, const std::string&);\r
+    ~StatementImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+       void Prepare(const std::string& sql);\r
+       void Execute(const std::string& sql);\r
+       inline void Execute()   { Execute(std::string()); }\r
+       void ExecuteImmediate(const std::string&);\r
+       void CursorExecute(const std::string& cursor, const std::string& sql);\r
+       inline void CursorExecute(const std::string& cursor)    { CursorExecute(cursor, std::string()); }\r
+       bool Fetch();\r
+       bool Fetch(IBPP::Row&);\r
+       int AffectedRows();\r
+       void Close();   // Free resources, attachments maintained\r
+       std::string& Sql() { return mSql; }\r
+       IBPP::STT Type() { return mType; }\r
+\r
+       void SetNull(int);\r
+       void Set(int, bool);\r
+       void Set(int, const char*);                             // c-strings\r
+       void Set(int, const void*, int);                // byte buffers\r
+       void Set(int, const std::string&);\r
+       void Set(int, int16_t);\r
+       void Set(int, int32_t);\r
+       void Set(int, int64_t);\r
+       void Set(int, float);\r
+       void Set(int, double);\r
+       void Set(int, const IBPP::Timestamp&);\r
+       void Set(int, const IBPP::Date&);\r
+       void Set(int, const IBPP::Time&);\r
+       void Set(int, const IBPP::DBKey&);\r
+       void Set(int, const IBPP::Blob&);\r
+       void Set(int, const IBPP::Array&);\r
+\r
+       bool IsNull(int);\r
+       bool Get(int, bool*);\r
+       bool Get(int, bool&);\r
+       bool Get(int, char*);                           // c-strings, len unchecked\r
+       bool Get(int, void*, int&);                     // byte buffers\r
+       bool Get(int, std::string&);\r
+       bool Get(int, int16_t*);\r
+       bool Get(int, int16_t&);\r
+       bool Get(int, int32_t*);\r
+       bool Get(int, int32_t&);\r
+       bool Get(int, int64_t*);\r
+       bool Get(int, int64_t&);\r
+       bool Get(int, float*);\r
+       bool Get(int, float&);\r
+       bool Get(int, double*);\r
+       bool Get(int, double&);\r
+       bool Get(int, IBPP::Timestamp&);\r
+       bool Get(int, IBPP::Date&);\r
+       bool Get(int, IBPP::Time&);\r
+       bool Get(int, IBPP::DBKey&);\r
+       bool Get(int, IBPP::Blob&);\r
+       bool Get(int, IBPP::Array&);\r
+\r
+       bool IsNull(const std::string&);\r
+       bool Get(const std::string&, bool*);\r
+       bool Get(const std::string&, bool&);\r
+       bool Get(const std::string&, char*);            // c-strings, len unchecked\r
+       bool Get(const std::string&, void*, int&);      // byte buffers\r
+       bool Get(const std::string&, std::string&);\r
+       bool Get(const std::string&, int16_t*);\r
+       bool Get(const std::string&, int16_t&);\r
+       bool Get(const std::string&, int32_t*);\r
+       bool Get(const std::string&, int32_t&);\r
+       bool Get(const std::string&, int64_t*);\r
+       bool Get(const std::string&, int64_t&);\r
+       bool Get(const std::string&, float*);\r
+       bool Get(const std::string&, float&);\r
+       bool Get(const std::string&, double*);\r
+       bool Get(const std::string&, double&);\r
+       bool Get(const std::string&, IBPP::Timestamp&);\r
+       bool Get(const std::string&, IBPP::Date&);\r
+       bool Get(const std::string&, IBPP::Time&);\r
+       bool Get(const std::string&, IBPP::DBKey&);\r
+       bool Get(const std::string&, IBPP::Blob&);\r
+       bool Get(const std::string&, IBPP::Array&);\r
+\r
+       int ColumnNum(const std::string&);\r
+    int ColumnNumAlias(const std::string&);\r
+       const char* ColumnName(int);\r
+       const char* ColumnAlias(int);\r
+       const char* ColumnTable(int);\r
+       IBPP::SDT ColumnType(int);\r
+       int ColumnSubtype(int);\r
+       int ColumnSize(int);\r
+       int ColumnScale(int);\r
+       int Columns();\r
+\r
+       IBPP::SDT ParameterType(int);\r
+       int ParameterSubtype(int);\r
+       int ParameterSize(int);\r
+       int ParameterScale(int);\r
+       int Parameters();\r
+\r
+       void Plan(std::string&);\r
+\r
+       IBPP::Database DatabasePtr() const;\r
+       IBPP::Transaction TransactionPtr() const;\r
+\r
+       IBPP::IStatement* AddRef();\r
+       void Release();\r
+};\r
+\r
+class BlobImpl : public IBPP::IBlob\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       friend class RowImpl;\r
+\r
+       int mRefCount;\r
+       bool                                    mIdAssigned;\r
+       ISC_QUAD                                mId;\r
+       isc_blob_handle                 mHandle;\r
+       bool                                    mWriteMode;\r
+       DatabaseImpl*                   mDatabase;              // Belongs to this database\r
+       TransactionImpl*                mTransaction;   // Belongs to this transaction\r
+\r
+       void Init();\r
+       void SetId(ISC_QUAD*);\r
+       void GetId(ISC_QUAD*);\r
+\r
+public:\r
+       void AttachDatabaseImpl(DatabaseImpl*);\r
+       void DetachDatabaseImpl();\r
+       void AttachTransactionImpl(TransactionImpl*);\r
+       void DetachTransactionImpl();\r
+\r
+       BlobImpl(const BlobImpl&);\r
+       BlobImpl(DatabaseImpl*, TransactionImpl* = 0);\r
+       ~BlobImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+       void Create();\r
+       void Open();\r
+       void Close();\r
+       void Cancel();\r
+       int Read(void*, int size);\r
+       void Write(const void*, int size);\r
+       void Info(int* Size, int* Largest, int* Segments);\r
+\r
+       void Save(const std::string& data);\r
+       void Load(std::string& data);\r
+\r
+       IBPP::Database DatabasePtr() const;\r
+       IBPP::Transaction TransactionPtr() const;\r
+\r
+       IBPP::IBlob* AddRef();\r
+       void Release();\r
+};\r
+\r
+class ArrayImpl : public IBPP::IArray\r
+{\r
+       //      (((((((( OBJECT INTERNALS ))))))))\r
+\r
+private:\r
+       friend class RowImpl;\r
+\r
+       int                                     mRefCount;              // Reference counter\r
+       bool                            mIdAssigned;\r
+       ISC_QUAD                        mId;\r
+       bool                            mDescribed;\r
+       ISC_ARRAY_DESC          mDesc;\r
+       DatabaseImpl*           mDatabase;              // Database attachée\r
+       TransactionImpl*        mTransaction;   // Transaction attachée\r
+       void*                           mBuffer;                // Buffer for native data\r
+       int                                     mBufferSize;    // Size of this buffer in bytes\r
+       int                                     mElemCount;             // Count of elements in this array\r
+       int                                     mElemSize;              // Size of an element in the buffer\r
+\r
+       void Init();\r
+       void SetId(ISC_QUAD*);\r
+       void GetId(ISC_QUAD*);\r
+       void ResetId();\r
+       void AllocArrayBuffer();\r
+\r
+public:\r
+       void AttachDatabaseImpl(DatabaseImpl*);\r
+       void DetachDatabaseImpl();\r
+       void AttachTransactionImpl(TransactionImpl*);\r
+       void DetachTransactionImpl();\r
+\r
+       ArrayImpl(const ArrayImpl&);\r
+       ArrayImpl(DatabaseImpl*, TransactionImpl* = 0);\r
+       ~ArrayImpl();\r
+\r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+       void Describe(const std::string& table, const std::string& column);\r
+       void ReadTo(IBPP::ADT, void*, int);\r
+       void WriteFrom(IBPP::ADT, const void*, int);\r
+       IBPP::SDT ElementType();\r
+       int ElementSize();\r
+       int ElementScale();\r
+       int Dimensions();\r
+       void Bounds(int dim, int* low, int* high);\r
+       void SetBounds(int dim, int low, int high);\r
+\r
+       IBPP::Database DatabasePtr() const;\r
+       IBPP::Transaction TransactionPtr() const;\r
+\r
+       IBPP::IArray* AddRef();\r
+       void Release();\r
+};\r
+\r
+//\r
+//     EventBufferIterator: used in EventsImpl implementation.\r
+//\r
+\r
+template<class It>\r
+struct EventBufferIterator\r
+{\r
+       It mIt;\r
+\r
+public:\r
+       EventBufferIterator& operator++()\r
+               { mIt += 1 + static_cast<int>(*mIt) + 4; return *this; }\r
+\r
+       bool operator == (const EventBufferIterator& i) const { return i.mIt == mIt; }\r
+       bool operator != (const EventBufferIterator& i) const { return i.mIt != mIt; }\r
+\r
+#ifdef __BCPLUSPLUS__\r
+#pragma warn -8027\r
+#endif\r
+       std::string get_name() const\r
+       {\r
+               return std::string(mIt + 1, mIt + 1 + static_cast<int32_t>(*mIt));\r
+       }\r
+#ifdef __BCPLUSPLUS__\r
+#pragma warn .8027\r
+#endif\r
+\r
+       uint32_t get_count() const\r
+       {\r
+               return (*gds.Call()->m_vax_integer)\r
+                       (const_cast<char*>(&*(mIt + 1 + static_cast<int>(*mIt))), 4);\r
+       }\r
+\r
+       // Those container like begin() and end() allow access to the underlying type\r
+       It begin()      { return mIt; }\r
+       It end()        { return mIt + 1 + static_cast<int>(*mIt) + 4; }\r
+\r
+       EventBufferIterator() {}\r
+       EventBufferIterator(It it) : mIt(it) {}\r
+};\r
+\r
+class EventsImpl : public IBPP::IEvents\r
+{\r
+       static const size_t MAXEVENTNAMELEN;\r
+       static void EventHandler(const char*, short, const char*);\r
+\r
+       typedef std::vector<IBPP::EventInterface*> ObjRefs;\r
+       ObjRefs mObjectReferences;\r
+\r
+       typedef std::vector<char> Buffer;\r
+       Buffer mEventBuffer;\r
+       Buffer mResultsBuffer;\r
+\r
+       int mRefCount;          // Reference counter\r
+\r
+       DatabaseImpl* mDatabase;\r
+       ISC_LONG mId;                   // Firebird internal Id of these events\r
+       bool mQueued;                   // Has isc_que_events() been called?\r
+       bool mTrapped;                  // EventHandled() was called since last que_events()\r
+\r
+       void FireActions();\r
+       void Queue();\r
+       void Cancel();\r
+\r
+       EventsImpl& operator=(const EventsImpl&);\r
+       EventsImpl(const EventsImpl&);\r
+\r
+public:\r
+       void AttachDatabaseImpl(DatabaseImpl*);\r
+       void DetachDatabaseImpl();\r
+       \r
+       EventsImpl(DatabaseImpl* dbi);\r
+       ~EventsImpl();\r
+               \r
+       //      (((((((( OBJECT INTERFACE ))))))))\r
+\r
+public:\r
+       void Add(const std::string&, IBPP::EventInterface*);\r
+       void Drop(const std::string&);\r
+       void List(std::vector<std::string>&);\r
+       void Clear();                           // Drop all events\r
+       void Dispatch();                        // Dispatch NON async events\r
+\r
+       IBPP::Database DatabasePtr() const;\r
+\r
+       IBPP::IEvents* AddRef();\r
+       void Release();\r
+};\r
+\r
+void encodeDate(ISC_DATE& isc_dt, const IBPP::Date& dt);\r
+void decodeDate(IBPP::Date& dt, const ISC_DATE& isc_dt);\r
+\r
+void encodeTime(ISC_TIME& isc_tm, const IBPP::Time& tm);\r
+void decodeTime(IBPP::Time& tm, const ISC_TIME& isc_tm);\r
+\r
+void encodeTimestamp(ISC_TIMESTAMP& isc_ts, const IBPP::Timestamp& ts);\r
+void decodeTimestamp(IBPP::Timestamp& ts, const ISC_TIMESTAMP& isc_ts);\r
+\r
+struct consts  // See _ibpp.cpp for initializations of these constants\r
+{\r
+       static const double dscales[19];\r
+       static const int Dec31_1899;\r
+       static const int16_t min16;\r
+       static const int16_t max16;\r
+       static const int32_t min32;\r
+       static const int32_t max32;\r
+};\r
+\r
+}      // namespace ibpp_internal\r
+\r
+#endif // __INTERNAL_IBPP_H__\r
+\r
+//\r
+//     Eof\r
+//\r
diff --git a/stglibs/ibpp.lib/_ibs.cpp b/stglibs/ibpp.lib/_ibs.cpp
new file mode 100644 (file)
index 0000000..25e66bc
--- /dev/null
@@ -0,0 +1,109 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _ibs.cpp,v 1.2 2009/03/19 20:00:27 faust Exp $\r
+//     Subject : IBPP, internal Status class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+int IBS::SqlCode() const\r
+{\r
+       return (int)(*gds.Call()->m_sqlcode)(&mVector[0]);\r
+}\r
+\r
+const char* IBS::ErrorMessage() const\r
+{\r
+       char msg[1024];\r
+       ISC_LONG sqlcode;\r
+\r
+       if (! mMessage.empty()) return mMessage.c_str();        // If message compiled, returns it\r
+\r
+       // Compiles the message (SQL part)\r
+       std::ostringstream message;\r
+       sqlcode = (*gds.Call()->m_sqlcode)(mVector);\r
+       if (sqlcode != -999)\r
+       {\r
+               (*gds.Call()->m_sql_interprete)((short)sqlcode, msg, sizeof(msg));\r
+               message<< _("SQL Message : ")<< sqlcode<< "\n"<< msg<< "\n\n";\r
+       }\r
+\r
+       message<< _("Engine Code    : ")<< EngineCode()<< "\n";\r
+\r
+       // Compiles the message (Engine part)\r
+       ISC_STATUS* error = &mVector[0];\r
+       try { (*gds.Call()->m_interprete)(msg, &error); }\r
+       catch(...) { msg[0] = '\0'; }\r
+       message<< _("Engine Message :")<< "\n"<< msg;\r
+       try\r
+       {\r
+               while ((*gds.Call()->m_interprete)(msg, &error))\r
+                       message<< "\n"<< msg;\r
+       }\r
+       catch (...) { }\r
+\r
+       message<< "\n";\r
+       mMessage = message.str();\r
+       return mMessage.c_str();\r
+}\r
+\r
+void IBS::Reset()\r
+{\r
+       for (int i = 0; i < 20; i++) mVector[i] = 0;\r
+       mMessage.erase();\r
+}\r
+\r
+IBS::IBS()\r
+{\r
+       Reset();\r
+}\r
+\r
+IBS::~IBS()\r
+{\r
+}\r
+\r
+/** Copy Constructor\r
+*/\r
+\r
+IBS::IBS(IBS& copied)\r
+{\r
+       memcpy(mVector, copied.mVector, sizeof(mVector));\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/_rb.cpp b/stglibs/ibpp.lib/_rb.cpp
new file mode 100644 (file)
index 0000000..d3dfbc8
--- /dev/null
@@ -0,0 +1,205 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _rb.cpp,v 1.2 2009/03/19 20:00:27 faust Exp $\r
+//     Subject : IBPP, internal RB class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * RB == Result Block/Buffer, see Interbase 6.0 C-API\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+char* RB::FindToken(char token)\r
+{\r
+       char* p = mBuffer;\r
+\r
+       while (*p != isc_info_end)\r
+       {\r
+               int len;\r
+\r
+               if (*p == token) return p;\r
+               len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+               p += (len + 3);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+char* RB::FindToken(char token, char subtoken)\r
+{\r
+       char* p = mBuffer;\r
+\r
+       while (*p != isc_info_end)\r
+       {\r
+               int len;\r
+\r
+               if (*p == token)\r
+               {\r
+                       // Found token, now find subtoken\r
+                       int inlen = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+                       p += 3;\r
+                       while (inlen > 0)\r
+                       {\r
+                               if (*p == subtoken) return p;\r
+                               len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+                               p += (len + 3);\r
+                               inlen -= (len + 3);\r
+                       }\r
+                       return 0;\r
+               }\r
+               len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+               p += (len + 3);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+int RB::GetValue(char token)\r
+{\r
+       int value;\r
+       int len;\r
+       char* p = FindToken(token);\r
+\r
+       if (p == 0)\r
+               throw LogicExceptionImpl("RB::GetValue", _("Token not found."));\r
+\r
+       len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+       if (len == 0) value = 0;\r
+       else value = (*gds.Call()->m_vax_integer)(p+3, (short)len);\r
+\r
+       return value;\r
+}\r
+\r
+int RB::GetCountValue(char token)\r
+{\r
+       // Specifically used on tokens like isc_info_insert_count and the like\r
+       // which return detailed counts per relation. We sum up the values.\r
+       int value;\r
+       int len;\r
+       char* p = FindToken(token);\r
+\r
+       if (p == 0)\r
+               throw LogicExceptionImpl("RB::GetCountValue", _("Token not found."));\r
+\r
+       // len is the number of bytes in the following array\r
+       len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+       p += 3;\r
+       value = 0;\r
+       while (len > 0)\r
+       {\r
+               // Each array item is 6 bytes : 2 bytes for the relation_id which\r
+               // we skip, and 4 bytes for the count value which we sum up accross\r
+               // all tables.\r
+               value += (*gds.Call()->m_vax_integer)(p+2, 4);\r
+               p += 6;\r
+               len -= 6;\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+int RB::GetValue(char token, char subtoken)\r
+{\r
+       int value;\r
+       int len;\r
+       char* p = FindToken(token, subtoken);\r
+\r
+       if (p == 0)\r
+               throw LogicExceptionImpl("RB::GetValue", _("Token/Subtoken not found."));\r
+\r
+       len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+       if (len == 0) value = 0;\r
+       else value = (*gds.Call()->m_vax_integer)(p+3, (short)len);\r
+\r
+       return value;\r
+}\r
+\r
+bool RB::GetBool(char token)\r
+{\r
+       int value;\r
+       char* p = FindToken(token);\r
+\r
+       if (p == 0)\r
+               throw LogicExceptionImpl("RB::GetBool", _("Token not found."));\r
+\r
+       value = (*gds.Call()->m_vax_integer)(p+1, 4);\r
+\r
+       return value == 0 ? false : true;\r
+}\r
+\r
+int RB::GetString(char token, std::string& data)\r
+{\r
+       int len;\r
+       char* p = FindToken(token);\r
+\r
+       if (p == 0)\r
+               throw LogicExceptionImpl("RB::GetString", _("Token not found."));\r
+\r
+       len = (*gds.Call()->m_vax_integer)(p+1, 2);\r
+       data = std::string(p+3, len);\r
+       return len;\r
+}\r
+\r
+void RB::Reset()\r
+{\r
+       delete [] mBuffer;\r
+       mBuffer = new char [mSize];\r
+       memset(mBuffer, 255, mSize);\r
+}\r
+\r
+RB::RB()\r
+{\r
+       mSize = 1024;\r
+       mBuffer = new char [1024];\r
+       memset(mBuffer, 255, mSize);\r
+}\r
+\r
+RB::RB(int Size)\r
+{\r
+       mSize = Size;\r
+       mBuffer = new char [Size];\r
+       memset(mBuffer, 255, mSize);\r
+}\r
+\r
+RB::~RB()\r
+{\r
+       try { delete [] mBuffer; }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/_spb.cpp b/stglibs/ibpp.lib/_spb.cpp
new file mode 100644 (file)
index 0000000..632a020
--- /dev/null
@@ -0,0 +1,135 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _spb.cpp,v 1.2 2009/03/19 20:00:27 faust Exp $\r
+//     Subject : IBPP, internal SPB class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * SPB == Service Parameter Block/Buffer, see Interbase 6.0 C-API\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+const int SPB::BUFFERINCR = 128;\r
+\r
+void SPB::Grow(int needed)\r
+{\r
+       if ((mSize + needed) > mAlloc)\r
+       {\r
+               // We need to grow the buffer. We use increments of BUFFERINCR bytes.\r
+               needed = (needed / BUFFERINCR + 1) * BUFFERINCR;\r
+               char* newbuffer = new char[mAlloc + needed];\r
+               if (mBuffer != 0)\r
+               {\r
+                       // Move the old buffer content to the new one\r
+                       memcpy(newbuffer, mBuffer, mSize);\r
+                       delete [] mBuffer;\r
+               }\r
+               mBuffer = newbuffer;\r
+               mAlloc += needed;\r
+       }\r
+}\r
+\r
+void SPB::Insert(char opcode)\r
+{\r
+       Grow(1);\r
+       mBuffer[mSize++] = opcode;\r
+}\r
+\r
+void SPB::InsertString(char type, int lenwidth, const char* data)\r
+{\r
+       int16_t len = (int16_t)strlen(data);\r
+\r
+       Grow(1 + lenwidth + len);\r
+       mBuffer[mSize++] = type;\r
+       switch (lenwidth)\r
+       {\r
+               case 1 :        mBuffer[mSize] = char(len); mSize++; break;\r
+               case 2 :        *(int16_t*)&mBuffer[mSize] = int16_t((*gds.Call()->m_vax_integer)((char*)&len, 2));\r
+                                       mSize += 2; break;\r
+               default :       throw LogicExceptionImpl("IISPB::IISPB", _("Invalid length parameter"));\r
+       }\r
+       strncpy(&mBuffer[mSize], data, len);\r
+       mSize += len;\r
+}\r
+\r
+void SPB::InsertByte(char type, char data)\r
+{\r
+       Grow(1 + 1);\r
+       mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = data;\r
+}\r
+\r
+void SPB::InsertQuad(char type, int32_t data)\r
+{\r
+       Grow(1 + 4);\r
+       mBuffer[mSize++] = type;\r
+       *(int32_t*)&mBuffer[mSize] = int32_t((*gds.Call()->m_vax_integer)((char*)&data, 4));\r
+       mSize += 4;\r
+}\r
+\r
+void SPB::Reset()\r
+{\r
+       if (mBuffer != 0)\r
+       {\r
+               delete [] mBuffer;\r
+               mBuffer = 0;\r
+               mSize = 0;\r
+               mAlloc = 0;\r
+    }\r
+}\r
+\r
+/*\r
+void SPB::Insert(char type, short data)\r
+{\r
+       Grow(1 + 3);\r
+       mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = char(2);\r
+       *(short*)&mBuffer[mSize] = data;\r
+       mSize += 2;\r
+}\r
+\r
+void SPB::Insert(char type, bool data)\r
+{\r
+       Grow(1 + 2);\r
+       mBuffer[mSize++] = type;\r
+       mBuffer[mSize++] = char(1);\r
+       mBuffer[mSize++] = char(data ? 1 : 0);\r
+}\r
+*/\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/_tpb.cpp b/stglibs/ibpp.lib/_tpb.cpp
new file mode 100644 (file)
index 0000000..d27c2d5
--- /dev/null
@@ -0,0 +1,100 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: _tpb.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, internal TPB class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * TPB == Transaction Parameter Block/Buffer, see Interbase 6.0 C-API\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+const int TPB::BUFFERINCR = 128;\r
+\r
+void TPB::Grow(int needed)\r
+{\r
+       if (mBuffer == 0) ++needed;     // Initial alloc will require one more byte\r
+       if ((mSize + needed) > mAlloc)\r
+       {\r
+               // We need to grow the buffer. We use increments of BUFFERINCR bytes.\r
+               needed = (needed / BUFFERINCR + 1) * BUFFERINCR;\r
+               char* newbuffer = new char[mAlloc + needed];\r
+               if (mBuffer == 0)\r
+               {\r
+                       // Initial allocation, initialize the version tag\r
+                       newbuffer[0] = isc_tpb_version3;\r
+                       mSize = 1;\r
+               }\r
+               else\r
+               {\r
+                       // Move the old buffer content to the new one\r
+                       memcpy(newbuffer, mBuffer, mSize);\r
+                       delete [] mBuffer;\r
+               }\r
+               mBuffer = newbuffer;\r
+               mAlloc += needed;\r
+       }\r
+}\r
+\r
+void TPB::Insert(char item)\r
+{\r
+       Grow(1);\r
+       mBuffer[mSize++] = item;\r
+}\r
+\r
+void TPB::Insert(const std::string& data)\r
+{\r
+       int len = (int)data.length();\r
+       Grow(1 + len);\r
+       mBuffer[mSize++] = (char)len;\r
+       strncpy(&mBuffer[mSize], data.c_str(), len);\r
+       mSize += len;\r
+}\r
+\r
+void TPB::Reset()\r
+{\r
+       if (mSize != 0)\r
+       {\r
+               delete [] mBuffer;\r
+               mBuffer = 0;\r
+               mSize = 0;\r
+               mAlloc = 0;\r
+       }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/all_in_one.cpp b/stglibs/ibpp.lib/all_in_one.cpp
new file mode 100644 (file)
index 0000000..9f74f7e
--- /dev/null
@@ -0,0 +1,56 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: all_in_one.cpp,v 1.1 2007/05/05 17:00:42 faust Exp $\r
+//     Subject : "All In One" source code file\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//     * This file is just an "all in one" holder for all the core source files\r
+//       of IBPP. When you build a project made of each individual source code\r
+//       files, please DON'T include this one.\r
+//       Though if you prefer, maybe for better compiler optimizations, you can\r
+//       compile all of IBPP at once by just compiling this single .cpp file,\r
+//       which in turn, includes all the others. Presenting such a single\r
+//       compilation unit to the compiler may help it do better optimizations.\r
+//       This is just provided for convenience and is in no case required.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "_ibpp.cpp"\r
+#include "_dpb.cpp"\r
+#include "_ibs.cpp"\r
+#include "_rb.cpp"\r
+#include "_spb.cpp"\r
+#include "_tpb.cpp"\r
+\r
+#include "array.cpp"\r
+#include "blob.cpp"\r
+#include "database.cpp"\r
+#include "date.cpp"\r
+#include "dbkey.cpp"\r
+#include "events.cpp"\r
+#include "exception.cpp"\r
+#include "row.cpp"\r
+#include "service.cpp"\r
+#include "statement.cpp"\r
+#include "time.cpp"\r
+#include "transaction.cpp"\r
+#include "user.cpp"\r
+\r
+// Eof\r
diff --git a/stglibs/ibpp.lib/array.cpp b/stglibs/ibpp.lib/array.cpp
new file mode 100644 (file)
index 0000000..2dc7ab2
--- /dev/null
@@ -0,0 +1,1046 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: array.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, Array class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <math.h>\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void ArrayImpl::Describe(const std::string& table, const std::string& column)\r
+{\r
+       //if (mIdAssigned)\r
+       //      throw LogicExceptionImpl("Array::Lookup", _("Array already in use."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::Lookup", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::Lookup", _("No Transaction is attached."));\r
+\r
+       ResetId();      // Re-use this array object if was previously assigned\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_array_lookup_bounds)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), const_cast<char*>(table.c_str()),\r
+                       const_cast<char*>(column.c_str()), &mDesc);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Array::Lookup",\r
+                       _("isc_array_lookup_bounds failed."));\r
+\r
+       AllocArrayBuffer();\r
+\r
+       mDescribed = true;\r
+}\r
+\r
+void ArrayImpl::SetBounds(int dim, int low, int high)\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("Array description not set."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("No Transaction is attached."));\r
+       if (dim < 0 || dim > mDesc.array_desc_dimensions-1)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("Invalid dimension."));\r
+       if (low > high ||\r
+               low < mDesc.array_desc_bounds[dim].array_bound_lower ||\r
+               low > mDesc.array_desc_bounds[dim].array_bound_upper ||\r
+               high > mDesc.array_desc_bounds[dim].array_bound_upper ||\r
+               high < mDesc.array_desc_bounds[dim].array_bound_lower)\r
+               throw LogicExceptionImpl("Array::SetBounds",\r
+                       _("Invalid bounds. You can only narrow the bounds."));\r
+\r
+       mDesc.array_desc_bounds[dim].array_bound_lower = short(low);\r
+       mDesc.array_desc_bounds[dim].array_bound_upper = short(high);\r
+\r
+       AllocArrayBuffer();\r
+}\r
+\r
+IBPP::SDT ArrayImpl::ElementType()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ElementType",\r
+                       _("Array description not set."));\r
+\r
+       IBPP::SDT value;\r
+       switch (mDesc.array_desc_dtype)\r
+       {\r
+               case blr_text :                 value = IBPP::sdString;         break;\r
+               case blr_varying :              value = IBPP::sdString;         break;\r
+               case blr_cstring :              value = IBPP::sdString;         break;\r
+               case blr_short :                value = IBPP::sdSmallint;       break;\r
+               case blr_long :                 value = IBPP::sdInteger;        break;\r
+               case blr_int64 :                value = IBPP::sdLargeint;       break;\r
+               case blr_float :                value = IBPP::sdFloat;          break;\r
+               case blr_double :               value = IBPP::sdDouble;         break;\r
+               case blr_timestamp :    value = IBPP::sdTimestamp;      break;\r
+               case blr_sql_date :             value = IBPP::sdDate;           break;\r
+               case blr_sql_time :             value = IBPP::sdTime;           break;\r
+               default : throw LogicExceptionImpl("Array::ElementType",\r
+                                               _("Found an unknown sqltype !"));\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+int ArrayImpl::ElementSize()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ElementSize",\r
+                       _("Array description not set."));\r
+\r
+       return mDesc.array_desc_length;\r
+}\r
+\r
+int ArrayImpl::ElementScale()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ElementScale",\r
+                       _("Array description not set."));\r
+\r
+       return mDesc.array_desc_scale;\r
+}\r
+\r
+int ArrayImpl::Dimensions()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::Dimensions",\r
+                       _("Array description not set."));\r
+\r
+       return mDesc.array_desc_dimensions;\r
+}\r
+\r
+void ArrayImpl::Bounds(int dim, int* low, int* high)\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::Bounds", _("Array description not set."));\r
+       if (dim < 0 || dim > mDesc.array_desc_dimensions-1)\r
+               throw LogicExceptionImpl("Array::Bounds", _("Invalid dimension."));\r
+       if (low == 0 || high == 0)\r
+               throw LogicExceptionImpl("Array::Bounds", _("Null reference detected."));\r
+\r
+       *low =  mDesc.array_desc_bounds[dim].array_bound_lower;\r
+       *high = mDesc.array_desc_bounds[dim].array_bound_upper;\r
+}\r
+\r
+/*\r
+\r
+COMMENTS\r
+\r
+1)\r
+For an array column of type CHAR(X), the internal type returned or expected is blr_text.\r
+In such case, the byte array received or submitted to get/put_slice is formatted in\r
+elements of X bytes, which correspond to what is reported in array_desc_length.\r
+The elements are not '\0' terminated but are right-padded with spaces ' '.\r
+\r
+2)\r
+For an array column of type VARCHAR(X), the internal type is blr_varying.\r
+The underlying format is rather curious and different than what is used in XSQLDA.\r
+The element size is reported in array_desc_length as X.\r
+Yet each element of the byte array is expected to be of size X+2 (just as if we were\r
+to stuff a short in the first 2 bytes to store the length (as is done with XSQLDA).\r
+No. The string of X characters maximum has to be stored in the chunks of X+2 bytes as\r
+a zero-terminated c-string. Note that the buffer is indeed one byte too large.\r
+Internally, the API probably convert in-place in these chunks the zero-terminated string\r
+to a variable-size string with a short in front and the string data non zero-terminated\r
+behind.\r
+\r
+3)\r
+With Interbase 6.0 and Firebird 1.0 (initial april 2002 release), the int64 support is\r
+broken regarding the arrays. It is not possible to work on arrays using a datatype stored\r
+in an int64, as for instance any NUMERIC(x,0) where x is equal or greater than 10. That's\r
+a bug in the engine, not in IBPP, which has been fixed in june 2002. Engines compiled from\r
+the current Firebird CVS code as of july 2002 are okay. As will be the 1.01 Firebird version.\r
+We have no idea if this is fixed or not in Interbase 6.5 though.\r
+\r
+*/\r
+\r
+void ArrayImpl::ReadTo(IBPP::ADT adtype, void* data, int datacount)\r
+{\r
+       if (! mIdAssigned)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Array Id not read from column."));\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Array description not set."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("No Transaction is attached."));\r
+       if (datacount != mElemCount)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Wrong count of array elements"));\r
+\r
+       IBS status;\r
+       ISC_LONG lenbuf = mBufferSize;\r
+       (*gds.Call()->m_array_get_slice)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mId, &mDesc, mBuffer, &lenbuf);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Array::ReadTo", _("isc_array_get_slice failed."));\r
+       if (lenbuf != mBufferSize)\r
+               throw SQLExceptionImpl(status, "Array::ReadTo", _("Internal buffer size discrepancy."));\r
+\r
+       // Now, convert the types and copy values to the user array...\r
+       int len;\r
+       char* src = (char*)mBuffer;\r
+       char* dst = (char*)data;\r
+\r
+       switch (mDesc.array_desc_dtype)\r
+       {\r
+               case blr_text :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       strncpy(dst, src, mElemSize);\r
+                                       dst[mElemSize] = '\0';\r
+                                       src += mElemSize;\r
+                                       dst += (mElemSize + 1);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*src == 't' || *src == 'T' || *src == 'y' || *src == 'Y' || *src == '1')\r
+                                               *(bool*)dst = true;\r
+                                       else *(bool*)dst = false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_varying :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       len = (int)strlen(src);\r
+                                       if (len > mElemSize-2) len = mElemSize-2;\r
+                                       strncpy(dst, src, len);\r
+                                       dst[len] = '\0';\r
+                                       src += mElemSize;\r
+                                       dst += (mElemSize - 2 + 1);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*src == 't' || *src == 'T' || *src == 'y' || *src == 'Y' || *src == '1')\r
+                                               *(bool*)dst = true;\r
+                                       else *(bool*)dst = false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_short :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(bool*)dst = (*(short*)src != 0) ? true : false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = *(short*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(short);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int*)dst = (int)*(short*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = (int64_t)*(short*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int64_t);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(float*)dst = (float)(*(short*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(float);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(short*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_long :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(bool*)dst = (*(long*)src != 0) ? true : false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(long*)src < consts::min16 || *(long*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::ReadTo",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = short(*(long*)src);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(short);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(long*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(long);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = (int64_t)*(long*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int64_t);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(float*)dst = (float)(*(long*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(float);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(long*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_int64 :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(bool*)dst = (*(int64_t*)src != 0) ? true : false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min16 || *(int64_t*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::ReadTo",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = short(*(int64_t*)src);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(short);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min32 || *(int64_t*)src > consts::max32)\r
+                                               throw LogicExceptionImpl("Array::ReadTo",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(long*)dst = (long)*(int64_t*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(long);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(int64_t*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int64_t);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(float*)dst = (float)(*(int64_t*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(float);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(int64_t*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_float :\r
+                       if (adtype != IBPP::adFloat || mDesc.array_desc_scale != 0)\r
+                               throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               *(float*)dst = *(float*)src;\r
+                               src += mElemSize;\r
+                               dst += sizeof(float);\r
+                       }\r
+                       break;\r
+\r
+               case blr_double :\r
+                       if (adtype != IBPP::adDouble) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                               _("Incompatible types."));\r
+                       if (mDesc.array_desc_scale != 0)\r
+                       {\r
+                               // Round to scale of NUMERIC(x,y)\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(double*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = *(double*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       break;\r
+\r
+               case blr_timestamp :\r
+                       if (adtype != IBPP::adTimestamp) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               decodeTimestamp(*(IBPP::Timestamp*)dst, *(ISC_TIMESTAMP*)src);\r
+                               src += mElemSize;\r
+                               dst += sizeof(IBPP::Timestamp);\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_date :\r
+                       if (adtype != IBPP::adDate) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               decodeDate(*(IBPP::Date*)dst, *(ISC_DATE*)src);\r
+                               src += mElemSize;\r
+                               dst += sizeof(IBPP::Date);\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_time :\r
+                       if (adtype != IBPP::adTime) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               decodeTime(*(IBPP::Time*)dst, *(ISC_TIME*)src);\r
+                               src += mElemSize;\r
+                               dst += sizeof(IBPP::Time);\r
+                       }\r
+                       break;\r
+\r
+               default :\r
+                       throw LogicExceptionImpl("Array::ReadTo", _("Unknown sql type."));\r
+       }\r
+}\r
+\r
+void ArrayImpl::WriteFrom(IBPP::ADT adtype, const void* data, int datacount)\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::WriteFrom", _("Array description not set."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::WriteFrom", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::WriteFrom", _("No Transaction is attached."));\r
+       if (datacount != mElemCount)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Wrong count of array elements"));\r
+\r
+       // Read user data and convert types to the mBuffer\r
+       int len;\r
+       char* src = (char*)data;\r
+       char* dst = (char*)mBuffer;\r
+\r
+       switch (mDesc.array_desc_dtype)\r
+       {\r
+               case blr_text :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       len = (int)strlen(src);\r
+                                       if (len > mElemSize) len = mElemSize;\r
+                                       strncpy(dst, src, len);\r
+                                       while (len < mElemSize) dst[len++] = ' ';\r
+                                       src += (mElemSize + 1);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *dst = *(bool*)src ? 'T' : 'F';\r
+                                       len = 1;\r
+                                       while (len < mElemSize) dst[len++] = ' ';\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_varying :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       len = (int)strlen(src);\r
+                                       if (len > mElemSize-2) len = mElemSize-2;\r
+                                       strncpy(dst, src, len);\r
+                                       dst[len] = '\0';\r
+                                       src += (mElemSize - 2 + 1);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = (short)1;\r
+                                       dst[2] = *(bool*)src ? 'T' : 'F';\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_short :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = short(*(bool*)src ? 1 : 0);\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = *(short*)src;\r
+                                       src += sizeof(short);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(long*)src < consts::min16 || *(long*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = (short)*(int*)src;\r
+                                       src += sizeof(int);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min16 || *(int64_t*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = (short)*(int64_t*)src;\r
+                                       src += sizeof(int64_t);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst =\r
+                                               (short)floor(*(float*)src * multiplier + 0.5);\r
+                                       src += sizeof(float);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst =\r
+                                               (short)floor(*(double*)src * multiplier + 0.5);\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_long :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(bool*)src ? 1 : 0;\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(short*)src;\r
+                                       src += sizeof(short);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(long*)src;\r
+                                       src += sizeof(long);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min32 || *(int64_t*)src > consts::max32)\r
+                                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(long*)dst = (long)*(int64_t*)src;\r
+                                       src += sizeof(int64_t);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst =\r
+                                               (long)floor(*(float*)src * multiplier + 0.5);\r
+                                       src += sizeof(float);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst =\r
+                                               (long)floor(*(double*)src * multiplier + 0.5);\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_int64 :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(bool*)src ? 1 : 0;\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(short*)src;\r
+                                       src += sizeof(short);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(long*)src;\r
+                                       src += sizeof(long);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(int64_t*)src;\r
+                                       src += sizeof(int64_t);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst =\r
+                                               (int64_t)floor(*(float*)src * multiplier + 0.5);\r
+                                       src += sizeof(float);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst =\r
+                                               (int64_t)floor(*(double*)src * multiplier + 0.5);\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else\r
+                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                       _("Incompatible types (blr_int64 and ADT %d)."), (int)adtype);\r
+                       break;\r
+\r
+               case blr_float :\r
+                       if (adtype != IBPP::adFloat || mDesc.array_desc_scale != 0)\r
+                               throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               *(float*)dst = *(float*)src;\r
+                               src += sizeof(float);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               case blr_double :\r
+                       if (adtype != IBPP::adDouble) throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                                               _("Incompatible types."));\r
+                       if (mDesc.array_desc_scale != 0)\r
+                       {\r
+                               // Round to scale of NUMERIC(x,y)\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst =\r
+                                               floor(*(double*)src * multiplier + 0.5) / multiplier;\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = *(double*)src;\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       break;\r
+\r
+               case blr_timestamp :\r
+                       if (adtype != IBPP::adTimestamp) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               encodeTimestamp(*(ISC_TIMESTAMP*)dst, *(IBPP::Timestamp*)src);\r
+                               src += sizeof(IBPP::Timestamp);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_date :\r
+                       if (adtype != IBPP::adDate) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               encodeDate(*(ISC_DATE*)dst, *(IBPP::Date*)src); \r
+                               src += sizeof(IBPP::Date);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_time :\r
+                       if (adtype != IBPP::adTime) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               encodeTime(*(ISC_TIME*)dst, *(IBPP::Time*)src);\r
+                               src += sizeof(IBPP::Time);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               default :\r
+                       throw LogicExceptionImpl("Array::WriteFrom", _("Unknown sql type."));\r
+       }\r
+\r
+       IBS status;\r
+       ISC_LONG lenbuf = mBufferSize;\r
+       (*gds.Call()->m_array_put_slice)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mId, &mDesc, mBuffer, &lenbuf);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Array::WriteFrom", _("isc_array_put_slice failed."));\r
+       if (lenbuf != mBufferSize)\r
+               throw SQLExceptionImpl(status, "Array::WriteFrom", _("Internal buffer size discrepancy."));\r
+}\r
+\r
+IBPP::Database ArrayImpl::DatabasePtr() const\r
+{\r
+       if (mDatabase == 0) throw LogicExceptionImpl("Array::DatabasePtr",\r
+                       _("No Database is attached."));\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::Transaction ArrayImpl::TransactionPtr() const\r
+{\r
+       if (mTransaction == 0) throw LogicExceptionImpl("Array::TransactionPtr",\r
+                       _("No Transaction is attached."));\r
+       return mTransaction;\r
+}\r
+\r
+IBPP::IArray* ArrayImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void ArrayImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void ArrayImpl::Init()\r
+{\r
+       ResetId();\r
+       mDescribed = false;\r
+       mDatabase = 0;\r
+       mTransaction = 0;\r
+       mBuffer = 0;\r
+       mBufferSize = 0;\r
+}\r
+\r
+void ArrayImpl::SetId(ISC_QUAD* quad)\r
+{\r
+       if (quad == 0)\r
+               throw LogicExceptionImpl("ArrayImpl::SetId", _("Null Id reference detected."));\r
+\r
+       memcpy(&mId, quad, sizeof(mId));\r
+       mIdAssigned = true;\r
+}\r
+\r
+void ArrayImpl::GetId(ISC_QUAD* quad)\r
+{\r
+       if (quad == 0)\r
+               throw LogicExceptionImpl("ArrayImpl::GetId", _("Null Id reference detected."));\r
+\r
+       memcpy(quad, &mId, sizeof(mId));\r
+}\r
+\r
+void ArrayImpl::ResetId()\r
+{\r
+       memset(&mId, 0, sizeof(mId));\r
+       mIdAssigned = false;\r
+}\r
+\r
+void ArrayImpl::AllocArrayBuffer()\r
+{\r
+       // Clean previous buffer if any\r
+       if (mBuffer != 0) delete [] (char*)mBuffer;\r
+       mBuffer = 0;\r
+\r
+       // Computes total number of elements in the array or slice\r
+       mElemCount = 1;\r
+       for (int i = 0; i < mDesc.array_desc_dimensions; i++)\r
+       {\r
+               mElemCount = mElemCount *\r
+                       (mDesc.array_desc_bounds[i].array_bound_upper -\r
+                               mDesc.array_desc_bounds[i].array_bound_lower + 1);\r
+       }\r
+\r
+       // Allocates a buffer for this count of elements\r
+       mElemSize = mDesc.array_desc_length;\r
+       if (mDesc.array_desc_dtype == blr_varying) mElemSize += 2;\r
+       else if (mDesc.array_desc_dtype == blr_cstring) mElemSize += 1;\r
+       mBufferSize = mElemSize * mElemCount;\r
+       mBuffer = (void*) new char[mBufferSize];\r
+}\r
+\r
+void ArrayImpl::AttachDatabaseImpl(DatabaseImpl* database)\r
+{\r
+       if (database == 0) throw LogicExceptionImpl("Array::AttachDatabase",\r
+                       _("Can't attach a 0 Database object."));\r
+\r
+       if (mDatabase != 0) mDatabase->DetachArrayImpl(this);\r
+       mDatabase = database;\r
+       mDatabase->AttachArrayImpl(this);\r
+}\r
+\r
+void ArrayImpl::AttachTransactionImpl(TransactionImpl* transaction)\r
+{\r
+       if (transaction == 0) throw LogicExceptionImpl("Array::AttachTransaction",\r
+                       _("Can't attach a 0 Transaction object."));\r
+\r
+       if (mTransaction != 0) mTransaction->DetachArrayImpl(this);\r
+       mTransaction = transaction;\r
+       mTransaction->AttachArrayImpl(this);\r
+}\r
+\r
+void ArrayImpl::DetachDatabaseImpl()\r
+{\r
+       if (mDatabase == 0) return;\r
+\r
+       mDatabase->DetachArrayImpl(this);\r
+       mDatabase = 0;\r
+}\r
+\r
+void ArrayImpl::DetachTransactionImpl()\r
+{\r
+       if (mTransaction == 0) return;\r
+\r
+       mTransaction->DetachArrayImpl(this);\r
+       mTransaction = 0;\r
+}\r
+\r
+ArrayImpl::ArrayImpl(DatabaseImpl* database, TransactionImpl* transaction)\r
+       : mRefCount(0)\r
+{\r
+       Init();\r
+       AttachDatabaseImpl(database);\r
+       if (transaction != 0) AttachTransactionImpl(transaction);\r
+}\r
+\r
+ArrayImpl::~ArrayImpl()\r
+{\r
+       try { if (mTransaction != 0) mTransaction->DetachArrayImpl(this); }\r
+               catch (...) {}\r
+       try { if (mDatabase != 0) mDatabase->DetachArrayImpl(this); }\r
+               catch (...) {}\r
+       try { if (mBuffer != 0) delete [] (char*)mBuffer; }\r
+               catch (...) {}\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/blob.cpp b/stglibs/ibpp.lib/blob.cpp
new file mode 100644 (file)
index 0000000..cfdd61f
--- /dev/null
@@ -0,0 +1,381 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: blob.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, Blob class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void BlobImpl::Open()\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Blob::Open", _("Blob already opened."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Blob::Open", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Blob::Open", _("No Transaction is attached."));\r
+       if (! mIdAssigned)\r
+               throw LogicExceptionImpl("Blob::Open", _("Blob Id is not assigned."));\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_open_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Open", _("isc_open_blob2 failed."));\r
+       mWriteMode = false;\r
+}\r
+\r
+void BlobImpl::Create()\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Blob::Create", _("Blob already opened."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Blob::Create", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Blob::Create", _("No Transaction is attached."));\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_create_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Create",\r
+                       _("isc_create_blob failed."));\r
+       mIdAssigned = true;\r
+       mWriteMode = true;\r
+}\r
+\r
+void BlobImpl::Close()\r
+{\r
+       if (mHandle == 0) return;       // Not opened anyway\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_close_blob)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Close", _("isc_close_blob failed."));\r
+       mHandle = 0;\r
+}\r
+\r
+void BlobImpl::Cancel()\r
+{\r
+       if (mHandle == 0) return;       // Not opened anyway\r
+\r
+       if (! mWriteMode)\r
+               throw LogicExceptionImpl("Blob::Cancel", _("Can't cancel a Blob opened for read"));\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_cancel_blob)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Cancel", _("isc_cancel_blob failed."));\r
+       mHandle = 0;\r
+       mIdAssigned = false;\r
+}\r
+\r
+int BlobImpl::Read(void* buffer, int size)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Blob::Read", _("The Blob is not opened"));\r
+       if (mWriteMode)\r
+               throw LogicExceptionImpl("Blob::Read", _("Can't read from Blob opened for write"));\r
+       if (size < 1 || size > (64*1024-1))\r
+               throw LogicExceptionImpl("Blob::Read", _("Invalid segment size (max 64Kb-1)"));\r
+\r
+       IBS status;\r
+       unsigned short bytesread;\r
+       int result = (*gds.Call()->m_get_segment)(status.Self(), &mHandle, &bytesread,\r
+                                       (unsigned short)size, (char*)buffer);\r
+       if (result == isc_segstr_eof) return 0; // Fin du blob\r
+       if (result != isc_segment && status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Read", _("isc_get_segment failed."));\r
+       return (int)bytesread;\r
+}\r
+\r
+void BlobImpl::Write(const void* buffer, int size)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Blob::Write", _("The Blob is not opened"));\r
+       if (! mWriteMode)\r
+               throw LogicExceptionImpl("Blob::Write", _("Can't write to Blob opened for read"));\r
+       if (size < 1 || size > (64*1024-1))\r
+               throw LogicExceptionImpl("Blob::Write", _("Invalid segment size (max 64Kb-1)"));\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_put_segment)(status.Self(), &mHandle,\r
+               (unsigned short)size, (char*)buffer);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Write", _("isc_put_segment failed."));\r
+}\r
+\r
+void BlobImpl::Info(int* Size, int* Largest, int* Segments)\r
+{\r
+       char items[] = {isc_info_blob_total_length,\r
+                                       isc_info_blob_max_segment,\r
+                                       isc_info_blob_num_segments};\r
+\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Blob::GetInfo", _("The Blob is not opened"));\r
+\r
+       IBS status;\r
+       RB result(100);\r
+       (*gds.Call()->m_blob_info)(status.Self(), &mHandle, sizeof(items), items,\r
+               (short)result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::GetInfo", _("isc_blob_info failed."));\r
+\r
+       if (Size != 0) *Size = result.GetValue(isc_info_blob_total_length);\r
+       if (Largest != 0) *Largest = result.GetValue(isc_info_blob_max_segment);\r
+       if (Segments != 0) *Segments = result.GetValue(isc_info_blob_num_segments);\r
+}\r
+\r
+void BlobImpl::Save(const std::string& data)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Blob::Save", _("Blob already opened."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Blob::Save", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Blob::Save", _("No Transaction is attached."));\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_create_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Save",\r
+                       _("isc_create_blob failed."));\r
+       mIdAssigned = true;\r
+       mWriteMode = true;\r
+\r
+       size_t pos = 0;\r
+       size_t len = data.size();\r
+       while (len != 0)\r
+       {\r
+               size_t blklen = (len < 32*1024-1) ? len : 32*1024-1;\r
+               status.Reset();\r
+               (*gds.Call()->m_put_segment)(status.Self(), &mHandle,\r
+                       (unsigned short)blklen, const_cast<char*>(data.data()+pos));\r
+               if (status.Errors())\r
+                       throw SQLExceptionImpl(status, "Blob::Save",\r
+                                       _("isc_put_segment failed."));\r
+               pos += blklen;\r
+               len -= blklen;\r
+       }\r
+       \r
+       status.Reset();\r
+       (*gds.Call()->m_close_blob)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Save", _("isc_close_blob failed."));\r
+       mHandle = 0;\r
+}\r
+\r
+void BlobImpl::Load(std::string& data)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Blob::Load", _("Blob already opened."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Blob::Load", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Blob::Load", _("No Transaction is attached."));\r
+       if (! mIdAssigned)\r
+               throw LogicExceptionImpl("Blob::Load", _("Blob Id is not assigned."));\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_open_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Load", _("isc_open_blob2 failed."));\r
+       mWriteMode = false;\r
+\r
+       size_t blklen = 32*1024-1;\r
+       data.resize(blklen);\r
+\r
+       size_t size = 0;\r
+       size_t pos = 0;\r
+       for (;;)\r
+       {\r
+               status.Reset();\r
+               unsigned short bytesread;\r
+               int result = (*gds.Call()->m_get_segment)(status.Self(), &mHandle,\r
+                                               &bytesread, (unsigned short)blklen,\r
+                                                       const_cast<char*>(data.data()+pos));\r
+               if (result == isc_segstr_eof) break;    // End of blob\r
+               if (result != isc_segment && status.Errors())\r
+                       throw SQLExceptionImpl(status, "Blob::Load", _("isc_get_segment failed."));\r
+\r
+               pos += bytesread;\r
+               size += bytesread;\r
+               data.resize(size + blklen);\r
+       }\r
+       data.resize(size);\r
+       \r
+       status.Reset();\r
+       (*gds.Call()->m_close_blob)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Blob::Load", _("isc_close_blob failed."));\r
+       mHandle = 0;\r
+}\r
+\r
+IBPP::Database BlobImpl::DatabasePtr() const\r
+{\r
+       if (mDatabase == 0) throw LogicExceptionImpl("Blob::DatabasePtr",\r
+                       _("No Database is attached."));\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::Transaction BlobImpl::TransactionPtr() const\r
+{\r
+       if (mTransaction == 0) throw LogicExceptionImpl("Blob::TransactionPtr",\r
+                       _("No Transaction is attached."));\r
+       return mTransaction;\r
+}\r
+\r
+IBPP::IBlob* BlobImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void BlobImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void BlobImpl::Init()\r
+{\r
+       mIdAssigned = false;\r
+       mWriteMode = false;\r
+       mHandle = 0;\r
+       mDatabase = 0;\r
+       mTransaction = 0;\r
+}\r
+\r
+void BlobImpl::SetId(ISC_QUAD* quad)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("BlobImpl::SetId", _("Can't set Id on an opened BlobImpl."));\r
+       if (quad == 0)\r
+               throw LogicExceptionImpl("BlobImpl::SetId", _("Null Id reference detected."));\r
+\r
+       memcpy(&mId, quad, sizeof(mId));\r
+       mIdAssigned = true;\r
+}\r
+\r
+void BlobImpl::GetId(ISC_QUAD* quad)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("BlobImpl::GetId", _("Can't get Id on an opened BlobImpl."));\r
+       if (! mWriteMode)\r
+               throw LogicExceptionImpl("BlobImpl::GetId", _("Can only get Id of a newly created Blob."));\r
+       if (quad == 0)\r
+               throw LogicExceptionImpl("BlobImpl::GetId", _("Null Id reference detected."));\r
+\r
+       memcpy(quad, &mId, sizeof(mId));\r
+}\r
+\r
+void BlobImpl::AttachDatabaseImpl(DatabaseImpl* database)\r
+{\r
+       if (database == 0) throw LogicExceptionImpl("Blob::AttachDatabase",\r
+                       _("Can't attach a NULL Database object."));\r
+\r
+       if (mDatabase != 0) mDatabase->DetachBlobImpl(this);\r
+       mDatabase = database;\r
+       mDatabase->AttachBlobImpl(this);\r
+}\r
+\r
+void BlobImpl::AttachTransactionImpl(TransactionImpl* transaction)\r
+{\r
+       if (transaction == 0) throw LogicExceptionImpl("Blob::AttachTransaction",\r
+                       _("Can't attach a NULL Transaction object."));\r
+\r
+       if (mTransaction != 0) mTransaction->DetachBlobImpl(this);\r
+       mTransaction = transaction;\r
+       mTransaction->AttachBlobImpl(this);\r
+}\r
+\r
+void BlobImpl::DetachDatabaseImpl()\r
+{\r
+       if (mDatabase == 0) return;\r
+\r
+       mDatabase->DetachBlobImpl(this);\r
+       mDatabase = 0;\r
+}\r
+\r
+void BlobImpl::DetachTransactionImpl()\r
+{\r
+       if (mTransaction == 0) return;\r
+\r
+       mTransaction->DetachBlobImpl(this);\r
+       mTransaction = 0;\r
+}\r
+\r
+BlobImpl::BlobImpl(DatabaseImpl* database, TransactionImpl* transaction)\r
+       : mRefCount(0)\r
+{\r
+       Init();\r
+       AttachDatabaseImpl(database);\r
+       if (transaction != 0) AttachTransactionImpl(transaction);\r
+}\r
+\r
+BlobImpl::~BlobImpl()\r
+{\r
+       try\r
+       {\r
+               if (mHandle != 0)\r
+               {\r
+                       if (mWriteMode) Cancel();\r
+                       else Close();\r
+               }\r
+       }\r
+       catch (...) { }\r
+       \r
+       try { if (mTransaction != 0) mTransaction->DetachBlobImpl(this); }\r
+               catch (...) { }\r
+       try { if (mDatabase != 0) mDatabase->DetachBlobImpl(this); }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/database.cpp b/stglibs/ibpp.lib/database.cpp
new file mode 100644 (file)
index 0000000..64b705d
--- /dev/null
@@ -0,0 +1,483 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: database.cpp,v 1.1 2007/05/05 17:00:42 faust Exp $\r
+//     Subject : IBPP, Database class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <algorithm>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void DatabaseImpl::Create(int dialect)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Database::Create", _("Database is already connected."));\r
+       if (mDatabaseName.empty())\r
+               throw LogicExceptionImpl("Database::Create", _("Unspecified database name."));\r
+       if (mUserName.empty())\r
+               throw LogicExceptionImpl("Database::Create", _("Unspecified user name."));\r
+       if (dialect != 1 && dialect != 3)\r
+               throw LogicExceptionImpl("Database::Create", _("Only dialects 1 and 3 are supported."));\r
+\r
+       // Build the SQL Create Statement\r
+       std::string create;\r
+       create.assign("CREATE DATABASE '");\r
+       if (! mServerName.empty()) create.append(mServerName).append(":");\r
+       create.append(mDatabaseName).append("' ");\r
+\r
+       create.append("USER '").append(mUserName).append("' ");\r
+       if (! mUserPassword.empty())\r
+               create.append("PASSWORD '").append(mUserPassword).append("' ");\r
+\r
+       if (! mCreateParams.empty()) create.append(mCreateParams);\r
+\r
+       // Call ExecuteImmediate to create the database\r
+       isc_tr_handle tr_handle = 0;\r
+       IBS status;\r
+    (*gds.Call()->m_dsql_execute_immediate)(status.Self(), &mHandle, &tr_handle,\r
+       0, const_cast<char*>(create.c_str()), short(dialect), NULL);\r
+    if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Database::Create", _("isc_dsql_execute_immediate failed"));\r
+\r
+       Disconnect();\r
+}\r
+\r
+void DatabaseImpl::Connect()\r
+{\r
+       if (mHandle != 0) return;       // Already connected\r
+\r
+       if (mDatabaseName.empty())\r
+               throw LogicExceptionImpl("Database::Connect", _("Unspecified database name."));\r
+       if (mUserName.empty())\r
+               throw LogicExceptionImpl("Database::Connect", _("Unspecified user name."));\r
+\r
+    // Build a DPB based on the properties\r
+       DPB dpb;\r
+    dpb.Insert(isc_dpb_user_name, mUserName.c_str());\r
+    dpb.Insert(isc_dpb_password, mUserPassword.c_str());\r
+    if (! mRoleName.empty()) dpb.Insert(isc_dpb_sql_role_name, mRoleName.c_str());\r
+    if (! mCharSet.empty()) dpb.Insert(isc_dpb_lc_ctype, mCharSet.c_str());\r
+\r
+       std::string connect;\r
+       if (! mServerName.empty())\r
+               connect.assign(mServerName).append(":");\r
+       connect.append(mDatabaseName);\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_attach_database)(status.Self(), (short)connect.size(),\r
+               const_cast<char*>(connect.c_str()), &mHandle, dpb.Size(), dpb.Self());\r
+    if (status.Errors())\r
+    {\r
+        mHandle = 0;     // Should be, but better be sure...\r
+               throw SQLExceptionImpl(status, "Database::Connect", _("isc_attach_database failed"));\r
+    }\r
+\r
+       // Now, get ODS version information and dialect.\r
+       // If ODS major is lower of equal to 9, we reject the connection.\r
+       // If ODS major is 10 or higher, this is at least an InterBase 6.x Server\r
+       // OR FireBird 1.x Server.\r
+\r
+       char items[] = {isc_info_ods_version,\r
+                                       isc_info_db_SQL_dialect,\r
+                                       isc_info_end};\r
+       RB result(100);\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,\r
+               result.Size(), result.Self());\r
+       if (status.Errors())\r
+       {\r
+               status.Reset();\r
+           (*gds.Call()->m_detach_database)(status.Self(), &mHandle);\r
+        mHandle = 0;     // Should be, but better be sure...\r
+               throw SQLExceptionImpl(status, "Database::Connect", _("isc_database_info failed"));\r
+       }\r
+\r
+       int ODS = result.GetValue(isc_info_ods_version);\r
+       if (ODS <= 9)\r
+       {\r
+               status.Reset();\r
+           (*gds.Call()->m_detach_database)(status.Self(), &mHandle);\r
+        mHandle = 0;     // Should be, but better be sure...\r
+               throw LogicExceptionImpl("Database::Connect",\r
+                       _("Unsupported Server : wrong ODS version (%d), at least '10' required."), ODS);\r
+       }\r
+\r
+       mDialect = result.GetValue(isc_info_db_SQL_dialect);\r
+       if (mDialect != 1 && mDialect != 3)\r
+       {\r
+               status.Reset();\r
+           (*gds.Call()->m_detach_database)(status.Self(), &mHandle);\r
+        mHandle = 0;     // Should be, but better be sure...\r
+               throw LogicExceptionImpl("Database::Connect", _("Dialect 1 or 3 required"));\r
+       }\r
+\r
+       // Now, verify the GDS32.DLL we are using is compatible with the server\r
+       if (ODS >= 10 && gds.Call()->mGDSVersion < 60)\r
+       {\r
+               status.Reset();\r
+           (*gds.Call()->m_detach_database)(status.Self(), &mHandle);\r
+        mHandle = 0;     // Should be, but better be sure...\r
+               throw LogicExceptionImpl("Database::Connect", _("GDS32.DLL version 5 against IBSERVER 6"));\r
+       }\r
+}\r
+\r
+void DatabaseImpl::Inactivate()\r
+{\r
+       if (mHandle == 0) return;       // Not connected anyway\r
+\r
+    IBS status;\r
+\r
+    // Rollback any started transaction...\r
+       for (unsigned i = 0; i < mTransactions.size(); i++)\r
+       {\r
+               if (mTransactions[i]->Started())\r
+                       mTransactions[i]->Rollback();\r
+       }\r
+\r
+       // Cancel all pending event traps\r
+       for (unsigned i = 0; i < mEvents.size(); i++)\r
+               mEvents[i]->Clear();\r
+\r
+       // Let's detach from all Blobs\r
+       while (mBlobs.size() > 0)\r
+               mBlobs.back()->DetachDatabaseImpl();\r
+\r
+       // Let's detach from all Arrays\r
+       while (mArrays.size() > 0)\r
+               mArrays.back()->DetachDatabaseImpl();\r
+\r
+       // Let's detach from all Statements\r
+       while (mStatements.size() > 0)\r
+               mStatements.back()->DetachDatabaseImpl();\r
+\r
+       // Let's detach from all Transactions\r
+       while (mTransactions.size() > 0)\r
+               mTransactions.back()->DetachDatabaseImpl(this);\r
+\r
+       // Let's detach from all Events\r
+       while (mEvents.size() > 0)\r
+               mEvents.back()->DetachDatabaseImpl();\r
+}\r
+\r
+void DatabaseImpl::Disconnect()\r
+{\r
+       if (mHandle == 0) return;       // Not connected anyway\r
+\r
+       // Put the connection to rest\r
+       Inactivate();\r
+\r
+       // Detach from the server\r
+       IBS status;\r
+    (*gds.Call()->m_detach_database)(status.Self(), &mHandle);\r
+\r
+    // Should we throw, set mHandle to 0 first, because Disconnect() may\r
+       // be called from Database destructor (keeps the object coherent).\r
+       mHandle = 0;\r
+    if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Database::Disconnect", _("isc_detach_database failed"));\r
+}\r
+\r
+void DatabaseImpl::Drop()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Database::Drop", _("Database must be connected."));\r
+\r
+       // Put the connection to a rest\r
+       Inactivate();\r
+\r
+       IBS vector;\r
+       (*gds.Call()->m_drop_database)(vector.Self(), &mHandle);\r
+    if (vector.Errors())\r
+       throw SQLExceptionImpl(vector, "Database::Drop", _("isc_drop_database failed"));\r
+\r
+    mHandle = 0;\r
+}\r
+\r
+void DatabaseImpl::Info(int* ODSMajor, int* ODSMinor,\r
+       int* PageSize, int* Pages, int* Buffers, int* Sweep,\r
+       bool* Sync, bool* Reserve)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Database::Info", _("Database is not connected."));\r
+\r
+       char items[] = {isc_info_ods_version,\r
+                                       isc_info_ods_minor_version,\r
+                                       isc_info_page_size,\r
+                                       isc_info_allocation,\r
+                                       isc_info_num_buffers,\r
+                                       isc_info_sweep_interval,\r
+                                       isc_info_forced_writes,\r
+                                       isc_info_no_reserve,\r
+                                       isc_info_end};\r
+    IBS status;\r
+       RB result(256);\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,\r
+               result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Database::Info", _("isc_database_info failed"));\r
+\r
+       if (ODSMajor != 0) *ODSMajor = result.GetValue(isc_info_ods_version);\r
+       if (ODSMinor != 0) *ODSMinor = result.GetValue(isc_info_ods_minor_version);\r
+       if (PageSize != 0) *PageSize = result.GetValue(isc_info_page_size);\r
+       if (Pages != 0) *Pages = result.GetValue(isc_info_allocation);\r
+       if (Buffers != 0) *Buffers = result.GetValue(isc_info_num_buffers);\r
+       if (Sweep != 0) *Sweep = result.GetValue(isc_info_sweep_interval);\r
+       if (Sync != 0)\r
+               *Sync = result.GetValue(isc_info_forced_writes) == 1 ? true : false;\r
+       if (Reserve != 0)\r
+               *Reserve = result.GetValue(isc_info_no_reserve) == 1 ? false : true;\r
+}\r
+\r
+void DatabaseImpl::Statistics(int* Fetches, int* Marks, int* Reads, int* Writes)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Database::Statistics", _("Database is not connected."));\r
+\r
+       char items[] = {isc_info_fetches,\r
+                                       isc_info_marks,\r
+                                       isc_info_reads,\r
+                                       isc_info_writes,\r
+                                       isc_info_end};\r
+    IBS status;\r
+       RB result(128);\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,\r
+               result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Database::Statistics", _("isc_database_info failed"));\r
+\r
+       if (Fetches != 0) *Fetches = result.GetValue(isc_info_fetches);\r
+       if (Marks != 0) *Marks = result.GetValue(isc_info_marks);\r
+       if (Reads != 0) *Reads = result.GetValue(isc_info_reads);\r
+       if (Writes != 0) *Writes = result.GetValue(isc_info_writes);\r
+}\r
+\r
+void DatabaseImpl::Counts(int* Insert, int* Update, int* Delete, \r
+       int* ReadIdx, int* ReadSeq)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Database::Counts", _("Database is not connected."));\r
+\r
+       char items[] = {isc_info_insert_count,\r
+                                       isc_info_update_count,\r
+                                       isc_info_delete_count,\r
+                                       isc_info_read_idx_count,\r
+                                       isc_info_read_seq_count,\r
+                                       isc_info_end};\r
+    IBS status;\r
+       RB result(1024);\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,\r
+               result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Database::Counts", _("isc_database_info failed"));\r
+\r
+       if (Insert != 0) *Insert = result.GetCountValue(isc_info_insert_count);\r
+       if (Update != 0) *Update = result.GetCountValue(isc_info_update_count);\r
+       if (Delete != 0) *Delete = result.GetCountValue(isc_info_delete_count);\r
+       if (ReadIdx != 0) *ReadIdx = result.GetCountValue(isc_info_read_idx_count);\r
+       if (ReadSeq != 0) *ReadSeq = result.GetCountValue(isc_info_read_seq_count);\r
+}\r
+\r
+void DatabaseImpl::Users(std::vector<std::string>& users)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Database::Users", _("Database is not connected."));\r
+\r
+       char items[] = {isc_info_user_names,\r
+                                       isc_info_end};\r
+    IBS status;\r
+       RB result(8000);\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,\r
+               result.Size(), result.Self());\r
+       if (status.Errors())\r
+       {\r
+               status.Reset();\r
+               throw SQLExceptionImpl(status, "Database::Users", _("isc_database_info failed"));\r
+       }\r
+\r
+       users.clear();\r
+       char* p = result.Self();\r
+       while (*p == isc_info_user_names)\r
+       {\r
+               p += 3;         // Get to the length byte (there are two undocumented bytes which we skip)\r
+               int len = (int)(*p);\r
+               ++p;            // Get to the first char of username\r
+       if (len != 0) users.push_back(std::string().append(p, len));\r
+               p += len;       // Skip username\r
+    }\r
+       return;\r
+}\r
+\r
+IBPP::IDatabase* DatabaseImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void DatabaseImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void DatabaseImpl::AttachTransactionImpl(TransactionImpl* tr)\r
+{\r
+       if (tr == 0)\r
+               throw LogicExceptionImpl("Database::AttachTransaction",\r
+                                       _("Transaction object is null."));\r
+\r
+       mTransactions.push_back(tr);\r
+}\r
+\r
+void DatabaseImpl::DetachTransactionImpl(TransactionImpl* tr)\r
+{\r
+       if (tr == 0)\r
+               throw LogicExceptionImpl("Database::DetachTransaction",\r
+                               _("ITransaction object is null."));\r
+\r
+       mTransactions.erase(std::find(mTransactions.begin(), mTransactions.end(), tr));\r
+}\r
+\r
+void DatabaseImpl::AttachStatementImpl(StatementImpl* st)\r
+{\r
+       if (st == 0)\r
+               throw LogicExceptionImpl("Database::AttachStatement",\r
+                                       _("Can't attach a null Statement object."));\r
+\r
+       mStatements.push_back(st);\r
+}\r
+\r
+void DatabaseImpl::DetachStatementImpl(StatementImpl* st)\r
+{\r
+       if (st == 0)\r
+               throw LogicExceptionImpl("Database::DetachStatement",\r
+                               _("Can't detach a null Statement object."));\r
+\r
+       mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));\r
+}\r
+\r
+void DatabaseImpl::AttachBlobImpl(BlobImpl* bb)\r
+{\r
+       if (bb == 0)\r
+               throw LogicExceptionImpl("Database::AttachBlob",\r
+                                       _("Can't attach a null Blob object."));\r
+\r
+       mBlobs.push_back(bb);\r
+}\r
+\r
+void DatabaseImpl::DetachBlobImpl(BlobImpl* bb)\r
+{\r
+       if (bb == 0)\r
+               throw LogicExceptionImpl("Database::DetachBlob",\r
+                               _("Can't detach a null Blob object."));\r
+\r
+       mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));\r
+}\r
+\r
+void DatabaseImpl::AttachArrayImpl(ArrayImpl* ar)\r
+{\r
+       if (ar == 0)\r
+               throw LogicExceptionImpl("Database::AttachArray",\r
+                                       _("Can't attach a null Array object."));\r
+\r
+       mArrays.push_back(ar);\r
+}\r
+\r
+void DatabaseImpl::DetachArrayImpl(ArrayImpl* ar)\r
+{\r
+       if (ar == 0)\r
+               throw LogicExceptionImpl("Database::DetachArray",\r
+                               _("Can't detach a null Array object."));\r
+\r
+       mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));\r
+}\r
+\r
+void DatabaseImpl::AttachEventsImpl(EventsImpl* ev)\r
+{\r
+       if (ev == 0)\r
+               throw LogicExceptionImpl("Database::AttachEventsImpl",\r
+                                       _("Can't attach a null Events object."));\r
+\r
+       mEvents.push_back(ev);\r
+}\r
+\r
+void DatabaseImpl::DetachEventsImpl(EventsImpl* ev)\r
+{\r
+       if (ev == 0)\r
+               throw LogicExceptionImpl("Database::DetachEventsImpl",\r
+                               _("Can't detach a null Events object."));\r
+\r
+       mEvents.erase(std::find(mEvents.begin(), mEvents.end(), ev));\r
+}\r
+\r
+DatabaseImpl::DatabaseImpl(const std::string& ServerName, const std::string& DatabaseName,\r
+                                                  const std::string& UserName, const std::string& UserPassword,\r
+                                                  const std::string& RoleName, const std::string& CharSet,\r
+                                                  const std::string& CreateParams) :\r
+\r
+       mRefCount(0), mHandle(0),\r
+       mServerName(ServerName), mDatabaseName(DatabaseName),\r
+       mUserName(UserName), mUserPassword(UserPassword), mRoleName(RoleName),\r
+       mCharSet(CharSet), mCreateParams(CreateParams),\r
+       mDialect(3)\r
+{\r
+}\r
+\r
+DatabaseImpl::~DatabaseImpl()\r
+{\r
+       try { if (Connected()) Disconnect(); }\r
+               catch(...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/date.cpp b/stglibs/ibpp.lib/date.cpp
new file mode 100644 (file)
index 0000000..f483824
--- /dev/null
@@ -0,0 +1,209 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: date.cpp,v 1.1 2007/05/05 17:00:42 faust Exp $\r
+//     Subject : IBPP, Date class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <time.h>              // Can't use <ctime> thanks to MSVC6 buggy library\r
+\r
+using namespace ibpp_internals;\r
+\r
+void IBPP::Date::Today()\r
+{\r
+       time_t systime = time(0);\r
+       tm* loctime = localtime(&systime);\r
+\r
+       if (! IBPP::itod(&mDate, loctime->tm_year + 1900,\r
+               loctime->tm_mon + 1, loctime->tm_mday))\r
+                       throw LogicExceptionImpl("Date::Today", _("Out of range"));\r
+}\r
+\r
+void IBPP::Date::SetDate(int dt)\r
+{\r
+       if (! IBPP::dtoi(dt, 0, 0, 0))\r
+               throw LogicExceptionImpl("Date::SetDate", _("Out of range"));\r
+       mDate = dt;\r
+}\r
+\r
+void IBPP::Date::SetDate(int year, int month, int day)\r
+{\r
+       if (! IBPP::itod(&mDate, year, month, day))\r
+               throw LogicExceptionImpl("Date::SetDate", _("Out of range"));\r
+}\r
+\r
+void IBPP::Date::GetDate(int& year, int& month, int& day) const\r
+{\r
+       if (! IBPP::dtoi(mDate, &year, &month, &day))\r
+               throw LogicExceptionImpl("Date::GetDate", _("Out of range"));\r
+}\r
+\r
+int IBPP::Date::Year() const\r
+{\r
+       int year;\r
+       if (! IBPP::dtoi(mDate, &year, 0, 0))\r
+               throw LogicExceptionImpl("Date::Year", _("Out of range"));\r
+       return year;\r
+}\r
+\r
+int IBPP::Date::Month() const\r
+{\r
+       int month;\r
+       if (! IBPP::dtoi(mDate, 0, &month, 0))\r
+               throw LogicExceptionImpl("Date::Month", _("Out of range"));\r
+       return month;\r
+}\r
+\r
+int IBPP::Date::Day() const\r
+{\r
+       int day;\r
+       if (! IBPP::dtoi(mDate, 0, 0, &day))\r
+               throw LogicExceptionImpl("Date::Day", _("Out of range"));\r
+       return day;\r
+}\r
+\r
+void IBPP::Date::Add(int days)\r
+{\r
+       int newdate = mDate + days;             // days can be signed\r
+       if (! IBPP::dtoi(newdate, 0, 0, 0))\r
+               throw LogicExceptionImpl("Date::Add()", _("Out of range"));\r
+       mDate = newdate;\r
+}\r
+\r
+void IBPP::Date::StartOfMonth()\r
+{\r
+       int year, month;\r
+       if (! IBPP::dtoi(mDate, &year, &month, 0))\r
+               throw LogicExceptionImpl("Date::StartOfMonth()", _("Out of range"));\r
+       if (! IBPP::itod(&mDate, year, month, 1))               // First of same month\r
+               throw LogicExceptionImpl("Date::StartOfMonth()", _("Out of range"));\r
+}\r
+\r
+void IBPP::Date::EndOfMonth()\r
+{\r
+       int year, month;\r
+       if (! IBPP::dtoi(mDate, &year, &month, 0))\r
+               throw LogicExceptionImpl("Date::EndOfMonth()", _("Out of range"));\r
+       if (++month > 12) { month = 1; year++; }\r
+       if (! IBPP::itod(&mDate, year, month, 1))       // First of next month\r
+               throw LogicExceptionImpl("Date::EndOfMonth()", _("Out of range"));\r
+       mDate--;        // Last day of original month, all weird cases accounted for\r
+}\r
+\r
+IBPP::Date::Date(int year, int month, int day)\r
+{\r
+       SetDate(year, month, day);\r
+}\r
+\r
+IBPP::Date::Date(const IBPP::Date& copied)\r
+{\r
+       mDate = copied.mDate;\r
+}\r
+\r
+IBPP::Date& IBPP::Date::operator=(const IBPP::Timestamp& assigned)\r
+{\r
+       mDate = assigned.GetDate();\r
+       return *this;\r
+}\r
+\r
+IBPP::Date& IBPP::Date::operator=(const IBPP::Date& assigned)\r
+{\r
+       mDate = assigned.mDate;\r
+       return *this;\r
+}\r
+\r
+// The following date calculations were inspired by web pages found on\r
+// Peter Baum web homepage at 'http://www.capecod.net/~pbaum/'.\r
+// His contact info is at : 'http://home.capecod.net/~pbaum/contact.htm'.\r
+// Please, understand that Peter Baum is not related to this IBPP project.\r
+// So __please__, do not contact him regarding IBPP matters.\r
+\r
+//     Take a date, in its integer format as used in IBPP internals and splits\r
+//     it in year (4 digits), month (1-12), day (1-31)\r
+\r
+bool IBPP::dtoi (int date, int *y, int *m, int *d)\r
+{\r
+    int RataDie, Z, H, A, B, C;\r
+    int year, month, day;\r
+\r
+       // Validity control.\r
+       if (date < IBPP::MinDate || date > IBPP::MaxDate)\r
+               return false;\r
+\r
+       // The "Rata Die" is the date specified as the number of days elapsed since\r
+       // 31 Dec of year 0. So 1 Jan 0001 is 1.\r
+\r
+       RataDie = date + ibpp_internals::consts::Dec31_1899;    // Because IBPP sets the '0' on 31 Dec 1899.\r
+\r
+    Z = RataDie + 306;\r
+    H = 100*Z - 25;\r
+    A = H/3652425;\r
+    B = A - A/4;\r
+    year = (100*B + H) / 36525;\r
+    C = B + Z - 365*year - year / 4;\r
+    month = (5*C + 456) / 153;\r
+    day = C - (153*month - 457) / 5;\r
+    if (month > 12) { year += 1; month -= 12; }\r
+\r
+       if (y != 0) *y = (int)year;\r
+       if (m != 0) *m = (int)month;\r
+       if (d != 0) *d = (int)day;\r
+\r
+       return true;\r
+}\r
+\r
+//     Take a date from its components year, month, day and convert it to the\r
+//     integer representation used internally in IBPP.\r
+\r
+bool IBPP::itod (int *pdate, int year, int month, int day)\r
+{\r
+    int RataDie, result;\r
+       int y, m, d;\r
+\r
+       d = day;        m = month;              y = year;\r
+    if (m < 3) { m += 12; y -= 1; }\r
+    RataDie = d + (153*m - 457) / 5 + 365*y + y/4 - y/100 + y/400 - 306;\r
+\r
+       result = RataDie - ibpp_internals::consts::Dec31_1899;   // Because IBPP sets the '0' on 31 Dec 1899\r
+\r
+       // Validity control\r
+       if (result < IBPP::MinDate || result > IBPP::MaxDate)\r
+               return false;\r
+\r
+       *pdate = result;\r
+       return true;\r
+}\r
+\r
+//     Eof\r
diff --git a/stglibs/ibpp.lib/dbkey.cpp b/stglibs/ibpp.lib/dbkey.cpp
new file mode 100644 (file)
index 0000000..080b4d7
--- /dev/null
@@ -0,0 +1,120 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: dbkey.cpp,v 1.1 2007/05/05 17:00:42 faust Exp $\r
+//     Subject : IBPP, DBKey class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <iostream>\r
+#include <sstream>\r
+#include <iomanip>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     Private implementation\r
+\r
+//     Public implementation\r
+\r
+void IBPP::DBKey::Clear()\r
+{\r
+       mDBKey.erase();\r
+       mString.erase();\r
+}\r
+\r
+void IBPP::DBKey::SetKey(const void* key, int size)\r
+{\r
+       if (key == 0)\r
+               throw LogicExceptionImpl("IBPP::DBKey::SetKey", _("Null DBKey reference detected."));\r
+       if (size <= 0 || ((size >> 3) << 3) != size)\r
+               throw LogicExceptionImpl("IBPP::DBKey::SetKey", _("Invalid DBKey size."));\r
+\r
+       mDBKey.assign((const char*)key, (size_t)size);\r
+       mString.erase();\r
+}\r
+\r
+void IBPP::DBKey::GetKey(void* key, int size) const\r
+{\r
+       if (mDBKey.empty())\r
+               throw LogicExceptionImpl("IBPP::DBKey::GetKey", _("DBKey not assigned."));\r
+       if (key == 0)\r
+               throw LogicExceptionImpl("IBPP::DBKey::GetKey", _("Null DBKey reference detected."));\r
+       if (size != (int)mDBKey.size())\r
+               throw LogicExceptionImpl("IBPP::DBKey::GetKey", _("Incompatible DBKey size detected."));\r
+\r
+       mDBKey.copy((char*)key, mDBKey.size());\r
+}\r
+\r
+const char* IBPP::DBKey::AsString() const\r
+{\r
+       if (mDBKey.empty())\r
+               throw LogicExceptionImpl("IBPP::DBKey::GetString", _("DBKey not assigned."));\r
+\r
+       if (mString.empty())\r
+       {\r
+               std::ostringstream hexkey;\r
+               hexkey.setf(std::ios::hex, std::ios::basefield);\r
+               hexkey.setf(std::ios::uppercase);\r
+\r
+               const uint32_t* key = reinterpret_cast<const uint32_t*>(mDBKey.data());\r
+               int n = (int)mDBKey.size() / 8;\r
+               for (int i = 0; i < n; i++)\r
+               {\r
+                       if (i != 0) hexkey<< "-";\r
+                       hexkey<< std::setw(4)<< key[i*2]<< ":";\r
+                       hexkey<< std::setw(8)<< key[i*2+1];\r
+               }\r
+\r
+               mString = hexkey.str();\r
+       }\r
+\r
+       return mString.c_str();\r
+}\r
+\r
+IBPP::DBKey::DBKey(const DBKey& copied)\r
+{\r
+       mDBKey = copied.mDBKey;\r
+       mString = copied.mString;\r
+}\r
+\r
+IBPP::DBKey& IBPP::DBKey::operator=(const IBPP::DBKey& assigned)\r
+{\r
+       mDBKey = assigned.mDBKey;\r
+       mString = assigned.mString;\r
+       return *this;\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/deps b/stglibs/ibpp.lib/deps
new file mode 100644 (file)
index 0000000..a15bf18
--- /dev/null
@@ -0,0 +1,76 @@
+array.o: array.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+blob.o: blob.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+database.o: database.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+date.o: date.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+dbkey.o: dbkey.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+_dpb.o: _dpb.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+events.o: events.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+exception.o: exception.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+_ibpp.o: _ibpp.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+_ibs.o: _ibs.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+_rb.o: _rb.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+row.o: row.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+service.o: service.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+_spb.o: _spb.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+statement.o: statement.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+time.o: time.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+_tpb.o: _tpb.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+transaction.o: transaction.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
+user.o: user.cpp _ibpp.h ibpp.h \
+ /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include/os_int.h \
+ ibase.h iberror.h Makefile ../../Makefile.conf
+       $(CC) -g3 -W -Wall -I/usr/local/include -DARCH_LE -fPIC -DIBPP_LINUX -I /mnt/tank/home/Projects/STG/stg-2.5/projects/stargazer/../../include -I ./ -DDEBUG -DLINUX -DSTG_TIME -c $<
diff --git a/stglibs/ibpp.lib/events.cpp b/stglibs/ibpp.lib/events.cpp
new file mode 100644 (file)
index 0000000..14ce1ba
--- /dev/null
@@ -0,0 +1,372 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: events.cpp,v 1.1 2007/05/05 17:00:42 faust Exp $\r
+//     Subject : IBPP, internal EventsImpl class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+//     SPECIAL WARNING COMMENT (by Olivier Mascia, 2000 Nov 12)\r
+//     The way this source file handles events is not publicly documented, in\r
+//     the ibase.h header file or in the IB 6.0 documentation. This documentation\r
+//     suggests to use the API isc_event_block to construct vectors of events.\r
+//     Unfortunately, this API takes a variable number of parameters to specify\r
+//     the list of event names. In addition, the documentation warn on not using\r
+//     more than 15 names. This is a sad limitation, partly because the maximum\r
+//     number of parameters safely processed in such an API is very compiler\r
+//     dependant and also because isc_event_counts() is designed to return counts\r
+//     through the IB status vector which is a vector of 20 32-bits integers !\r
+//     From reverse engineering of the isc_event_block() API in\r
+//     source file jrd/alt.c (as available on fourceforge.net/project/InterBase as\r
+//     of 2000 Nov 12), it looks like the internal format of those EPB is simple.\r
+//     An EPB starts by a byte with value 1. A version identifier of some sort.\r
+//     Then a small cluster is used for each event name. The cluster starts with\r
+//     a byte for the length of the event name (no final '\0'). Followed by the N\r
+//     characters of the name itself (no final '\0'). The cluster ends with 4 bytes\r
+//     preset to 0.\r
+//\r
+//     SPECIAL CREDIT (July 2004) : this is a complete re-implementation of this\r
+//     class, directly based on work by Val Samko.\r
+//     The whole event handling has then be completely redesigned, based on the old\r
+//     EPB class to bring up the current IBPP::Events implementation.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+using namespace ibpp_internals;\r
+\r
+const size_t EventsImpl::MAXEVENTNAMELEN = 127;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void EventsImpl::Add(const std::string& eventname, IBPP::EventInterface* objref)\r
+{\r
+       if (eventname.size() == 0)\r
+               throw LogicExceptionImpl("Events::Add", _("Zero length event names not permitted"));\r
+       if (eventname.size() > MAXEVENTNAMELEN)\r
+               throw LogicExceptionImpl("Events::Add", _("Event name is too long"));\r
+       if ((mEventBuffer.size() + eventname.length() + 5) > 32766)     // max signed 16 bits integer minus one\r
+               throw LogicExceptionImpl("Events::Add",\r
+                       _("Can't add this event, the events list would overflow IB/FB limitation"));\r
+\r
+       Cancel();\r
+\r
+       // 1) Alloc or grow the buffers\r
+       size_t prev_buffer_size = mEventBuffer.size();\r
+       size_t needed = ((prev_buffer_size==0) ? 1 : 0) + eventname.length() + 5;\r
+       // Initial alloc will require one more byte, we need 4 more bytes for\r
+       // the count itself, and one byte for the string length prefix\r
+\r
+       mEventBuffer.resize(mEventBuffer.size() + needed);\r
+       mResultsBuffer.resize(mResultsBuffer.size() + needed);\r
+       if (prev_buffer_size == 0)\r
+               mEventBuffer[0] = mResultsBuffer[0] = 1; // First byte is a 'one'. Documentation ??\r
+\r
+       // 2) Update the buffers (append)\r
+       {\r
+               Buffer::iterator it = mEventBuffer.begin() +\r
+                               ((prev_buffer_size==0) ? 1 : prev_buffer_size); // Byte after current content\r
+               *(it++) = static_cast<char>(eventname.length());\r
+               it = std::copy(eventname.begin(), eventname.end(), it);\r
+               // We initialize the counts to (uint32_t)(-1) to initialize properly, see FireActions()\r
+               *(it++) = -1; *(it++) = -1; *(it++) = -1; *it = -1;\r
+       }\r
+\r
+       // copying new event to the results buffer to keep event_buffer_ and results_buffer_ consistant,\r
+       // otherwise we might get a problem in `FireActions`\r
+       // Val Samko, val@digiways.com\r
+       std::copy(mEventBuffer.begin() + prev_buffer_size,\r
+               mEventBuffer.end(), mResultsBuffer.begin() + prev_buffer_size);\r
+\r
+       // 3) Alloc or grow the objref array and update the objref array (append)\r
+       mObjectReferences.push_back(objref);\r
+\r
+       Queue();\r
+}\r
+\r
+void EventsImpl::Drop(const std::string& eventname)\r
+{\r
+       if (eventname.size() == 0)\r
+               throw LogicExceptionImpl("EventsImpl::Drop", _("Zero length event names not permitted"));\r
+       if (eventname.size() > MAXEVENTNAMELEN)\r
+               throw LogicExceptionImpl("EventsImpl::Drop", _("Event name is too long"));\r
+\r
+       if (mEventBuffer.size() <= 1) return;   // Nothing to do, but not an error\r
+\r
+       Cancel();\r
+\r
+       // 1) Find the event in the buffers\r
+       typedef EventBufferIterator<Buffer::iterator> EventIterator;\r
+       EventIterator eit(mEventBuffer.begin()+1);\r
+       EventIterator rit(mResultsBuffer.begin()+1);\r
+\r
+       for (ObjRefs::iterator oit = mObjectReferences.begin();\r
+                       oit != mObjectReferences.end();\r
+                               ++oit, ++eit, ++rit)\r
+       {\r
+               if (eventname != eit.get_name()) continue;\r
+               \r
+               // 2) Event found, remove it\r
+               mEventBuffer.erase(eit.begin(), eit.end());\r
+               mResultsBuffer.erase(rit.begin(), rit.end());\r
+               mObjectReferences.erase(oit);\r
+               break;\r
+       }\r
+\r
+       Queue();\r
+}\r
+\r
+void EventsImpl::List(std::vector<std::string>& events)\r
+{\r
+       events.clear();\r
+       \r
+       if (mEventBuffer.size() <= 1) return;   // Nothing to do, but not an error\r
+\r
+       typedef EventBufferIterator<Buffer::iterator> EventIterator;\r
+       EventIterator eit(mEventBuffer.begin()+1);\r
+\r
+       for (ObjRefs::iterator oit = mObjectReferences.begin();\r
+                       oit != mObjectReferences.end();\r
+                               ++oit, ++eit)\r
+       {\r
+               events.push_back(eit.get_name());\r
+       }\r
+}\r
+\r
+void EventsImpl::Clear()\r
+{\r
+       Cancel();\r
+       \r
+       mObjectReferences.clear();\r
+       mEventBuffer.clear();\r
+       mResultsBuffer.clear();\r
+}\r
+\r
+void EventsImpl::Dispatch()\r
+{\r
+       // If no events registered, nothing to do of course.\r
+       if (mEventBuffer.size() == 0) return;\r
+\r
+       // Let's fire the events actions for all the events which triggered, if any, and requeue.\r
+       FireActions();\r
+       Queue();\r
+}\r
+\r
+IBPP::Database EventsImpl::DatabasePtr() const\r
+{\r
+       if (mDatabase == 0) throw LogicExceptionImpl("Events::DatabasePtr",\r
+                       _("No Database is attached."));\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::IEvents* EventsImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void EventsImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void EventsImpl::Queue()\r
+{\r
+       if (! mQueued)\r
+       {\r
+               if (mDatabase->GetHandle() == 0)\r
+                       throw LogicExceptionImpl("EventsImpl::Queue",\r
+                                 _("Database is not connected"));\r
+\r
+               IBS vector;\r
+               mTrapped = false;\r
+               mQueued = true;\r
+               (*gds.Call()->m_que_events)(vector.Self(), mDatabase->GetHandlePtr(), &mId,\r
+                       short(mEventBuffer.size()), &mEventBuffer[0],\r
+                               (isc_callback)EventHandler, (char*)this);\r
+\r
+               if (vector.Errors())\r
+               {\r
+                       mId = 0;        // Should be, but better be safe\r
+                       mQueued = false;\r
+                       throw SQLExceptionImpl(vector, "EventsImpl::Queue",\r
+                               _("isc_que_events failed"));\r
+               }\r
+       }\r
+}\r
+\r
+void EventsImpl::Cancel()\r
+{\r
+       if (mQueued)\r
+       {\r
+               if (mDatabase->GetHandle() == 0) throw LogicExceptionImpl("EventsImpl::Cancel",\r
+                       _("Database is not connected"));\r
+\r
+               IBS vector;\r
+\r
+               // A call to cancel_events will call *once* the handler routine, even\r
+               // though no events had fired. This is why we first set mEventsQueued\r
+               // to false, so that we can be sure to dismiss those unwanted callbacks\r
+               // subsequent to the execution of isc_cancel_events().\r
+               mTrapped = false;\r
+               mQueued = false;\r
+               (*gds.Call()->m_cancel_events)(vector.Self(), mDatabase->GetHandlePtr(), &mId);\r
+\r
+           if (vector.Errors())\r
+               {\r
+                       mQueued = true; // Need to restore this as cancel failed\r
+               throw SQLExceptionImpl(vector, "EventsImpl::Cancel",\r
+                       _("isc_cancel_events failed"));\r
+               }\r
+\r
+               mId = 0;        // Should be, but better be safe\r
+       }\r
+}\r
+\r
+void EventsImpl::FireActions()\r
+{\r
+       if (mTrapped)\r
+       {\r
+               typedef EventBufferIterator<Buffer::iterator> EventIterator;\r
+               EventIterator eit(mEventBuffer.begin()+1);\r
+               EventIterator rit(mResultsBuffer.begin()+1);\r
+\r
+               for (ObjRefs::iterator oit = mObjectReferences.begin();\r
+                        oit != mObjectReferences.end();\r
+                                ++oit, ++eit, ++rit)\r
+               {\r
+                       if (eit == EventIterator(mEventBuffer.end())\r
+                                 || rit == EventIterator(mResultsBuffer.end()))\r
+                               throw LogicExceptionImpl("EventsImpl::FireActions", _("Internal buffer size error"));\r
+                       uint32_t vnew = rit.get_count();\r
+                       uint32_t vold = eit.get_count();\r
+                       if (vnew > vold)\r
+                       {\r
+                               // Fire the action\r
+                               try\r
+                               {\r
+                                       (*oit)->ibppEventHandler(this, eit.get_name(), (int)(vnew - vold));\r
+                               }\r
+                               catch (...)\r
+                               {\r
+                                       std::copy(rit.begin(), rit.end(), eit.begin());\r
+                                       throw;\r
+                               }\r
+                               std::copy(rit.begin(), rit.end(), eit.begin());\r
+                       }\r
+                       // This handles initialization too, where vold == (uint32_t)(-1)\r
+                       // Thanks to M. Hieke for this idea and related initialization to (-1)\r
+                       if (vnew != vold)\r
+                               std::copy(rit.begin(), rit.end(), eit.begin());\r
+               }\r
+       }\r
+}\r
+\r
+// This function must keep this prototype to stay compatible with\r
+// what isc_que_events() expects\r
+\r
+void EventsImpl::EventHandler(const char* object, short size, const char* tmpbuffer)\r
+{\r
+       // >>>>> This method is a STATIC member !! <<<<<\r
+       // Consider this method as a kind of "interrupt handler". It should do as\r
+       // few work as possible as quickly as possible and then return.\r
+       // Never forget: this is called by the Firebird client code, on *some*\r
+       // thread which might not be (and won't probably be) any of your application\r
+       // thread. This function is to be considered as an "interrupt-handler" of a\r
+       // hardware driver.\r
+\r
+       // There can be spurious calls to EventHandler from FB internal. We must\r
+       // dismiss those calls.\r
+       if (object == 0 || size == 0 || tmpbuffer == 0) return;\r
+               \r
+       EventsImpl* evi = (EventsImpl*)object;  // Ugly, but wanted, c-style cast\r
+\r
+       if (evi->mQueued)\r
+       {\r
+               try\r
+               {\r
+                       char* rb = &evi->mResultsBuffer[0];\r
+                       if (evi->mEventBuffer.size() < (unsigned)size) size = (short)evi->mEventBuffer.size();\r
+                       for (int i = 0; i < size; i++)\r
+                               rb[i] = tmpbuffer[i];\r
+                       evi->mTrapped = true;\r
+                       evi->mQueued = false;\r
+               }\r
+               catch (...) { }\r
+       }\r
+}\r
+\r
+void EventsImpl::AttachDatabaseImpl(DatabaseImpl* database)\r
+{\r
+       if (database == 0) throw LogicExceptionImpl("EventsImpl::AttachDatabase",\r
+                       _("Can't attach a null Database object."));\r
+\r
+       if (mDatabase != 0) mDatabase->DetachEventsImpl(this);\r
+       mDatabase = database;\r
+       mDatabase->AttachEventsImpl(this);\r
+}\r
+\r
+void EventsImpl::DetachDatabaseImpl()\r
+{\r
+       if (mDatabase == 0) return;\r
+\r
+       mDatabase->DetachEventsImpl(this);\r
+       mDatabase = 0;\r
+}\r
+\r
+EventsImpl::EventsImpl(DatabaseImpl* database)\r
+       : mRefCount(0)\r
+{\r
+       mDatabase = 0;\r
+       mId = 0;\r
+       mQueued = mTrapped = false;\r
+       AttachDatabaseImpl(database);\r
+}\r
+\r
+EventsImpl::~EventsImpl()\r
+{\r
+       try { Clear(); }\r
+               catch (...) { }\r
+       \r
+       try { if (mDatabase != 0) mDatabase->DetachEventsImpl(this); }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/exception.cpp b/stglibs/ibpp.lib/exception.cpp
new file mode 100644 (file)
index 0000000..aa47e28
--- /dev/null
@@ -0,0 +1,351 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: exception.cpp,v 1.1 2007/05/05 17:00:42 faust Exp $\r
+//     Subject : IBPP, Initialization of the library\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+\r
+using namespace ibpp_internals;\r
+\r
+// None of the exception classes methods are implemented inline, because they\r
+// are all declared throw() and Borland compilers at least, but possibly some\r
+// others emit a warning like "W8026 - functions with exception specification\r
+// are not expanded inline". Nothing we have to worry about, but we don't want\r
+// people concerned by such warnings.\r
+\r
+IBPP::Exception::~Exception() throw()\r
+{\r
+}\r
+\r
+IBPP::LogicException::~LogicException() throw()\r
+{\r
+}\r
+\r
+IBPP::SQLException::~SQLException() throw()\r
+{\r
+}\r
+\r
+IBPP::WrongType::~WrongType() throw()\r
+{\r
+}\r
+\r
+//\r
+//     (((((((( ExceptionBase Implementation ))))))))\r
+//\r
+\r
+void ExceptionBase::buildErrorMessage(const char* message)\r
+{\r
+       if (! mContext.empty())\r
+               mWhat.append(_("Context: ")).append(mContext).append("\n");\r
+\r
+       if (message != 0 && *message != 0 )\r
+               mWhat.append(_("Message: ")).append(message).append("\n");\r
+       \r
+       mWhat.append("\n");\r
+}\r
+\r
+void ExceptionBase::raise(const std::string& context, const char* message, va_list argptr)\r
+{\r
+       mContext.assign(context);\r
+\r
+       if (message != 0)\r
+       {\r
+               char buffer[1024];\r
+#if defined(_MSC_VER) || defined(__DMC__)\r
+               _vsnprintf(buffer, sizeof(buffer)-1, message, argptr);\r
+#else\r
+               vsnprintf(buffer, sizeof(buffer)-1, message, argptr);\r
+#endif\r
+               buffer[sizeof(buffer)-1] = 0;\r
+       \r
+               buildErrorMessage(buffer);\r
+       }\r
+       else\r
+               buildErrorMessage(0);\r
+}\r
+\r
+ExceptionBase::ExceptionBase() throw()\r
+{\r
+}\r
+\r
+ExceptionBase::ExceptionBase(const ExceptionBase& copied) throw()\r
+{\r
+       mContext = copied.mContext;\r
+       mWhat = copied.mWhat;\r
+}\r
+\r
+ExceptionBase& ExceptionBase::operator=(const ExceptionBase& copied) throw()\r
+{\r
+       mContext = copied.mContext;\r
+       mWhat = copied.mWhat;\r
+       return *this;\r
+}\r
+\r
+ExceptionBase::ExceptionBase(const std::string& context,\r
+                                                               const char* message, ...) throw()\r
+{\r
+       va_list argptr;\r
+       va_start(argptr, message);\r
+       mWhat.assign("*** IBPP::Exception ***\n");\r
+       raise(context, message, argptr);\r
+       va_end(argptr);\r
+}\r
+\r
+ExceptionBase::~ExceptionBase() throw()\r
+{\r
+}\r
+\r
+const char* ExceptionBase::Origin() const throw()\r
+{\r
+       return mContext.c_str();\r
+}\r
+\r
+const char* ExceptionBase::ErrorMessage() const throw()\r
+{\r
+       return mWhat.c_str();\r
+}\r
+\r
+const char* ExceptionBase::what() const throw()\r
+{\r
+       return mWhat.c_str();\r
+}\r
+\r
+//     (((((((( LogicExceptionImpl Implementation ))))))))\r
+\r
+// The following constructors are small and could be inlined, but for object\r
+// code compacity of the library it is much better to have them non-inlined.\r
+// The amount of code generated by compilers for a throw is well-enough.\r
+\r
+LogicExceptionImpl::LogicExceptionImpl() throw()\r
+       : ExceptionBase()\r
+{\r
+}\r
+\r
+LogicExceptionImpl::LogicExceptionImpl(const LogicExceptionImpl& copied) throw()\r
+       : IBPP::LogicException(), ExceptionBase(copied)\r
+{\r
+}\r
+\r
+LogicExceptionImpl& LogicExceptionImpl::operator=(const LogicExceptionImpl& copied) throw()\r
+{\r
+       ExceptionBase::operator=(copied);\r
+       return *this;\r
+}\r
+\r
+LogicExceptionImpl::LogicExceptionImpl(const std::string& context,\r
+                                                                               const char* message, ...) throw()\r
+{\r
+       va_list argptr;\r
+       va_start(argptr, message);\r
+       mWhat.assign("*** IBPP::LogicException ***\n");\r
+       raise(context, message, argptr);\r
+       va_end(argptr);\r
+}\r
+\r
+LogicExceptionImpl::~LogicExceptionImpl() throw ()\r
+{\r
+}\r
+\r
+const char* LogicExceptionImpl::Origin() const throw()\r
+{\r
+       return ExceptionBase::Origin();\r
+}\r
+\r
+const char* LogicExceptionImpl::ErrorMessage() const throw()\r
+{\r
+       return ExceptionBase::what();\r
+}\r
+\r
+const char* LogicExceptionImpl::what() const throw()\r
+{\r
+       return ExceptionBase::what();\r
+}\r
+\r
+//     (((((((( SQLExceptionImpl Implementation ))))))))\r
+\r
+SQLExceptionImpl::SQLExceptionImpl() throw()\r
+       : ExceptionBase(), mSqlCode(0), mEngineCode(0)\r
+{\r
+}\r
+\r
+SQLExceptionImpl::SQLExceptionImpl(const SQLExceptionImpl& copied) throw()\r
+       : IBPP::SQLException(), ExceptionBase(copied), mSqlCode(copied.mSqlCode),\r
+               mEngineCode(copied.mEngineCode)\r
+{\r
+}\r
+\r
+SQLExceptionImpl& SQLExceptionImpl::operator=(const SQLExceptionImpl& copied) throw()\r
+{\r
+       ExceptionBase::operator=(copied);\r
+       mSqlCode = copied.mSqlCode;\r
+       mEngineCode = copied.mEngineCode;\r
+       return *this;\r
+}\r
+\r
+SQLExceptionImpl::SQLExceptionImpl(const IBS& status, const std::string& context,\r
+                                                                       const char* message, ...) throw()\r
+{\r
+       va_list argptr;\r
+       va_start(argptr, message);\r
+       mWhat.assign("*** IBPP::SQLException ***\n");\r
+       raise(context, message, argptr);\r
+       va_end(argptr);\r
+       mSqlCode = status.SqlCode();\r
+       mEngineCode = status.EngineCode();\r
+       mWhat.append(status.ErrorMessage());\r
+}\r
+\r
+SQLExceptionImpl::~SQLExceptionImpl() throw ()\r
+{\r
+}\r
+\r
+const char* SQLExceptionImpl::Origin() const throw()\r
+{\r
+       return ExceptionBase::Origin();\r
+}\r
+\r
+const char* SQLExceptionImpl::ErrorMessage() const throw()\r
+{\r
+       return ExceptionBase::what();\r
+}\r
+\r
+const char* SQLExceptionImpl::what() const throw()\r
+{\r
+       return ExceptionBase::what();\r
+}\r
+\r
+int SQLExceptionImpl::SqlCode() const throw()\r
+{\r
+       return mSqlCode;\r
+}\r
+\r
+int SQLExceptionImpl::EngineCode() const throw()\r
+{\r
+       return mEngineCode;\r
+}\r
+\r
+//     (((((((( WrongTypeImpl Implementation ))))))))\r
+\r
+// The following constructors are small and could be inlined, but for object\r
+// code compacity of the library it is much better to have them non-inlined.\r
+// The amount of code generated by compilers for a throw is well-enough.\r
+\r
+WrongTypeImpl::WrongTypeImpl() throw()\r
+       : IBPP::WrongType(), ExceptionBase()\r
+{\r
+}\r
+\r
+WrongTypeImpl::WrongTypeImpl(const WrongTypeImpl& copied) throw()\r
+       : IBPP::WrongType(), ExceptionBase(copied)\r
+{\r
+}\r
+\r
+WrongTypeImpl& WrongTypeImpl::operator=(const WrongTypeImpl& copied) throw()\r
+{\r
+       ExceptionBase::operator=(copied);\r
+       return *this;\r
+}\r
+\r
+WrongTypeImpl::WrongTypeImpl(const std::string& context, int sqlType, IITYPE varType,\r
+                               const char* message, ...) throw()\r
+{\r
+       va_list argptr;\r
+       va_start(argptr, message);\r
+       mWhat.assign("*** IBPP::WrongType ***\n");\r
+       raise(context, message, argptr);\r
+       va_end(argptr);\r
+\r
+       std::string info;\r
+       switch (sqlType & ~1)\r
+       {\r
+               case SQL_TEXT :                 info.append("CHAR"); break;\r
+               case SQL_VARYING :              info.append("VARCHAR"); break;\r
+               case SQL_SHORT :                info.append("SMALLINT"); break;\r
+               case SQL_LONG :                 info.append("INTEGER"); break;\r
+               case SQL_INT64 :                info.append("BIGINT"); break;\r
+               case SQL_FLOAT :                info.append("FLOAT"); break;\r
+               case SQL_DOUBLE :               info.append("DOUBLE"); break;\r
+               case SQL_TIMESTAMP :    info.append("TIMESTAMP"); break;\r
+               case SQL_TYPE_DATE :    info.append("DATE"); break;\r
+               case SQL_TYPE_TIME :    info.append("TIME"); break;\r
+               case SQL_BLOB :                 info.append("BLOB"); break;\r
+               case SQL_ARRAY :                info.append("ARRAY"); break;\r
+       }\r
+       info.append(" ").append(_(" and ")).append(" ");\r
+       switch (varType)\r
+       {\r
+               case ivArray :          info.append("Array"); break;\r
+               case ivBlob :           info.append("Blob"); break;\r
+               case ivDate :           info.append("Date"); break;\r
+               case ivTime :           info.append("Time"); break;\r
+               case ivTimestamp :      info.append("Timestamp"); break;\r
+               case ivString :         info.append("std::string"); break;\r
+               case ivInt16 :          info.append("int16_t"); break;\r
+               case ivInt32 :          info.append("int32_t"); break;\r
+               case ivInt64 :          info.append("int64_t"); break;\r
+               case ivFloat :          info.append("float"); break;\r
+               case ivDouble :         info.append("double"); break;\r
+               case ivBool :           info.append("bool"); break;\r
+               case ivDBKey :          info.append("DBKey"); break;\r
+               case ivByte :           info.append("int8_t"); break;\r
+       }\r
+       mWhat.append(info).append("\n");\r
+}\r
+\r
+WrongTypeImpl::~WrongTypeImpl() throw ()\r
+{\r
+}\r
+\r
+const char* WrongTypeImpl::Origin() const throw()\r
+{\r
+       return ExceptionBase::Origin();\r
+}\r
+\r
+const char* WrongTypeImpl::ErrorMessage() const throw()\r
+{\r
+       return ExceptionBase::what();\r
+}\r
+\r
+const char* WrongTypeImpl::what() const throw()\r
+{\r
+       return ExceptionBase::what();\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/ibase.h b/stglibs/ibpp.lib/ibase.h
new file mode 100644 (file)
index 0000000..c108aac
--- /dev/null
@@ -0,0 +1,2851 @@
+/*\r
+ *     MODULE:         ibase.h\r
+ *     DESCRIPTION:    OSRI entrypoints and defines\r
+ *\r
+ * The contents of this file are subject to the Interbase Public\r
+ * License Version 1.0 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy\r
+ * of the License at http://www.Inprise.com/IPL.html\r
+ *\r
+ * Software distributed under the License is distributed on an\r
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express\r
+ * or implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code was created by Inprise Corporation\r
+ * and its predecessors. Portions created by Inprise Corporation are\r
+ * Copyright (C) Inprise Corporation.\r
+ *\r
+ * All Rights Reserved.\r
+ * Contributor(s): ______________________________________.\r
+ * Added TCP_NO_DELAY option for superserver on Linux\r
+ * FSG 16.03.2001\r
+ * 2001.07.28: John Bellardo:  Added blr_skip\r
+ * 2001.09.18: Ann Harrison:   New info codes\r
+ * 17-Oct-2001 Mike Nordell: CPU affinity\r
+ * 2001-04-16 Paul Beach: ISC_TIME_SECONDS_PRECISION_SCALE modified for HP10\r
+ * Compiler Compatibility\r
+ * 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete ports:\r
+ *                          - EPSON, XENIX, MAC (MAC_AUX), Cray and OS/2\r
+ * 2002.10.29 Nickolay Samofatov: Added support for savepoints\r
+ *\r
+ * 2002.10.29 Sean Leyne - Removed support for obsolete IPX/SPX Protocol\r
+ *\r
+ */\r
+/*\r
+$Id: ibase.h,v 1.2 2007/05/17 08:39:25 faust Exp $\r
+ */\r
+\r
+#ifndef JRD_IBASE_H\r
+#define JRD_IBASE_H\r
+\r
+\r
+/*\r
+ *\r
+ *  The contents of this file are subject to the Mozilla Public\r
+ *  License Version 1.1 (the "License"); you may not use this file\r
+ *  except in compliance with the License. You may obtain a copy of\r
+ *  the License at http://www.mozilla.org/MPL/\r
+ *  Alternatively, the contents of this file may be used under the\r
+ *  terms of the GNU General Public License Version 2 or later (the\r
+ *  "GPL"), in which case the provisions of the GPL are applicable\r
+ *  instead of those above. You may obtain a copy of the Licence at\r
+ *  http://www.gnu.org/copyleft/gpl.html\r
+ *\r
+ *  This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *    Relevant for more details.\r
+ *\r
+ *    This file was created by members of the firebird development team.\r
+ *    All individual contributions remain the Copyright (C) of those\r
+ *    individuals.  Contributors to this file are either listed here or\r
+ *    can be obtained from a CVS history command.\r
+ *\r
+ *   All rights reserved.\r
+ *\r
+ *   Contributor(s):\r
+ *       Mike Nordel <tamlin@algonet.se>\r
+ *       Mark O'Donohue <mark.odonohue@ludwig.edu.au>\r
+ *\r
+ *\r
+ *  $Id: ibase.h,v 1.2 2007/05/17 08:39:25 faust Exp $\r
+ *\r
+ * 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "OS/2" port\r
+ *\r
+ */\r
+\r
+\r
+#ifndef INCLUDE_FB_TYPES_H\r
+#define INCLUDE_FB_TYPES_H\r
+\r
+\r
+/******************************************************************/\r
+/* Define type, export and other stuff based on c/c++ and Windows */\r
+/******************************************************************/\r
+\r
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)\r
+#ifndef __GNUC__\r
+typedef __int64                                ISC_INT64;\r
+typedef unsigned __int64       ISC_UINT64;\r
+#define  ISC_INT64_DEFINED\r
+#endif\r
+#define  ISC_EXPORT    __stdcall\r
+#define  ISC_EXPORT_VARARG     __cdecl\r
+#else\r
+#define  ISC_EXPORT\r
+#define  ISC_EXPORT_VARARG\r
+#endif\r
+\r
+/*******************************************************************/\r
+/* 64 bit Integers                                                 */\r
+/*******************************************************************/\r
+\r
+#ifdef  ISC_INT64_DEFINED\r
+#undef  ISC_INT64_DEFINED\r
+#else\r
+typedef long long int                  ISC_INT64;\r
+typedef unsigned long long int ISC_UINT64;\r
+#endif\r
+\r
+// Nickolay: it is easier to assume that integer is at least 32-bit.\r
+// This comes from limitation that we cannot reliably detect datatype size at\r
+// compile time in cases when we do not control compilation (public headers) \r
+// We are not going to support 16-bit platforms, right?\r
+//\r
+// Temporarly restrict new definition until ULONG clash with Windows\r
+// type is solved. Win64 port is not possible before that point.\r
+// Cannot use SIZEOF_LONG define here because we are in a public header\r
+#if defined(_LP64) || defined(__LP64__) || defined(__arch64__)\r
+       /* EKU: Firebird requires (S)LONG to be 32 bit */\r
+#   define LONG_DEFINED\r
+    typedef int SLONG;\r
+    typedef unsigned int ULONG;\r
+#endif /* SIZEOF_LONG == 8 */\r
+\r
+\r
+\r
+/* Basic data types */\r
+\r
+\r
+#ifdef NOT_USED_OR_REPLACED\r
+typedef signed char SCHAR;\r
+#else\r
+/* TMN: TODO It seems SCHAR is used just about *everywhere* where a plain\r
+ * "char" is really intended. This currently forces us to this bad definition.\r
+ */\r
+typedef char SCHAR;\r
+#endif\r
+\r
+\r
+typedef unsigned char UCHAR;\r
+typedef short SSHORT;\r
+typedef unsigned short USHORT;\r
+\r
+\r
+#ifndef LONG_DEFINED                   /* 32 bit */\r
+typedef long SLONG;\r
+typedef unsigned long ULONG;\r
+#else\r
+#undef LONG_DEFINED\r
+#endif\r
+\r
+\r
+#ifndef SQUAD_DEFINED                  /* 64 bit */\r
+typedef struct {\r
+       SLONG high;\r
+       ULONG low;\r
+} SQUAD;\r
+#endif\r
+\r
+\r
+#ifndef DEFINED_GDS_QUAD\r
+#define DEFINED_GDS_QUAD\r
+struct GDS_QUAD_t {\r
+       SLONG gds_quad_high;\r
+       ULONG gds_quad_low;\r
+};\r
+\r
+typedef struct GDS_QUAD_t GDS_QUAD;\r
+\r
+#endif /* DEFINED_GDS_QUAD */\r
+\r
+//\r
+// TMN: some misc data types from all over the place\r
+//\r
+struct vary\r
+{\r
+       USHORT vary_length;\r
+       char   vary_string[1];\r
+};\r
+// TMN: Currently we can't do this, since remote uses a different\r
+// definition of VARY than the rest of the code! :-<\r
+//typedef vary* VARY;\r
+\r
+struct lstring\r
+{\r
+       ULONG   lstr_length;\r
+       ULONG   lstr_allocated;\r
+       UCHAR*  lstr_address;\r
+};\r
+typedef struct lstring LSTRING;\r
+\r
+\r
+typedef unsigned char BOOLEAN;\r
+typedef char TEXT;                             // To be expunged over time\r
+//typedef unsigned char STEXT; Signed text - not used\r
+//typedef unsigned char UTEXT; Unsigned text - not used\r
+typedef unsigned char BYTE;            // Unsigned byte - common\r
+//typedef char SBYTE;                  Signed byte - not used\r
+typedef long ISC_STATUS;\r
+typedef long IPTR;\r
+typedef unsigned long U_IPTR;\r
+typedef void (*FPTR_VOID) ();\r
+typedef void (*FPTR_VOID_PTR) (void *);\r
+typedef int (*FPTR_INT) ();\r
+typedef int (*FPTR_INT_VOID_PTR) (void *);\r
+typedef ULONG RCRD_OFFSET;\r
+typedef USHORT FLD_LENGTH;\r
+typedef int (*lock_ast_t)(void *);\r
+\r
+typedef IPTR FB_THREAD_ID;\r
+\r
+#define ISC_STATUS_LENGTH      20\r
+typedef ISC_STATUS ISC_STATUS_ARRAY[ISC_STATUS_LENGTH];\r
+\r
+/* Number of elements in an arry */\r
+#define FB_NELEM(x)    ((int)(sizeof(x) / sizeof(x[0])))\r
+#define FB_ALIGN(n,b) ((n+b-1)&~(b-1))\r
+\r
+#endif /* INCLUDE_FB_TYPES_H */\r
+\r
+#define FB_API_VER 15\r
+#define isc_version4\r
+\r
+#define  ISC_TRUE      1\r
+#define  ISC_FALSE     0\r
+#if !(defined __cplusplus)\r
+#define  ISC__TRUE     ISC_TRUE\r
+#define  ISC__FALSE    ISC_FALSE\r
+#endif\r
+\r
+#define ISC_FAR\r
+\r
+// It is difficult to detect 64-bit long from the redistributable header\r
+// we do not care of 16-bit platforms anymore thus we may use plain "int"\r
+// which is 32-bit on all platforms we support\r
+#if defined(_LP64) || defined(__LP64__) || defined(__arch64__)\r
+typedef        int             ISC_LONG;\r
+typedef        unsigned int    ISC_ULONG;\r
+#else\r
+typedef        signed long     ISC_LONG;\r
+typedef        unsigned long   ISC_ULONG;\r
+#endif\r
+\r
+typedef        signed short    ISC_SHORT;\r
+typedef        unsigned short  ISC_USHORT;\r
+\r
+typedef        unsigned char   ISC_UCHAR;\r
+\r
+#define  DSQL_close     1\r
+#define  DSQL_drop      2\r
+\r
+\r
+/********************************/\r
+/* InterBase Handle Definitions */\r
+/********************************/\r
+\r
+#ifndef JRD_Y_REF_H\r
+#define FRBRD void\r
+#endif\r
+\r
+typedef FRBRD * isc_att_handle;\r
+typedef FRBRD * isc_blob_handle;\r
+typedef FRBRD * isc_db_handle;\r
+typedef FRBRD * isc_req_handle;\r
+typedef FRBRD * isc_stmt_handle;\r
+typedef FRBRD * isc_svc_handle;\r
+typedef FRBRD * isc_tr_handle;\r
+typedef void (* isc_callback) ();\r
+typedef ISC_LONG isc_resv_handle;\r
+\r
+/*******************************************************************/\r
+/* Time & Date Support                                             */\r
+/*******************************************************************/\r
+\r
+#ifndef ISC_TIMESTAMP_DEFINED\r
+typedef int                    ISC_DATE;\r
+typedef unsigned int   ISC_TIME;\r
+typedef struct\r
+{\r
+       ISC_DATE timestamp_date;\r
+       ISC_TIME timestamp_time;\r
+} ISC_TIMESTAMP;\r
+#define ISC_TIMESTAMP_DEFINED\r
+#endif /* ISC_TIMESTAMP_DEFINED */\r
+\r
+#define ISC_TIME_SECONDS_PRECISION          10000L\r
+#define ISC_TIME_SECONDS_PRECISION_SCALE    (-4)\r
+\r
+/*******************************************************************/\r
+/* Blob id structure                                               */\r
+/*******************************************************************/\r
+\r
+#if !(defined __cplusplus)\r
+typedef GDS_QUAD GDS__QUAD;\r
+#endif /* !(defined __cplusplus) */\r
+\r
+typedef struct GDS_QUAD_t ISC_QUAD;\r
+\r
+#define        isc_quad_high   gds_quad_high\r
+#define        isc_quad_low    gds_quad_low\r
+\r
+typedef struct\r
+{\r
+       short array_bound_lower;\r
+       short array_bound_upper;\r
+} ISC_ARRAY_BOUND;\r
+\r
+typedef struct\r
+{\r
+       unsigned char   array_desc_dtype;\r
+       char                    array_desc_scale;\r
+       unsigned short  array_desc_length;\r
+       char                    array_desc_field_name[32];\r
+       char                    array_desc_relation_name[32];\r
+       short                   array_desc_dimensions;\r
+       short                   array_desc_flags;\r
+       ISC_ARRAY_BOUND array_desc_bounds[16];\r
+} ISC_ARRAY_DESC;\r
+\r
+typedef struct\r
+{\r
+       short                   blob_desc_subtype;\r
+       short                   blob_desc_charset;\r
+       short                   blob_desc_segment_size;\r
+       unsigned char   blob_desc_field_name[32];\r
+       unsigned char   blob_desc_relation_name[32];\r
+} ISC_BLOB_DESC;\r
+\r
+\r
+\r
+/***************************/\r
+/* Blob control structure  */\r
+/***************************/\r
+\r
+typedef struct isc_blob_ctl\r
+{\r
+       ISC_STATUS      (* ctl_source)();       /* Source filter */\r
+       struct isc_blob_ctl *   ctl_source_handle;      /* Argument to pass to source filter */\r
+       short                                   ctl_to_sub_type;                /* Target type */\r
+       short                                   ctl_from_sub_type;              /* Source type */\r
+       unsigned short                  ctl_buffer_length;              /* Length of buffer */\r
+       unsigned short                  ctl_segment_length;             /* Length of current segment */\r
+       unsigned short                  ctl_bpb_length;                 /* Length of blob parameter  block */\r
+       char *                                  ctl_bpb;                                /* Address of blob parameter block */\r
+       unsigned char *                 ctl_buffer;                             /* Address of segment buffer */\r
+       ISC_LONG                                ctl_max_segment;                /* Length of longest segment */\r
+       ISC_LONG                                ctl_number_segments;    /* Total number of segments */\r
+       ISC_LONG                                ctl_total_length;               /* Total length of blob */\r
+       ISC_STATUS *                    ctl_status;                             /* Address of status vector */\r
+       long                                    ctl_data[8];                    /* Application specific data */\r
+} * ISC_BLOB_CTL;\r
+\r
+/***************************/\r
+/* Blob stream definitions */\r
+/***************************/\r
+\r
+typedef struct bstream\r
+{\r
+       isc_blob_handle bstr_blob;              /* Blob handle */\r
+       char *                  bstr_buffer;    /* Address of buffer */\r
+       char *                  bstr_ptr;               /* Next character */\r
+       short                   bstr_length;    /* Length of buffer */\r
+       short                   bstr_cnt;               /* Characters in buffer */\r
+       char                    bstr_mode;              /* (mode) ? OUTPUT : INPUT */\r
+} BSTREAM;\r
+\r
+/* Three ugly macros, one even using octal radix... sigh... */\r
+#define getb(p)        (--(p)->bstr_cnt >= 0 ? *(p)->bstr_ptr++ & 0377: BLOB_get (p))\r
+#define putb(x,p) (((x) == '\n' || (!(--(p)->bstr_cnt))) ? BLOB_put ((x),p) : ((int) (*(p)->bstr_ptr++ = (unsigned) (x))))\r
+#define putbx(x,p) ((!(--(p)->bstr_cnt)) ? BLOB_put ((x),p) : ((int) (*(p)->bstr_ptr++ = (unsigned) (x))))\r
+\r
+\r
+/********************************************************************/\r
+/* CVC: Public blob interface definition held in val.h.             */\r
+/* For some unknown reason, it was only documented in langRef       */\r
+/* and being the structure passed by the engine to UDFs it never    */\r
+/* made its way into this public definitions file.                  */\r
+/* Being its original name "blob", I renamed it blobcallback here.  */\r
+/* I did the full definition with the proper parameters instead of  */\r
+/* the weak C declaration with any number and type of parameters.   */\r
+/* Since the first parameter -BLB- is unknown outside the engine,   */\r
+/* it's more accurate to use void* than int* as the blob pointer    */\r
+/********************************************************************/\r
+\r
+#if !defined(JRD_VAL_H) && !defined(REQUESTER)\r
+/* Blob passing structure */\r
+\r
+enum lseek_mode {blb_seek_relative = 1, blb_seek_from_tail = 2};\r
+\r
+typedef struct blobcallback {\r
+    short ( *blob_get_segment)\r
+               (void * hnd, unsigned char* buffer, ISC_USHORT buf_size, ISC_USHORT* result_len);\r
+    void                       *blob_handle;\r
+    ISC_LONG   blob_number_segments;\r
+    ISC_LONG   blob_max_segment;\r
+    ISC_LONG   blob_total_length;\r
+    void ( *blob_put_segment)\r
+               (void * hnd, unsigned char* buffer, ISC_USHORT buf_size);\r
+    ISC_LONG ( *blob_lseek)\r
+               (void * hnd, ISC_USHORT mode, ISC_LONG offset);\r
+}  *BLOBCALLBACK;\r
+#endif /* !defined(JRD_VAL_H) && !defined(REQUESTER) */\r
+\r
+\r
+\r
+/********************************************************************/\r
+/* CVC: Public descriptor interface held in dsc.h.                  */\r
+/* We need it documented to be able to recognize NULL in UDFs.      */\r
+/* Being its original name "dsc", I renamed it paramdsc here.       */\r
+/* Notice that I adjust to the original definition: contrary to     */\r
+/* other cases, the typedef is the same struct not the pointer.     */\r
+/* I included the enumeration of dsc_dtype possible values.         */\r
+/* Ultimately, dsc.h should be part of the public interface.        */\r
+/********************************************************************/\r
+\r
+#if !defined(JRD_DSC_H)\r
+/* This is the famous internal descriptor that UDFs can use, too. */\r
+typedef struct paramdsc {\r
+    unsigned char      dsc_dtype;\r
+    signed char                dsc_scale;\r
+    ISC_USHORT         dsc_length;\r
+    short              dsc_sub_type;\r
+    ISC_USHORT         dsc_flags;\r
+    unsigned char      *dsc_address;\r
+} PARAMDSC;\r
+\r
+#if !defined(JRD_VAL_H)\r
+/* This is a helper struct to work with varchars. */\r
+typedef struct paramvary {\r
+    ISC_USHORT         vary_length;\r
+    unsigned char      vary_string [1];\r
+} PARAMVARY;\r
+#endif /* !defined(JRD_VAL_H) */\r
+\r
+/* values for dsc_flags */\r
+/* Note: DSC_null is only reliably set for local variables\r
+   (blr_variable) */\r
+#define DSC_null               1\r
+#define DSC_no_subtype         2       /* dsc has no sub type specified */\r
+#define DSC_nullable           4       /* not stored. instead, is derived\r
+                                       from metadata primarily to flag\r
+                                       SQLDA (in DSQL)               */\r
+\r
+/* Overload text typing information into the dsc_sub_type field.\r
+   See intl.h for definitions of text types */ \r
+\r
+#ifndef dsc_ttype\r
+#define dsc_ttype      dsc_sub_type\r
+#endif\r
+\r
+\r
+/* Note that dtype_null actually means that we do not yet know the\r
+   dtype for this descriptor.  A nice cleanup item would be to globally\r
+   change it to dtype_unknown.  --chrisj 1999-02-17 */\r
+\r
+#define dtype_null     0\r
+#define dtype_text     1\r
+#define dtype_cstring  2\r
+#define dtype_varying  3\r
+\r
+#define dtype_packed   6\r
+#define dtype_byte     7\r
+#define dtype_short    8\r
+#define dtype_long     9\r
+#define dtype_quad     10\r
+#define dtype_real     11\r
+#define dtype_double   12\r
+#define dtype_d_float  13\r
+#define dtype_sql_date 14\r
+#define dtype_sql_time 15\r
+#define dtype_timestamp        16\r
+#define dtype_blob     17\r
+#define dtype_array    18\r
+#define dtype_int64     19\r
+#define DTYPE_TYPE_MAX 20\r
+#endif /* !defined(JRD_DSC_H) */\r
+\r
+\r
+/***************************/\r
+/* Dynamic SQL definitions */\r
+/***************************/\r
+\r
+/******************************/\r
+/* Declare the extended SQLDA */\r
+/******************************/\r
+\r
+#ifndef FB_SQLDA\r
+\r
+typedef struct\r
+{\r
+       short                   sqltype;                        /* datatype of field */\r
+       short                   sqlscale;                       /* scale factor */\r
+       short                   sqlsubtype;                     /* datatype subtype - BLOBs & Text types only */\r
+       short                   sqllen;                         /* length of data area */\r
+       char *                  sqldata;                        /* address of data */\r
+       short *                 sqlind;                         /* address of indicator variable */\r
+       short                   sqlname_length;         /* length of sqlname field */\r
+       char                    sqlname[32];            /* name of field, name length + space for NULL */\r
+       short                   relname_length;         /* length of relation name */\r
+       char                    relname[32];            /* field's relation name + space for NULL */\r
+       short                   ownname_length;         /* length of owner name */\r
+       char                    ownname[32];            /* relation's owner name + space for  NULL */\r
+       short                   aliasname_length;       /* length of alias name */\r
+       char                    aliasname[32];          /* relation's alias name + space for NULL */\r
+} XSQLVAR;\r
+\r
+typedef struct\r
+{\r
+       short           version;                        /* version of this XSQLDA */\r
+       char            sqldaid[8];                     /* XSQLDA name field */\r
+       ISC_LONG        sqldabc;                        /* length in bytes of SQLDA */\r
+       short           sqln;                           /* number of fields allocated */\r
+       short           sqld;                           /* actual number of fields */\r
+       XSQLVAR         sqlvar[1];                      /* first field address */\r
+} XSQLDA;\r
+\r
+#define XSQLDA_LENGTH(n)       (sizeof (XSQLDA) + ((n)-1) * sizeof (XSQLVAR))\r
+\r
+#define SQLDA_VERSION1                         1\r
+\r
+#define SQL_DIALECT_V5                         1       /* meaning is same as DIALECT_xsqlda */\r
+#define SQL_DIALECT_V6_TRANSITION      2       /* flagging anything that is delimited\r
+                                                                                  by double quotes as an error and\r
+                                                                                  flagging keyword DATE as an error */\r
+#define SQL_DIALECT_V6                         3       /* supports SQL delimited identifier,\r
+                                                                                  SQLDATE/DATE, TIME, TIMESTAMP,\r
+                                                                                  CURRENT_DATE, CURRENT_TIME,\r
+                                                                                  CURRENT_TIMESTAMP, and 64-bit exact\r
+                                                                                  numeric type */\r
+#define SQL_DIALECT_CURRENT            SQL_DIALECT_V6  /* latest IB DIALECT */\r
+\r
+\r
+#define FB_SQLDA\r
+#endif\r
+\r
+/***************************/\r
+/* OSRI database functions */\r
+/***************************/\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+ISC_STATUS ISC_EXPORT isc_attach_database(ISC_STATUS *,\r
+                                                                                 short,\r
+                                                                                 char *,\r
+                                                                                 isc_db_handle *,\r
+                                                                                 short,\r
+                                                                                 char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_array_gen_sdl(ISC_STATUS *,\r
+                                                                               ISC_ARRAY_DESC *,\r
+                                                                               short *,\r
+                                                                               char *,\r
+                                                                               short *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_array_get_slice(ISC_STATUS *,\r
+                                                                                 isc_db_handle *,\r
+                                                                                 isc_tr_handle *,\r
+                                                                                 ISC_QUAD *,\r
+                                                                                 ISC_ARRAY_DESC *,\r
+                                                                                 void *,\r
+                                                                                 ISC_LONG *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_array_lookup_bounds(ISC_STATUS *,\r
+                                                                                         isc_db_handle *,\r
+                                                                                         isc_tr_handle *,\r
+                                                                                         char *,\r
+                                                                                         char *,\r
+                                                                                         ISC_ARRAY_DESC *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_array_lookup_desc(ISC_STATUS *,\r
+                                                                                       isc_db_handle *,\r
+                                                                                       isc_tr_handle *,\r
+                                                                                       char *,\r
+                                                                                       char *,\r
+                                                                                       ISC_ARRAY_DESC *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_array_set_desc(ISC_STATUS *,\r
+                                                                                char *,\r
+                                                                                char *,\r
+                                                                                short *,\r
+                                                                                short *,\r
+                                                                                short *,\r
+                                                                                ISC_ARRAY_DESC *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_array_put_slice(ISC_STATUS *,\r
+                                                                                 isc_db_handle *,\r
+                                                                                 isc_tr_handle *,\r
+                                                                                 ISC_QUAD *,\r
+                                                                                 ISC_ARRAY_DESC *,\r
+                                                                                 void *,\r
+                                                                                 ISC_LONG *);\r
+\r
+void ISC_EXPORT isc_blob_default_desc(ISC_BLOB_DESC *,\r
+                                                                         unsigned char *,\r
+                                                                         unsigned char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_blob_gen_bpb(ISC_STATUS *,\r
+                                                                          ISC_BLOB_DESC *,\r
+                                                                          ISC_BLOB_DESC *,\r
+                                                                          unsigned short,\r
+                                                                          unsigned char *,\r
+                                                                          unsigned short *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_blob_info(ISC_STATUS *,\r
+                                                                       isc_blob_handle *,\r
+                                                                       short,\r
+                                                                       char *,\r
+                                                                       short,\r
+                                                                       char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_blob_lookup_desc(ISC_STATUS *,\r
+                                                                                  isc_db_handle *,\r
+                                                                                  isc_tr_handle *,\r
+                                                                                  unsigned char *,\r
+                                                                                  unsigned char *,\r
+                                                                                  ISC_BLOB_DESC *,\r
+                                                                                  unsigned char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_blob_set_desc(ISC_STATUS *,\r
+                                                                               unsigned char *,\r
+                                                                               unsigned char *,\r
+                                                                               short,\r
+                                                                               short,\r
+                                                                               short,\r
+                                                                               ISC_BLOB_DESC *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_cancel_blob(ISC_STATUS *,\r
+                                                                         isc_blob_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_cancel_events(ISC_STATUS *,\r
+                                                                               isc_db_handle *,\r
+                                                                               ISC_LONG *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_close_blob(ISC_STATUS *,\r
+                                                                        isc_blob_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_commit_retaining(ISC_STATUS *,\r
+                                                                                  isc_tr_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_commit_transaction(ISC_STATUS *,\r
+                                                                                        isc_tr_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_create_blob(ISC_STATUS *,\r
+                                                                         isc_db_handle *,\r
+                                                                         isc_tr_handle *,\r
+                                                                         isc_blob_handle *,\r
+                                                                         ISC_QUAD *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_create_blob2(ISC_STATUS *,\r
+                                                                          isc_db_handle *,\r
+                                                                          isc_tr_handle *,\r
+                                                                          isc_blob_handle *,\r
+                                                                          ISC_QUAD *,\r
+                                                                          short,\r
+                                                                          char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_create_database(ISC_STATUS *,\r
+                                                                                 short,\r
+                                                                                 char *,\r
+                                                                                 isc_db_handle *,\r
+                                                                                 short,\r
+                                                                                 char *,\r
+                                                                                 short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_database_info(ISC_STATUS *,\r
+                                                                               isc_db_handle *,\r
+                                                                               short,\r
+                                                                               char *,\r
+                                                                               short,\r
+                                                                               char *);\r
+\r
+void ISC_EXPORT isc_decode_date(ISC_QUAD *,\r
+                                                               void *);\r
+\r
+void ISC_EXPORT isc_decode_sql_date(ISC_DATE *,\r
+                                                                       void *);\r
+\r
+void ISC_EXPORT isc_decode_sql_time(ISC_TIME *,\r
+                                                                       void *);\r
+\r
+void ISC_EXPORT isc_decode_timestamp(ISC_TIMESTAMP *,\r
+                                                                        void *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_detach_database(ISC_STATUS *,\r
+                                                                                 isc_db_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_drop_database(ISC_STATUS *,\r
+                                                                               isc_db_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_allocate_statement(ISC_STATUS *,\r
+                                                                                                 isc_db_handle *,\r
+                                                                                                 isc_stmt_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_alloc_statement2(ISC_STATUS *,\r
+                                                                                               isc_db_handle *,\r
+                                                                                               isc_stmt_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_describe(ISC_STATUS *,\r
+                                                                               isc_stmt_handle *,\r
+                                                                               unsigned short,\r
+                                                                               XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_describe_bind(ISC_STATUS *,\r
+                                                                                        isc_stmt_handle *,\r
+                                                                                        unsigned short,\r
+                                                                                        XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_exec_immed2(ISC_STATUS *,\r
+                                                                                  isc_db_handle *,\r
+                                                                                  isc_tr_handle *,\r
+                                                                                  unsigned short,\r
+                                                                                  char *,\r
+                                                                                  unsigned short,\r
+                                                                                  XSQLDA *,\r
+                                                                                  XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_execute(ISC_STATUS *,\r
+                                                                          isc_tr_handle *,\r
+                                                                          isc_stmt_handle *,\r
+                                                                          unsigned short,\r
+                                                                          XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_execute2(ISC_STATUS *,\r
+                                                                               isc_tr_handle *,\r
+                                                                               isc_stmt_handle *,\r
+                                                                               unsigned short,\r
+                                                                               XSQLDA *,\r
+                                                                               XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_execute_immediate(ISC_STATUS *,\r
+                                                                                                isc_db_handle *,\r
+                                                                                                isc_tr_handle *,\r
+                                                                                                unsigned short,\r
+                                                                                                char *,\r
+                                                                                                unsigned short,\r
+                                                                                                XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_fetch(ISC_STATUS *,\r
+                                                                        isc_stmt_handle *,\r
+                                                                        unsigned short,\r
+                                                                        XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_finish(isc_db_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_free_statement(ISC_STATUS *,\r
+                                                                                         isc_stmt_handle *,\r
+                                                                                         unsigned short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_insert(ISC_STATUS *,\r
+                                                                         isc_stmt_handle *,\r
+                                                                         unsigned short,\r
+                                                                         XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_prepare(ISC_STATUS *,\r
+                                                                          isc_tr_handle *,\r
+                                                                          isc_stmt_handle *,\r
+                                                                          unsigned short,\r
+                                                                          char *,\r
+                                                                          unsigned short,\r
+                                                                          XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_set_cursor_name(ISC_STATUS *,\r
+                                                                                          isc_stmt_handle *,\r
+                                                                                          char *,\r
+                                                                                          unsigned short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_sql_info(ISC_STATUS *,\r
+                                                                               isc_stmt_handle *,\r
+                                                                               short,\r
+                                                                               const char *,\r
+                                                                               short,\r
+                                                                               char *);\r
+\r
+void ISC_EXPORT isc_encode_date(void *,\r
+                                                               ISC_QUAD *);\r
+\r
+void ISC_EXPORT isc_encode_sql_date(void *,\r
+                                                                       ISC_DATE *);\r
+\r
+void ISC_EXPORT isc_encode_sql_time(void *,\r
+                                                                       ISC_TIME *);\r
+\r
+void ISC_EXPORT isc_encode_timestamp(void *,\r
+                                                                        ISC_TIMESTAMP *);\r
+\r
+ISC_LONG ISC_EXPORT_VARARG isc_event_block(char * *,\r
+                                                                                  char * *,\r
+                                                                                  unsigned short, ...);\r
+\r
+void ISC_EXPORT isc_event_counts(ISC_ULONG *,\r
+                                                                short,\r
+                                                                char *,\r
+                                                                char *);\r
+\r
+/* 17 May 2001 - isc_expand_dpb is DEPRECATED */\r
+void ISC_EXPORT_VARARG isc_expand_dpb(char * *,\r
+                                                                         short *, ...);\r
+\r
+int ISC_EXPORT isc_modify_dpb(char * *,\r
+                                                         short *,\r
+                                                         unsigned short,\r
+                                                         char *,\r
+                                                         short);\r
+\r
+ISC_LONG ISC_EXPORT isc_free(char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_get_segment(ISC_STATUS *,\r
+                                                                         isc_blob_handle *,\r
+                                                                         unsigned short *,\r
+                                                                         unsigned short,\r
+                                                                         char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_get_slice(ISC_STATUS *,\r
+                                                                       isc_db_handle *,\r
+                                                                       isc_tr_handle *,\r
+                                                                       ISC_QUAD *,\r
+                                                                       short,\r
+                                                                       char *,\r
+                                                                       short,\r
+                                                                       ISC_LONG *,\r
+                                                                       ISC_LONG,\r
+                                                                       void *,\r
+                                                                       ISC_LONG *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_interprete(char *,\r
+                                                                        ISC_STATUS * *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_open_blob(ISC_STATUS *,\r
+                                                                       isc_db_handle *,\r
+                                                                       isc_tr_handle *,\r
+                                                                       isc_blob_handle *,\r
+                                                                       ISC_QUAD *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_open_blob2(ISC_STATUS *,\r
+                                                                        isc_db_handle *,\r
+                                                                        isc_tr_handle *,\r
+                                                                        isc_blob_handle *,\r
+                                                                        ISC_QUAD *,\r
+                                                                        ISC_USHORT,\r
+                                                                        ISC_UCHAR *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_prepare_transaction2(ISC_STATUS *,\r
+                                                                                          isc_tr_handle *,\r
+                                                                                          ISC_USHORT,\r
+                                                                                          ISC_UCHAR *);\r
+\r
+void ISC_EXPORT isc_print_sqlerror(ISC_SHORT,\r
+                                                                  ISC_STATUS *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_print_status(ISC_STATUS *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_put_segment(ISC_STATUS *,\r
+                                                                         isc_blob_handle *,\r
+                                                                         unsigned short,\r
+                                                                         char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_put_slice(ISC_STATUS *,\r
+                                                                       isc_db_handle *,\r
+                                                                       isc_tr_handle *,\r
+                                                                       ISC_QUAD *,\r
+                                                                       short,\r
+                                                                       char *,\r
+                                                                       short,\r
+                                                                       ISC_LONG *,\r
+                                                                       ISC_LONG,\r
+                                                                       void *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_que_events(ISC_STATUS *,\r
+                                                                        isc_db_handle *,\r
+                                                                        ISC_LONG *,\r
+                                                                        short,\r
+                                                                        char *,\r
+                                                                        isc_callback,\r
+                                                                        void *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_rollback_retaining(ISC_STATUS *,\r
+                                                                                        isc_tr_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_rollback_transaction(ISC_STATUS *,\r
+                                                                                          isc_tr_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_start_multiple(ISC_STATUS *,\r
+                                                                                isc_tr_handle *,\r
+                                                                                short,\r
+                                                                                void *);\r
+\r
+ISC_STATUS ISC_EXPORT_VARARG isc_start_transaction(ISC_STATUS *,\r
+                                                                                                  isc_tr_handle *,\r
+                                                                                                  short, ...);\r
+\r
+ISC_LONG ISC_EXPORT isc_sqlcode(ISC_STATUS *);\r
+\r
+void ISC_EXPORT isc_sql_interprete(short,\r
+                                                                  char *,\r
+                                                                  short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_transaction_info(ISC_STATUS *,\r
+                                                                                  isc_tr_handle *,\r
+                                                                                  short,\r
+                                                                                  char *,\r
+                                                                                  short,\r
+                                                                                  char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_transact_request(ISC_STATUS *,\r
+                                                                                  isc_db_handle *,\r
+                                                                                  isc_tr_handle *,\r
+                                                                                  unsigned short,\r
+                                                                                  char *,\r
+                                                                                  unsigned short,\r
+                                                                                  char *,\r
+                                                                                  unsigned short,\r
+                                                                                  char *);\r
+\r
+ISC_LONG ISC_EXPORT isc_vax_integer(char *,\r
+                                                                       short);\r
+\r
+ISC_INT64 ISC_EXPORT isc_portable_integer(unsigned char *,\r
+                                                                                 short);\r
+\r
+/*************************************/\r
+/* Security Functions and structures */\r
+/*************************************/\r
+\r
+#define sec_uid_spec               0x01\r
+#define sec_gid_spec               0x02\r
+#define sec_server_spec                    0x04\r
+#define sec_password_spec          0x08\r
+#define sec_group_name_spec        0x10\r
+#define sec_first_name_spec        0x20\r
+#define sec_middle_name_spec        0x40\r
+#define sec_last_name_spec         0x80\r
+#define sec_dba_user_name_spec      0x100\r
+#define sec_dba_password_spec       0x200\r
+\r
+#define sec_protocol_tcpip            1\r
+#define sec_protocol_netbeui          2\r
+#define sec_protocol_spx              3 /* -- Deprecated Protocol. Declaration retained for compatibility   */\r
+#define sec_protocol_local            4\r
+\r
+typedef struct {\r
+       short sec_flags;                        /* which fields are specified */\r
+       int uid;                                        /* the user's id */\r
+       int gid;                                        /* the user's group id */\r
+       int protocol;                           /* protocol to use for connection */\r
+       char *server;                           /* server to administer */\r
+       char *user_name;                        /* the user's name */\r
+       char *password;                         /* the user's password */\r
+       char *group_name;                       /* the group name */\r
+       char *first_name;                       /* the user's first name */\r
+       char *middle_name;                      /* the user's middle name */\r
+       char *last_name;                        /* the user's last name */\r
+       char *dba_user_name;            /* the dba user name */\r
+       char *dba_password;                     /* the dba password */\r
+} USER_SEC_DATA;\r
+\r
+int ISC_EXPORT isc_add_user(ISC_STATUS *, USER_SEC_DATA *);\r
+\r
+int ISC_EXPORT isc_delete_user(ISC_STATUS *, USER_SEC_DATA *);\r
+\r
+int ISC_EXPORT isc_modify_user(ISC_STATUS *, USER_SEC_DATA *);\r
+\r
+/**********************************/\r
+/*  Other OSRI functions          */\r
+/**********************************/\r
+\r
+ISC_STATUS ISC_EXPORT isc_compile_request(ISC_STATUS *,\r
+                                                                                 isc_db_handle *,\r
+                                                                                 isc_req_handle *,\r
+                                                                                 short,\r
+                                                                                 char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_compile_request2(ISC_STATUS *,\r
+                                                                                  isc_db_handle *,\r
+                                                                                  isc_req_handle *,\r
+                                                                                  short,\r
+                                                                                  char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_ddl(ISC_STATUS *,\r
+                                                         isc_db_handle *,\r
+                                                         isc_tr_handle *,\r
+                                                         short,\r
+                                                         char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_prepare_transaction(ISC_STATUS *,\r
+                                                                                         isc_tr_handle *);\r
+\r
+\r
+ISC_STATUS ISC_EXPORT isc_receive(ISC_STATUS *,\r
+                                                                 isc_req_handle *,\r
+                                                                 short,\r
+                                                                 short,\r
+                                                                 void *,\r
+                                                                 short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_reconnect_transaction(ISC_STATUS *,\r
+                                                                                               isc_db_handle *,\r
+                                                                                               isc_tr_handle *,\r
+                                                                                               short,\r
+                                                                                               char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_release_request(ISC_STATUS *,\r
+                                                                                 isc_req_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_request_info(ISC_STATUS *,\r
+                                                                          isc_req_handle *,\r
+                                                                          short,\r
+                                                                          short,\r
+                                                                          char *,\r
+                                                                          short,\r
+                                                                          char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_seek_blob(ISC_STATUS *,\r
+                                                                       isc_blob_handle *,\r
+                                                                       short,\r
+                                                                       ISC_LONG,\r
+                                                                       ISC_LONG *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_send(ISC_STATUS *,\r
+                                                          isc_req_handle *,\r
+                                                          short,\r
+                                                          short,\r
+                                                          void *,\r
+                                                          short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_start_and_send(ISC_STATUS *,\r
+                                                                                isc_req_handle *,\r
+                                                                                isc_tr_handle *,\r
+                                                                                short,\r
+                                                                                short,\r
+                                                                                void *,\r
+                                                                                short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_start_request(ISC_STATUS *,\r
+                                                                               isc_req_handle *,\r
+                                                                               isc_tr_handle *,\r
+                                                                               short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_unwind_request(ISC_STATUS *,\r
+                                                                                isc_tr_handle *,\r
+                                                                                short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_wait_for_event(ISC_STATUS *,\r
+                                                                                isc_db_handle *,\r
+                                                                                short,\r
+                                                                                char *,\r
+                                                                                char *);\r
+\r
+\r
+/*****************************/\r
+/* Other Sql functions       */\r
+/*****************************/\r
+\r
+ISC_STATUS ISC_EXPORT isc_close(ISC_STATUS *,\r
+                                                               char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_declare(ISC_STATUS *,\r
+                                                                 char *,\r
+                                                                 char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_describe(ISC_STATUS *,\r
+                                                                  char *,\r
+                                                                  XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_describe_bind(ISC_STATUS *,\r
+                                                                               char *,\r
+                                                                               XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_execute(ISC_STATUS *,\r
+                                                                 isc_tr_handle *,\r
+                                                                 char *,\r
+                                                                 XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_execute_immediate(ISC_STATUS *,\r
+                                                                                       isc_db_handle *,\r
+                                                                                       isc_tr_handle *,\r
+                                                                                       short *,\r
+                                                                                       char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_fetch(ISC_STATUS *,\r
+                                                               char *,\r
+                                                               XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_open(ISC_STATUS *,\r
+                                                          isc_tr_handle *,\r
+                                                          char *,\r
+                                                          XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_prepare(ISC_STATUS *,\r
+                                                                 isc_db_handle *,\r
+                                                                 isc_tr_handle *,\r
+                                                                 char *,\r
+                                                                 short *,\r
+                                                                 char *,\r
+                                                                 XSQLDA *);\r
+\r
+\r
+/*************************************/\r
+/* Other Dynamic sql functions       */\r
+/*************************************/\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_execute_m(ISC_STATUS *,\r
+                                                                                isc_tr_handle *,\r
+                                                                                isc_stmt_handle *,\r
+                                                                                unsigned short,\r
+                                                                                char *,\r
+                                                                                unsigned short,\r
+                                                                                unsigned short,\r
+                                                                                char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_execute2_m(ISC_STATUS *,\r
+                                                                                 isc_tr_handle *,\r
+                                                                                 isc_stmt_handle *,\r
+                                                                                 unsigned short,\r
+                                                                                 char *,\r
+                                                                                 unsigned short,\r
+                                                                                 unsigned short,\r
+                                                                                 char *,\r
+                                                                                 unsigned short,\r
+                                                                                 char *,\r
+                                                                                 unsigned short,\r
+                                                                                 unsigned short,\r
+                                                                                 char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_execute_immediate_m(ISC_STATUS *,\r
+                                                                                                  isc_db_handle *,\r
+                                                                                                  isc_tr_handle *,\r
+                                                                                                  unsigned short,\r
+                                                                                                  char *,\r
+                                                                                                  unsigned short,\r
+                                                                                                  unsigned short,\r
+                                                                                                  char *,\r
+                                                                                                  unsigned short,\r
+                                                                                                  unsigned short,\r
+                                                                                                  char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_exec_immed3_m(ISC_STATUS *,\r
+                                                                                        isc_db_handle *,\r
+                                                                                        isc_tr_handle *,\r
+                                                                                        unsigned short,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        unsigned short,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        unsigned short,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        unsigned short,\r
+                                                                                        char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_fetch_m(ISC_STATUS *,\r
+                                                                          isc_stmt_handle *,\r
+                                                                          unsigned short,\r
+                                                                          char *,\r
+                                                                          unsigned short,\r
+                                                                          unsigned short,\r
+                                                                          char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_insert_m(ISC_STATUS *,\r
+                                                                               isc_stmt_handle *,\r
+                                                                               unsigned short,\r
+                                                                               char *,\r
+                                                                               unsigned short,\r
+                                                                               unsigned short,\r
+                                                                               char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_prepare_m(ISC_STATUS *,\r
+                                                                                isc_tr_handle *,\r
+                                                                                isc_stmt_handle *,\r
+                                                                                unsigned short,\r
+                                                                                char *,\r
+                                                                                unsigned short,\r
+                                                                                unsigned short,\r
+                                                                                char *,\r
+                                                                                unsigned short,\r
+                                                                                char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_dsql_release(ISC_STATUS *,\r
+                                                                          char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_close(ISC_STATUS *,\r
+                                                                                  char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_declare(ISC_STATUS *,\r
+                                                                                        char *,\r
+                                                                                        char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_describe(ISC_STATUS *,\r
+                                                                                         char *,\r
+                                                                                         unsigned short,\r
+                                                                                         XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_describe_bind(ISC_STATUS *,\r
+                                                                                                  char *,\r
+                                                                                                  unsigned short,\r
+                                                                                                  XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_execute(ISC_STATUS *,\r
+                                                                                        isc_tr_handle *,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_execute2(ISC_STATUS *,\r
+                                                                                         isc_tr_handle *,\r
+                                                                                         char *,\r
+                                                                                         unsigned short,\r
+                                                                                         XSQLDA *,\r
+                                                                                         XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_execute_immed(ISC_STATUS *,\r
+                                                                                                  isc_db_handle *,\r
+                                                                                                  isc_tr_handle *,\r
+                                                                                                  unsigned short,\r
+                                                                                                  char *,\r
+                                                                                                  unsigned short,\r
+                                                                                                  XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_fetch(ISC_STATUS *,\r
+                                                                                  char *,\r
+                                                                                  unsigned short,\r
+                                                                                  XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_open(ISC_STATUS *,\r
+                                                                                 isc_tr_handle *,\r
+                                                                                 char *,\r
+                                                                                 unsigned short,\r
+                                                                                 XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_open2(ISC_STATUS *,\r
+                                                                                  isc_tr_handle *,\r
+                                                                                  char *,\r
+                                                                                  unsigned short,\r
+                                                                                  XSQLDA *,\r
+                                                                                  XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_insert(ISC_STATUS *,\r
+                                                                                       char *,\r
+                                                                                       unsigned short,\r
+                                                                                       XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_prepare(ISC_STATUS *,\r
+                                                                                        isc_db_handle *,\r
+                                                                                        isc_tr_handle *,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        char *,\r
+                                                                                        unsigned short,\r
+                                                                                        XSQLDA *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_embed_dsql_release(ISC_STATUS *,\r
+                                                                                        char *);\r
+\r
+\r
+/******************************/\r
+/* Other Blob functions       */\r
+/******************************/\r
+\r
+BSTREAM *ISC_EXPORT BLOB_open(isc_blob_handle,\r
+                                                                         char *,\r
+                                                                         int);\r
+\r
+int ISC_EXPORT BLOB_put(char,\r
+                                               BSTREAM *);\r
+\r
+int ISC_EXPORT BLOB_close(BSTREAM *);\r
+\r
+int ISC_EXPORT BLOB_get(BSTREAM *);\r
+\r
+int ISC_EXPORT BLOB_display(ISC_QUAD *,\r
+                                                       isc_db_handle,\r
+                                                       isc_tr_handle,\r
+                                                       char *);\r
+\r
+int ISC_EXPORT BLOB_dump(ISC_QUAD *,\r
+                                                isc_db_handle,\r
+                                                isc_tr_handle,\r
+                                                char *);\r
+\r
+int ISC_EXPORT BLOB_edit(ISC_QUAD *,\r
+                                                isc_db_handle,\r
+                                                isc_tr_handle,\r
+                                                char *);\r
+\r
+int ISC_EXPORT BLOB_load(ISC_QUAD *,\r
+                                                isc_db_handle,\r
+                                                isc_tr_handle,\r
+                                                char *);\r
+\r
+int ISC_EXPORT BLOB_text_dump(ISC_QUAD *,\r
+                                                         isc_db_handle,\r
+                                                         isc_tr_handle,\r
+                                                         char *);\r
+\r
+int ISC_EXPORT BLOB_text_load(ISC_QUAD *,\r
+                                                         isc_db_handle,\r
+                                                         isc_tr_handle,\r
+                                                         char *);\r
+\r
+BSTREAM *ISC_EXPORT Bopen(ISC_QUAD *,\r
+                                                                 isc_db_handle,\r
+                                                                 isc_tr_handle,\r
+                                                                 char *);\r
+\r
+BSTREAM *ISC_EXPORT Bopen2(ISC_QUAD *,\r
+                                                                  isc_db_handle,\r
+                                                                  isc_tr_handle,\r
+                                                                  char *,\r
+                                                                  unsigned short);\r
+\r
+\r
+/******************************/\r
+/* Other Misc functions       */\r
+/******************************/\r
+\r
+ISC_LONG ISC_EXPORT isc_ftof(char *,\r
+                                                        unsigned short,\r
+                                                        char *,\r
+                                                        unsigned short);\r
+\r
+ISC_STATUS ISC_EXPORT isc_print_blr(char *,\r
+                                                                       isc_callback,\r
+                                                                       void *,\r
+                                                                       short);\r
+\r
+void ISC_EXPORT isc_set_debug(int);\r
+\r
+void ISC_EXPORT isc_qtoq(ISC_QUAD *,\r
+                                                ISC_QUAD *);\r
+\r
+void ISC_EXPORT isc_vtof(char *,\r
+                                                char *,\r
+                                                unsigned short);\r
+\r
+void ISC_EXPORT isc_vtov(char *,\r
+                                                char *,\r
+                                                short);\r
+\r
+int ISC_EXPORT isc_version(isc_db_handle *,\r
+                                                  isc_callback,\r
+                                                  void *);\r
+\r
+ISC_LONG ISC_EXPORT isc_reset_fpe(unsigned short);\r
+\r
+\r
+/*****************************************/\r
+/* Service manager functions             */\r
+/*****************************************/\r
+\r
+#define ADD_SPB_LENGTH(p, length)      {*(p)++ = (length); *(p)++ = (length) >> 8;}\r
+\r
+#define ADD_SPB_NUMERIC(p, data)       {*(p)++ = (SCHAR) (data); *(p)++ = (SCHAR) ((data) >> 8); *(p)++ = (SCHAR) ((data) >> 16); *(p)++ = (SCHAR) ((data) >> 24);}\r
+\r
+ISC_STATUS ISC_EXPORT isc_service_attach(ISC_STATUS *,\r
+                                                                                unsigned short,\r
+                                                                                char *,\r
+                                                                                isc_svc_handle *,\r
+                                                                                unsigned short,\r
+                                                                                char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_service_detach(ISC_STATUS *,\r
+                                                                                isc_svc_handle *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_service_query(ISC_STATUS *,\r
+                                                                               isc_svc_handle *,\r
+                                                                               isc_resv_handle *,\r
+                                                                               unsigned short,\r
+                                                                               char *,\r
+                                                                               unsigned short,\r
+                                                                               char *,\r
+                                                                               unsigned short,\r
+                                                                               char *);\r
+\r
+ISC_STATUS ISC_EXPORT isc_service_start(ISC_STATUS *,\r
+                                                                               isc_svc_handle *,\r
+                                                                               isc_resv_handle *,\r
+                                                                               unsigned short,\r
+                                                                               char *);\r
+\r
+\r
+/********************************/\r
+/* Client information functions */\r
+/********************************/\r
+\r
+void ISC_EXPORT isc_get_client_version ( char  *);\r
+int  ISC_EXPORT isc_get_client_major_version ();\r
+int  ISC_EXPORT isc_get_client_minor_version ();\r
+\r
+#ifdef __cplusplus\r
+}      /* extern "C" */\r
+#endif\r
+\r
+\r
+/***************************************************/\r
+/* Actions to pass to the blob filter (ctl_source) */\r
+/***************************************************/\r
+\r
+#define isc_blob_filter_open             0\r
+#define isc_blob_filter_get_segment      1\r
+#define isc_blob_filter_close            2\r
+#define isc_blob_filter_create           3\r
+#define isc_blob_filter_put_segment      4\r
+#define isc_blob_filter_alloc            5\r
+#define isc_blob_filter_free             6\r
+#define isc_blob_filter_seek             7\r
+\r
+/*******************/\r
+/* Blr definitions */\r
+/*******************/\r
+\r
+/*\r
+ *     PROGRAM:        C preprocessor\r
+ *     MODULE:         blr.h\r
+ *     DESCRIPTION:    BLR constants\r
+ *\r
+ * The contents of this file are subject to the Interbase Public\r
+ * License Version 1.0 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy\r
+ * of the License at http://www.Inprise.com/IPL.html\r
+ *\r
+ * Software distributed under the License is distributed on an\r
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express\r
+ * or implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code was created by Inprise Corporation\r
+ * and its predecessors. Portions created by Inprise Corporation are\r
+ * Copyright (C) Inprise Corporation.\r
+ *\r
+ * All Rights Reserved.\r
+ * Contributor(s): ______________________________________.\r
+ *\r
+ * Claudio Valderrama: 2001.6.18: Add blr_current_role.\r
+ * 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced\r
+ *                            exception handling in SPs/triggers,\r
+ *                            implemented ROWS_AFFECTED system variable\r
+ * 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks\r
+ * 2002.10.29 Nickolay Samofatov: Added support for savepoints\r
+ */\r
+\r
+#ifndef _JRD_BLR_H_\r
+#define _JRD_BLR_H_\r
+\r
+/*  WARNING: if you add a new BLR representing a data type, and the value\r
+ *           is greater than the numerically greatest value which now\r
+ *           represents a data type, you must change the define for\r
+ *           DTYPE_BLR_MAX in jrd/align.h, and add the necessary entries\r
+ *           to all the arrays in that file.\r
+ */\r
+\r
+#define blr_text               (unsigned char)14\r
+#define blr_text2              (unsigned char)15       /* added in 3.2 JPN */\r
+#define blr_short              (unsigned char)7\r
+#define blr_long               (unsigned char)8\r
+#define blr_quad               (unsigned char)9\r
+#define blr_float              (unsigned char)10\r
+#define blr_double             (unsigned char)27\r
+#define blr_d_float            (unsigned char)11\r
+#define blr_timestamp          (unsigned char)35\r
+#define blr_varying            (unsigned char)37\r
+#define blr_varying2           (unsigned char)38       /* added in 3.2 JPN */\r
+#define blr_blob               (unsigned short)261\r
+#define blr_cstring            (unsigned char)40       \r
+#define blr_cstring2           (unsigned char)41       /* added in 3.2 JPN */\r
+#define blr_blob_id            (unsigned char)45       /* added from gds.h */\r
+#define blr_sql_date           (unsigned char)12\r
+#define blr_sql_time           (unsigned char)13\r
+#define blr_int64               (unsigned char)16\r
+\r
+/* Historical alias for pre V6 applications */\r
+#define blr_date               blr_timestamp\r
+\r
+#define blr_inner              (unsigned char)0\r
+#define blr_left               (unsigned char)1\r
+#define blr_right              (unsigned char)2\r
+#define blr_full               (unsigned char)3\r
+\r
+#define blr_gds_code           (unsigned char)0\r
+#define blr_sql_code           (unsigned char)1\r
+#define blr_exception          (unsigned char)2\r
+#define blr_trigger_code       (unsigned char)3\r
+#define blr_default_code       (unsigned char)4\r
+#define blr_raise                      (unsigned char)5\r
+#define blr_exception_msg      (unsigned char)6\r
+\r
+#define blr_version4           (unsigned char)4\r
+#define blr_version5           (unsigned char)5\r
+#define blr_eoc                        (unsigned char)76\r
+#define blr_end                        (unsigned char)255      /* note: defined as -1 in gds.h */\r
+\r
+#define blr_assignment         (unsigned char)1\r
+#define blr_begin              (unsigned char)2\r
+#define blr_dcl_variable       (unsigned char)3        /* added from gds.h */\r
+#define blr_message            (unsigned char)4\r
+#define blr_erase              (unsigned char)5\r
+#define blr_fetch              (unsigned char)6\r
+#define blr_for                        (unsigned char)7\r
+#define blr_if                 (unsigned char)8\r
+#define blr_loop               (unsigned char)9\r
+#define blr_modify             (unsigned char)10\r
+#define blr_handler            (unsigned char)11\r
+#define blr_receive            (unsigned char)12\r
+#define blr_select             (unsigned char)13\r
+#define blr_send               (unsigned char)14\r
+#define blr_store              (unsigned char)15\r
+#define blr_label              (unsigned char)17\r
+#define blr_leave              (unsigned char)18\r
+#define blr_store2             (unsigned char)19\r
+#define blr_post                (unsigned char)20\r
+#define blr_literal            (unsigned char)21\r
+#define blr_dbkey              (unsigned char)22\r
+#define blr_field              (unsigned char)23\r
+#define blr_fid                        (unsigned char)24\r
+#define blr_parameter          (unsigned char)25\r
+#define blr_variable           (unsigned char)26\r
+#define blr_average            (unsigned char)27\r
+#define blr_count              (unsigned char)28\r
+#define blr_maximum            (unsigned char)29\r
+#define blr_minimum            (unsigned char)30\r
+#define blr_total              (unsigned char)31\r
+/* count 2\r
+#define blr_count2             32\r
+*/\r
+#define blr_add                        (unsigned char)34\r
+#define blr_subtract           (unsigned char)35\r
+#define blr_multiply           (unsigned char)36\r
+#define blr_divide             (unsigned char)37\r
+#define blr_negate             (unsigned char)38\r
+#define blr_concatenate                (unsigned char)39\r
+#define blr_substring          (unsigned char)40\r
+#define blr_parameter2         (unsigned char)41\r
+#define blr_from               (unsigned char)42\r
+#define blr_via                        (unsigned char)43\r
+#define blr_parameter2_old     (unsigned char)44       /* Confusion */\r
+#define blr_user_name          (unsigned char)44       /* added from gds.h */\r
+#define blr_null               (unsigned char)45\r
+\r
+#define blr_eql                        (unsigned char)47\r
+#define blr_neq                        (unsigned char)48\r
+#define blr_gtr                        (unsigned char)49\r
+#define blr_geq                        (unsigned char)50\r
+#define blr_lss                        (unsigned char)51\r
+#define blr_leq                        (unsigned char)52\r
+#define blr_containing         (unsigned char)53\r
+#define blr_matching           (unsigned char)54\r
+#define blr_starting           (unsigned char)55\r
+#define blr_between            (unsigned char)56\r
+#define blr_or                 (unsigned char)57\r
+#define blr_and                        (unsigned char)58\r
+#define blr_not                        (unsigned char)59\r
+#define blr_any                        (unsigned char)60\r
+#define blr_missing            (unsigned char)61\r
+#define blr_unique             (unsigned char)62\r
+#define blr_like               (unsigned char)63\r
+\r
+#define blr_stream             (unsigned char)65       /* added from gds.h */\r
+#define blr_set_index          (unsigned char)66       /* added from gds.h */\r
+\r
+#define blr_rse                        (unsigned char)67\r
+#define blr_first              (unsigned char)68\r
+#define blr_project            (unsigned char)69\r
+#define blr_sort               (unsigned char)70\r
+#define blr_boolean            (unsigned char)71\r
+#define blr_ascending          (unsigned char)72\r
+#define blr_descending         (unsigned char)73\r
+#define blr_relation           (unsigned char)74\r
+#define blr_rid                        (unsigned char)75\r
+#define blr_union              (unsigned char)76\r
+#define blr_map                        (unsigned char)77\r
+#define blr_group_by           (unsigned char)78\r
+#define blr_aggregate          (unsigned char)79\r
+#define blr_join_type          (unsigned char)80\r
+\r
+#define blr_agg_count          (unsigned char)83\r
+#define blr_agg_max            (unsigned char)84\r
+#define blr_agg_min            (unsigned char)85\r
+#define blr_agg_total          (unsigned char)86\r
+#define blr_agg_average                (unsigned char)87\r
+#define        blr_parameter3          (unsigned char)88       /* same as Rdb definition */\r
+#define blr_run_max            (unsigned char)89\r
+#define blr_run_min            (unsigned char)90\r
+#define blr_run_total          (unsigned char)91\r
+#define blr_run_average                (unsigned char)92\r
+#define blr_agg_count2         (unsigned char)93\r
+#define blr_agg_count_distinct (unsigned char)94\r
+#define blr_agg_total_distinct (unsigned char)95\r
+#define blr_agg_average_distinct (unsigned char)96\r
+\r
+#define blr_function           (unsigned char)100\r
+#define blr_gen_id             (unsigned char)101\r
+#define blr_prot_mask          (unsigned char)102\r
+#define blr_upcase             (unsigned char)103\r
+#define blr_lock_state         (unsigned char)104\r
+#define blr_value_if           (unsigned char)105\r
+#define blr_matching2          (unsigned char)106\r
+#define blr_index              (unsigned char)107\r
+#define blr_ansi_like          (unsigned char)108\r
+#define blr_bookmark           (unsigned char)109\r
+#define blr_crack              (unsigned char)110\r
+#define blr_force_crack                (unsigned char)111\r
+#define blr_seek               (unsigned char)112\r
+#define blr_find               (unsigned char)113\r
+                                 \r
+/* these indicate directions for blr_seek and blr_find */\r
+\r
+#define blr_continue           (unsigned char)0\r
+#define blr_forward            (unsigned char)1\r
+#define blr_backward           (unsigned char)2\r
+#define blr_bof_forward                (unsigned char)3\r
+#define blr_eof_backward       (unsigned char)4\r
+\r
+#define blr_lock_relation      (unsigned char)114\r
+#define blr_lock_record                (unsigned char)115\r
+#define blr_set_bookmark       (unsigned char)116\r
+#define blr_get_bookmark       (unsigned char)117\r
+\r
+#define blr_run_count          (unsigned char)118      /* changed from 88 to avoid conflict with blr_parameter3 */\r
+#define blr_rs_stream          (unsigned char)119\r
+#define blr_exec_proc          (unsigned char)120\r
+#define blr_begin_range        (unsigned char)121\r
+#define blr_end_range          (unsigned char)122\r
+#define blr_delete_range       (unsigned char)123\r
+#define blr_procedure          (unsigned char)124\r
+#define blr_pid                        (unsigned char)125\r
+#define blr_exec_pid           (unsigned char)126\r
+#define blr_singular           (unsigned char)127\r
+#define blr_abort              (unsigned char)128\r
+#define blr_block              (unsigned char)129\r
+#define blr_error_handler      (unsigned char)130\r
+\r
+#define blr_cast               (unsigned char)131\r
+#define blr_release_lock       (unsigned char)132\r
+#define blr_release_locks      (unsigned char)133\r
+#define blr_start_savepoint    (unsigned char)134\r
+#define blr_end_savepoint      (unsigned char)135\r
+#define blr_find_dbkey         (unsigned char)136\r
+#define blr_range_relation     (unsigned char)137\r
+#define blr_delete_ranges      (unsigned char)138\r
+\r
+#define blr_plan               (unsigned char)139      /* access plan items */\r
+#define blr_merge              (unsigned char)140\r
+#define blr_join               (unsigned char)141\r
+#define blr_sequential         (unsigned char)142\r
+#define blr_navigational       (unsigned char)143\r
+#define blr_indices            (unsigned char)144\r
+#define blr_retrieve           (unsigned char)145\r
+\r
+#define blr_relation2          (unsigned char)146\r
+#define blr_rid2               (unsigned char)147\r
+#define blr_reset_stream       (unsigned char)148\r
+#define blr_release_bookmark   (unsigned char)149\r
+\r
+#define blr_set_generator       (unsigned char)150\r
+\r
+#define blr_ansi_any           (unsigned char)151   /* required for NULL handling */\r
+#define blr_exists             (unsigned char)152   /* required for NULL handling */\r
+#define blr_cardinality                (unsigned char)153\r
+\r
+#define blr_record_version     (unsigned char)154      /* get tid of record */\r
+#define blr_stall              (unsigned char)155      /* fake server stall */\r
+\r
+#define blr_seek_no_warn       (unsigned char)156      \r
+#define blr_find_dbkey_version (unsigned char)157   /* find dbkey with record version */\r
+#define blr_ansi_all           (unsigned char)158   /* required for NULL handling */\r
+\r
+#define blr_extract            (unsigned char)159\r
+\r
+/* sub parameters for blr_extract */\r
+\r
+#define blr_extract_year       (unsigned char)0\r
+#define blr_extract_month      (unsigned char)1\r
+#define blr_extract_day                (unsigned char)2\r
+#define blr_extract_hour       (unsigned char)3\r
+#define blr_extract_minute     (unsigned char)4\r
+#define blr_extract_second     (unsigned char)5\r
+#define blr_extract_weekday    (unsigned char)6\r
+#define blr_extract_yearday    (unsigned char)7\r
+\r
+#define blr_current_date       (unsigned char)160\r
+#define blr_current_timestamp  (unsigned char)161\r
+#define blr_current_time       (unsigned char)162\r
+\r
+/* FB 1.0 specific BLR */\r
+\r
+#define blr_current_role       (unsigned char)174\r
+#define blr_skip               (unsigned char)175\r
+\r
+/* FB 1.5 specific BLR */\r
+\r
+#define blr_exec_sql           (unsigned char)176\r
+#define blr_internal_info      (unsigned char)177\r
+#define blr_nullsfirst         (unsigned char)178\r
+#define blr_writelock          (unsigned char)179\r
+#define blr_nullslast       (unsigned char)180\r
+\r
+/* These codes reuse BLR code space */\r
+\r
+#define blr_post_arg           (unsigned char)163\r
+#define blr_exec_into          (unsigned char)164\r
+#define blr_user_savepoint     (unsigned char)165\r
+\r
+/* These codes are actions for user-defined savepoints */\r
+\r
+#define blr_savepoint_set      (unsigned char)0\r
+#define blr_savepoint_release  (unsigned char)1\r
+#define blr_savepoint_undo     (unsigned char)2\r
+#define blr_savepoint_release_single   (unsigned char)3\r
+\r
+#endif /* _JRD_BLR_H_ */\r
+\r
+\r
+/**********************************/\r
+/* Database parameter block stuff */\r
+/**********************************/\r
+\r
+#define isc_dpb_version1                  1\r
+#define isc_dpb_cdd_pathname              1\r
+#define isc_dpb_allocation                2\r
+#define isc_dpb_journal                   3\r
+#define isc_dpb_page_size                 4\r
+#define isc_dpb_num_buffers               5\r
+#define isc_dpb_buffer_length             6\r
+#define isc_dpb_debug                     7\r
+#define isc_dpb_garbage_collect           8\r
+#define isc_dpb_verify                    9\r
+#define isc_dpb_sweep                     10\r
+#define isc_dpb_enable_journal            11\r
+#define isc_dpb_disable_journal           12\r
+#define isc_dpb_dbkey_scope               13\r
+#define isc_dpb_number_of_users           14\r
+#define isc_dpb_trace                     15\r
+#define isc_dpb_no_garbage_collect        16\r
+#define isc_dpb_damaged                   17\r
+#define isc_dpb_license                   18\r
+#define isc_dpb_sys_user_name             19\r
+#define isc_dpb_encrypt_key               20\r
+#define isc_dpb_activate_shadow           21\r
+#define isc_dpb_sweep_interval            22\r
+#define isc_dpb_delete_shadow             23\r
+#define isc_dpb_force_write               24\r
+#define isc_dpb_begin_log                 25\r
+#define isc_dpb_quit_log                  26\r
+#define isc_dpb_no_reserve                27\r
+#define isc_dpb_user_name                 28\r
+#define isc_dpb_password                  29\r
+#define isc_dpb_password_enc              30\r
+#define isc_dpb_sys_user_name_enc         31\r
+#define isc_dpb_interp                    32\r
+#define isc_dpb_online_dump               33\r
+#define isc_dpb_old_file_size             34\r
+#define isc_dpb_old_num_files             35\r
+#define isc_dpb_old_file                  36\r
+#define isc_dpb_old_start_page            37\r
+#define isc_dpb_old_start_seqno           38\r
+#define isc_dpb_old_start_file            39\r
+#define isc_dpb_drop_walfile              40\r
+#define isc_dpb_old_dump_id               41\r
+#define isc_dpb_wal_backup_dir            42\r
+#define isc_dpb_wal_chkptlen              43\r
+#define isc_dpb_wal_numbufs               44\r
+#define isc_dpb_wal_bufsize               45\r
+#define isc_dpb_wal_grp_cmt_wait          46\r
+#define isc_dpb_lc_messages               47\r
+#define isc_dpb_lc_ctype                  48\r
+#define isc_dpb_cache_manager            49\r
+#define isc_dpb_shutdown                 50\r
+#define isc_dpb_online                   51\r
+#define isc_dpb_shutdown_delay           52\r
+#define isc_dpb_reserved                 53\r
+#define isc_dpb_overwrite                54\r
+#define isc_dpb_sec_attach               55\r
+#define isc_dpb_disable_wal              56\r
+#define isc_dpb_connect_timeout           57\r
+#define isc_dpb_dummy_packet_interval     58\r
+#define isc_dpb_gbak_attach               59\r
+#define isc_dpb_sql_role_name             60\r
+#define isc_dpb_set_page_buffers          61\r
+#define isc_dpb_working_directory         62\r
+#define isc_dpb_sql_dialect               63\r
+#define isc_dpb_set_db_readonly           64\r
+#define isc_dpb_set_db_sql_dialect        65\r
+#define isc_dpb_gfix_attach              66\r
+#define isc_dpb_gstat_attach             67\r
+#define isc_dpb_set_db_charset                 68\r
+\r
+/*********************************/\r
+/* isc_dpb_verify specific flags */\r
+/*********************************/\r
+\r
+#define isc_dpb_pages                     1\r
+#define isc_dpb_records                   2\r
+#define isc_dpb_indices                   4\r
+#define isc_dpb_transactions              8\r
+#define isc_dpb_no_update                 16\r
+#define isc_dpb_repair                    32\r
+#define isc_dpb_ignore                    64\r
+\r
+/***********************************/\r
+/* isc_dpb_shutdown specific flags */\r
+/***********************************/\r
+\r
+#define isc_dpb_shut_cache               1\r
+#define isc_dpb_shut_attachment          2\r
+#define isc_dpb_shut_transaction         4\r
+#define isc_dpb_shut_force               8\r
+\r
+/**************************************/\r
+/* Bit assignments in RDB$SYSTEM_FLAG */\r
+/**************************************/\r
+\r
+#define RDB_system                         1\r
+#define RDB_id_assigned                    2\r
+\r
+\r
+/*************************************/\r
+/* Transaction parameter block stuff */\r
+/*************************************/\r
+\r
+#define isc_tpb_version1                  1\r
+#define isc_tpb_version3                  3\r
+#define isc_tpb_consistency               1\r
+#define isc_tpb_concurrency               2\r
+#define isc_tpb_shared                    3\r
+#define isc_tpb_protected                 4\r
+#define isc_tpb_exclusive                 5\r
+#define isc_tpb_wait                      6\r
+#define isc_tpb_nowait                    7\r
+#define isc_tpb_read                      8\r
+#define isc_tpb_write                     9\r
+#define isc_tpb_lock_read                 10\r
+#define isc_tpb_lock_write                11\r
+#define isc_tpb_verb_time                 12\r
+#define isc_tpb_commit_time               13\r
+#define isc_tpb_ignore_limbo              14\r
+#define isc_tpb_read_committed           15\r
+#define isc_tpb_autocommit               16\r
+#define isc_tpb_rec_version              17\r
+#define isc_tpb_no_rec_version           18\r
+#define isc_tpb_restart_requests         19\r
+#define isc_tpb_no_auto_undo              20\r
+\r
+\r
+/************************/\r
+/* Blob Parameter Block */\r
+/************************/\r
+\r
+#define isc_bpb_version1                  1\r
+#define isc_bpb_source_type               1\r
+#define isc_bpb_target_type               2\r
+#define isc_bpb_type                      3\r
+#define isc_bpb_source_interp             4\r
+#define isc_bpb_target_interp             5\r
+#define isc_bpb_filter_parameter          6\r
+\r
+#define isc_bpb_type_segmented            0\r
+#define isc_bpb_type_stream               1\r
+\r
+\r
+/*********************************/\r
+/* Service parameter block stuff */\r
+/*********************************/\r
+\r
+#define isc_spb_version1                  1\r
+#define isc_spb_current_version           2\r
+#define isc_spb_version                          isc_spb_current_version\r
+#define isc_spb_user_name                 isc_dpb_user_name\r
+#define isc_spb_sys_user_name             isc_dpb_sys_user_name\r
+#define isc_spb_sys_user_name_enc         isc_dpb_sys_user_name_enc\r
+#define isc_spb_password                  isc_dpb_password\r
+#define isc_spb_password_enc              isc_dpb_password_enc\r
+#define isc_spb_command_line              105\r
+#define isc_spb_dbname                    106\r
+#define isc_spb_verbose                   107\r
+#define isc_spb_options                   108\r
+\r
+#define isc_spb_connect_timeout           isc_dpb_connect_timeout\r
+#define isc_spb_dummy_packet_interval     isc_dpb_dummy_packet_interval\r
+#define isc_spb_sql_role_name             isc_dpb_sql_role_name\r
+\r
+\r
+/*********************************/\r
+/* Information call declarations */\r
+/*********************************/\r
+\r
+/****************************/\r
+/* Common, structural codes */\r
+/****************************/\r
+\r
+#define isc_info_end                      1\r
+#define isc_info_truncated                2\r
+#define isc_info_error                    3\r
+#define isc_info_data_not_ready                  4\r
+#define isc_info_flag_end                127\r
+\r
+/******************************/\r
+/* Database information items */\r
+/******************************/\r
+\r
+enum db_info_types\r
+    {\r
+       isc_info_db_id = 4,\r
+       isc_info_reads = 5,\r
+       isc_info_writes = 6,\r
+       isc_info_fetches = 7,\r
+       isc_info_marks = 8,\r
+\r
+       isc_info_implementation = 11,\r
+       isc_info_isc_version = 12,\r
+       isc_info_base_level = 13,\r
+       isc_info_page_size = 14,\r
+       isc_info_num_buffers = 15,\r
+       isc_info_limbo = 16,\r
+       isc_info_current_memory = 17,\r
+       isc_info_max_memory = 18,\r
+       isc_info_window_turns = 19,\r
+       isc_info_license = 20,   \r
+\r
+       isc_info_allocation = 21,\r
+       isc_info_attachment_id = 22,\r
+       isc_info_read_seq_count = 23,\r
+       isc_info_read_idx_count = 24,\r
+       isc_info_insert_count = 25,\r
+       isc_info_update_count = 26,\r
+       isc_info_delete_count = 27,\r
+       isc_info_backout_count = 28,\r
+       isc_info_purge_count = 29,\r
+       isc_info_expunge_count = 30, \r
+\r
+       isc_info_sweep_interval = 31,\r
+       isc_info_ods_version = 32,\r
+       isc_info_ods_minor_version = 33,\r
+       isc_info_no_reserve = 34,\r
+       isc_info_logfile = 35,\r
+       isc_info_cur_logfile_name = 36,\r
+       isc_info_cur_log_part_offset = 37,\r
+       isc_info_num_wal_buffers = 38,\r
+       isc_info_wal_buffer_size = 39,\r
+       isc_info_wal_ckpt_length = 40,   \r
+\r
+       isc_info_wal_cur_ckpt_interval = 41,  \r
+       isc_info_wal_prv_ckpt_fname = 42,\r
+       isc_info_wal_prv_ckpt_poffset = 43,\r
+       isc_info_wal_recv_ckpt_fname = 44,\r
+       isc_info_wal_recv_ckpt_poffset = 45,\r
+       isc_info_wal_grpc_wait_usecs = 47,\r
+       isc_info_wal_num_io = 48,\r
+       isc_info_wal_avg_io_size = 49,\r
+       isc_info_wal_num_commits = 50,  \r
+\r
+       isc_info_wal_avg_grpc_size = 51,\r
+       isc_info_forced_writes = 52,\r
+       isc_info_user_names = 53,\r
+       isc_info_page_errors = 54,\r
+       isc_info_record_errors = 55,\r
+       isc_info_bpage_errors = 56,\r
+       isc_info_dpage_errors = 57,\r
+       isc_info_ipage_errors = 58,\r
+       isc_info_ppage_errors = 59,\r
+       isc_info_tpage_errors = 60,\r
+\r
+       isc_info_set_page_buffers = 61,\r
+       isc_info_db_sql_dialect = 62,   \r
+       isc_info_db_read_only = 63,\r
+       isc_info_db_size_in_pages = 64,\r
+\r
+    /* Values 65 -100 unused to avoid conflict with InterBase */\r
+       \r
+       frb_info_att_charset = 101,\r
+       isc_info_db_class = 102,\r
+       isc_info_firebird_version = 103,\r
+       isc_info_oldest_transaction = 104,\r
+       isc_info_oldest_active = 105,\r
+       isc_info_oldest_snapshot = 106,\r
+       isc_info_next_transaction = 107,\r
+       isc_info_db_provider = 108,\r
+       isc_info_active_transactions = 109,\r
+\r
+       isc_info_db_last_value   /* Leave this LAST! */\r
+    };\r
+\r
+#define isc_info_version isc_info_isc_version\r
+\r
+\r
+/**************************************/\r
+/* Database information return values */\r
+/**************************************/\r
+\r
+enum  info_db_implementations\r
+    {\r
+       isc_info_db_impl_rdb_vms = 1,\r
+       isc_info_db_impl_rdb_eln = 2,\r
+       isc_info_db_impl_rdb_eln_dev = 3,\r
+       isc_info_db_impl_rdb_vms_y = 4,\r
+       isc_info_db_impl_rdb_eln_y = 5,\r
+       isc_info_db_impl_jri = 6,\r
+       isc_info_db_impl_jsv = 7,\r
+\r
+       isc_info_db_impl_isc_apl_68K = 25,\r
+       isc_info_db_impl_isc_vax_ultr = 26,\r
+       isc_info_db_impl_isc_vms = 27,\r
+       isc_info_db_impl_isc_sun_68k = 28,\r
+       isc_info_db_impl_isc_os2 = 29,\r
+       isc_info_db_impl_isc_sun4 = 30,    /* 30 */\r
+       \r
+       isc_info_db_impl_isc_hp_ux = 31,\r
+       isc_info_db_impl_isc_sun_386i = 32,\r
+       isc_info_db_impl_isc_vms_orcl = 33,\r
+       isc_info_db_impl_isc_mac_aux = 34,\r
+       isc_info_db_impl_isc_rt_aix = 35,\r
+       isc_info_db_impl_isc_mips_ult = 36,\r
+       isc_info_db_impl_isc_xenix = 37,\r
+       isc_info_db_impl_isc_dg = 38,\r
+       isc_info_db_impl_isc_hp_mpexl = 39,\r
+       isc_info_db_impl_isc_hp_ux68K = 40,       /* 40 */\r
+\r
+       isc_info_db_impl_isc_sgi = 41,\r
+       isc_info_db_impl_isc_sco_unix = 42,\r
+       isc_info_db_impl_isc_cray = 43,\r
+       isc_info_db_impl_isc_imp = 44,\r
+       isc_info_db_impl_isc_delta = 45,\r
+       isc_info_db_impl_isc_next = 46,\r
+       isc_info_db_impl_isc_dos = 47,\r
+       isc_info_db_impl_m88K = 48,\r
+       isc_info_db_impl_unixware = 49,\r
+       isc_info_db_impl_isc_winnt_x86 = 50,\r
+\r
+       isc_info_db_impl_isc_epson = 51,\r
+       isc_info_db_impl_alpha_osf = 52,\r
+       isc_info_db_impl_alpha_vms = 53,\r
+       isc_info_db_impl_netware_386 = 54, \r
+       isc_info_db_impl_win_only = 55,\r
+       isc_info_db_impl_ncr_3000 = 56,\r
+       isc_info_db_impl_winnt_ppc = 57,\r
+       isc_info_db_impl_dg_x86 = 58,\r
+       isc_info_db_impl_sco_ev = 59,\r
+       isc_info_db_impl_i386 = 60,\r
+\r
+       isc_info_db_impl_freebsd = 61,\r
+       isc_info_db_impl_netbsd = 62,\r
+       isc_info_db_impl_darwin = 63,\r
+       isc_info_db_impl_sinixz = 64,\r
+\r
+       isc_info_db_impl_linux_sparc = 65,\r
+       isc_info_db_impl_linux_amd64 = 66,\r
+\r
+       isc_info_db_impl_last_value   /* Leave this LAST! */\r
+    };\r
+\r
+#define isc_info_db_impl_isc_a            isc_info_db_impl_isc_apl_68K\r
+#define isc_info_db_impl_isc_u            isc_info_db_impl_isc_vax_ultr\r
+#define isc_info_db_impl_isc_v            isc_info_db_impl_isc_vms\r
+#define isc_info_db_impl_isc_s            isc_info_db_impl_isc_sun_68k\r
+\r
+\r
+enum info_db_class\r
+    {\r
+       isc_info_db_class_access = 1,\r
+       isc_info_db_class_y_valve = 2,\r
+       isc_info_db_class_rem_int = 3,\r
+       isc_info_db_class_rem_srvr = 4,\r
+       isc_info_db_class_pipe_int = 7,\r
+       isc_info_db_class_pipe_srvr = 8,\r
+       isc_info_db_class_sam_int = 9,\r
+       isc_info_db_class_sam_srvr = 10,\r
+       isc_info_db_class_gateway = 11,\r
+       isc_info_db_class_cache = 12,\r
+       isc_info_db_class_classic_access = 13,\r
+       isc_info_db_class_server_access = 14,\r
+\r
+       isc_info_db_class_last_value   /* Leave this LAST! */\r
+    };\r
+\r
+enum info_db_provider\r
+    {\r
+       isc_info_db_code_rdb_eln = 1,\r
+       isc_info_db_code_rdb_vms = 2,\r
+       isc_info_db_code_interbase = 3,\r
+       isc_info_db_code_firebird = 4,\r
+\r
+       isc_info_db_code_last_value   /* Leave this LAST! */\r
+    };\r
+\r
+\r
+/*****************************/\r
+/* Request information items */\r
+/*****************************/\r
+\r
+#define isc_info_number_messages          4\r
+#define isc_info_max_message              5\r
+#define isc_info_max_send                 6\r
+#define isc_info_max_receive              7\r
+#define isc_info_state                    8\r
+#define isc_info_message_number           9\r
+#define isc_info_message_size             10\r
+#define isc_info_request_cost             11\r
+#define isc_info_access_path              12\r
+#define isc_info_req_select_count         13\r
+#define isc_info_req_insert_count         14\r
+#define isc_info_req_update_count         15\r
+#define isc_info_req_delete_count         16\r
+\r
+\r
+/*********************/\r
+/* Access path items */\r
+/*********************/\r
+\r
+#define isc_info_rsb_end                  0\r
+#define isc_info_rsb_begin                1\r
+#define isc_info_rsb_type                 2\r
+#define isc_info_rsb_relation             3\r
+#define isc_info_rsb_plan                  4\r
+\r
+/*************/\r
+/* Rsb types */\r
+/*************/\r
+\r
+#define isc_info_rsb_unknown              1\r
+#define isc_info_rsb_indexed              2\r
+#define isc_info_rsb_navigate             3\r
+#define isc_info_rsb_sequential                   4\r
+#define isc_info_rsb_cross                5\r
+#define isc_info_rsb_sort                 6\r
+#define isc_info_rsb_first                7\r
+#define isc_info_rsb_boolean              8\r
+#define isc_info_rsb_union                9\r
+#define isc_info_rsb_aggregate           10\r
+#define isc_info_rsb_merge               11\r
+#define isc_info_rsb_ext_sequential      12\r
+#define isc_info_rsb_ext_indexed         13\r
+#define isc_info_rsb_ext_dbkey           14\r
+#define isc_info_rsb_left_cross                  15\r
+#define isc_info_rsb_select              16\r
+#define isc_info_rsb_sql_join            17\r
+#define isc_info_rsb_simulate            18\r
+#define isc_info_rsb_sim_cross           19\r
+#define isc_info_rsb_once                20\r
+#define isc_info_rsb_procedure           21\r
+\r
+/**********************/\r
+/* Bitmap expressions */\r
+/**********************/\r
+\r
+#define isc_info_rsb_and               1\r
+#define isc_info_rsb_or                        2\r
+#define isc_info_rsb_dbkey             3\r
+#define isc_info_rsb_index             4\r
+\r
+#define isc_info_req_active               2\r
+#define isc_info_req_inactive             3\r
+#define isc_info_req_send                 4\r
+#define isc_info_req_receive              5\r
+#define isc_info_req_select               6\r
+#define isc_info_req_sql_stall           7\r
+\r
+/**************************/\r
+/* Blob information items */\r
+/**************************/\r
+\r
+#define isc_info_blob_num_segments        4\r
+#define isc_info_blob_max_segment         5\r
+#define isc_info_blob_total_length        6\r
+#define isc_info_blob_type                7\r
+\r
+/*********************************/\r
+/* Transaction information items */\r
+/*********************************/\r
+\r
+#define isc_info_tra_id                   4\r
+\r
+/*****************************\r
+ * Service action items      *\r
+ *****************************/\r
+\r
+#define isc_action_svc_backup          1       /* Starts database backup process on the server */\r
+#define isc_action_svc_restore         2       /* Starts database restore process on the server */\r
+#define isc_action_svc_repair          3       /* Starts database repair process on the server */\r
+#define isc_action_svc_add_user        4       /* Adds a new user to the security database */\r
+#define isc_action_svc_delete_user     5       /* Deletes a user record from the security database */\r
+#define isc_action_svc_modify_user     6       /* Modifies a user record in the security database */\r
+#define isc_action_svc_display_user    7       /* Displays a user record from the security database */\r
+#define isc_action_svc_properties      8       /* Sets database properties */\r
+#define isc_action_svc_add_license     9       /* Adds a license to the license file */\r
+#define isc_action_svc_remove_license 10       /* Removes a license from the license file */\r
+#define isc_action_svc_db_stats              11        /* Retrieves database statistics */\r
+#define isc_action_svc_get_ib_log     12       /* Retrieves the InterBase log file from the server */\r
+\r
+/*****************************\r
+ * Service information items *\r
+ *****************************/\r
+\r
+#define isc_info_svc_svr_db_info      50       /* Retrieves the number of attachments and databases */\r
+#define isc_info_svc_get_license      51       /* Retrieves all license keys and IDs from the license file */\r
+#define isc_info_svc_get_license_mask 52       /* Retrieves a bitmask representing licensed options on the server */\r
+#define isc_info_svc_get_config       53       /* Retrieves the parameters and values for IB_CONFIG */\r
+#define isc_info_svc_version          54       /* Retrieves the version of the services manager */\r
+#define isc_info_svc_server_version   55       /* Retrieves the version of the InterBase server */\r
+#define isc_info_svc_implementation   56       /* Retrieves the implementation of the InterBase server */\r
+#define isc_info_svc_capabilities     57       /* Retrieves a bitmask representing the server's capabilities */\r
+#define isc_info_svc_user_dbpath      58       /* Retrieves the path to the security database in use by the server */\r
+#define isc_info_svc_get_env         59        /* Retrieves the setting of $INTERBASE */\r
+#define isc_info_svc_get_env_lock     60       /* Retrieves the setting of $INTERBASE_LCK */\r
+#define isc_info_svc_get_env_msg      61       /* Retrieves the setting of $INTERBASE_MSG */\r
+#define isc_info_svc_line             62       /* Retrieves 1 line of service output per call */\r
+#define isc_info_svc_to_eof           63       /* Retrieves as much of the server output as will fit in the supplied buffer */\r
+#define isc_info_svc_timeout          64       /* Sets / signifies a timeout value for reading service information */\r
+#define isc_info_svc_get_licensed_users 65     /* Retrieves the number of users licensed for accessing the server */\r
+#define isc_info_svc_limbo_trans       66      /* Retrieve the limbo transactions */\r
+#define isc_info_svc_running           67      /* Checks to see if a service is running on an attachment */\r
+#define isc_info_svc_get_users         68      /* Returns the user information from isc_action_svc_display_users */\r
+\r
+/******************************************************\r
+ * Parameters for isc_action_{add|delete|modify)_user *\r
+ ******************************************************/\r
+\r
+#define isc_spb_sec_userid            5\r
+#define isc_spb_sec_groupid           6\r
+#define isc_spb_sec_username          7\r
+#define isc_spb_sec_password          8\r
+#define isc_spb_sec_groupname         9\r
+#define isc_spb_sec_firstname         10\r
+#define isc_spb_sec_middlename        11\r
+#define isc_spb_sec_lastname          12\r
+\r
+/*******************************************************\r
+ * Parameters for isc_action_svc_(add|remove)_license, *\r
+ * isc_info_svc_get_license                            *\r
+ *******************************************************/\r
+\r
+#define isc_spb_lic_key               5\r
+#define isc_spb_lic_id                6\r
+#define isc_spb_lic_desc              7\r
+\r
+\r
+/*****************************************\r
+ * Parameters for isc_action_svc_backup  *\r
+ *****************************************/\r
+\r
+#define isc_spb_bkp_file                 5\r
+#define isc_spb_bkp_factor               6\r
+#define isc_spb_bkp_length               7\r
+#define isc_spb_bkp_ignore_checksums     0x01\r
+#define isc_spb_bkp_ignore_limbo         0x02\r
+#define isc_spb_bkp_metadata_only        0x04\r
+#define isc_spb_bkp_no_garbage_collect   0x08\r
+#define isc_spb_bkp_old_descriptions     0x10\r
+#define isc_spb_bkp_non_transportable    0x20\r
+#define isc_spb_bkp_convert              0x40\r
+#define isc_spb_bkp_expand              0x80\r
+\r
+/********************************************\r
+ * Parameters for isc_action_svc_properties *\r
+ ********************************************/\r
+\r
+#define isc_spb_prp_page_buffers               5\r
+#define isc_spb_prp_sweep_interval             6\r
+#define isc_spb_prp_shutdown_db                        7\r
+#define isc_spb_prp_deny_new_attachments       9\r
+#define isc_spb_prp_deny_new_transactions      10\r
+#define isc_spb_prp_reserve_space              11\r
+#define isc_spb_prp_write_mode                 12\r
+#define isc_spb_prp_access_mode                        13\r
+#define isc_spb_prp_set_sql_dialect            14\r
+#define isc_spb_prp_activate                   0x0100\r
+#define isc_spb_prp_db_online                  0x0200\r
+\r
+/********************************************\r
+ * Parameters for isc_spb_prp_reserve_space *\r
+ ********************************************/\r
+\r
+#define isc_spb_prp_res_use_full       35\r
+#define isc_spb_prp_res                        36\r
+\r
+/******************************************\r
+ * Parameters for isc_spb_prp_write_mode  *\r
+ ******************************************/\r
+\r
+#define isc_spb_prp_wm_async           37\r
+#define isc_spb_prp_wm_sync                    38\r
+\r
+/******************************************\r
+ * Parameters for isc_spb_prp_access_mode *\r
+ ******************************************/\r
+\r
+#define isc_spb_prp_am_readonly                39\r
+#define isc_spb_prp_am_readwrite       40\r
+\r
+/*****************************************\r
+ * Parameters for isc_action_svc_repair  *\r
+ *****************************************/\r
+\r
+#define isc_spb_rpr_commit_trans               15\r
+#define isc_spb_rpr_rollback_trans             34\r
+#define isc_spb_rpr_recover_two_phase  17\r
+#define isc_spb_tra_id                                 18\r
+#define isc_spb_single_tra_id                  19\r
+#define isc_spb_multi_tra_id                   20\r
+#define isc_spb_tra_state                              21\r
+#define isc_spb_tra_state_limbo                        22\r
+#define isc_spb_tra_state_commit               23\r
+#define isc_spb_tra_state_rollback             24\r
+#define isc_spb_tra_state_unknown              25\r
+#define isc_spb_tra_host_site                  26\r
+#define isc_spb_tra_remote_site                        27\r
+#define isc_spb_tra_db_path                            28\r
+#define isc_spb_tra_advise                             29\r
+#define isc_spb_tra_advise_commit              30\r
+#define isc_spb_tra_advise_rollback            31\r
+#define isc_spb_tra_advise_unknown             33\r
+\r
+#define isc_spb_rpr_validate_db                        0x01\r
+#define isc_spb_rpr_sweep_db                   0x02\r
+#define isc_spb_rpr_mend_db                            0x04\r
+#define isc_spb_rpr_list_limbo_trans   0x08\r
+#define isc_spb_rpr_check_db                   0x10\r
+#define isc_spb_rpr_ignore_checksum            0x20\r
+#define isc_spb_rpr_kill_shadows               0x40\r
+#define isc_spb_rpr_full                               0x80\r
+\r
+/*****************************************\r
+ * Parameters for isc_action_svc_restore *\r
+ *****************************************/\r
+\r
+#define isc_spb_res_buffers                            9\r
+#define isc_spb_res_page_size                  10\r
+#define isc_spb_res_length                             11\r
+#define isc_spb_res_access_mode                        12\r
+#define isc_spb_res_deactivate_idx             0x0100\r
+#define isc_spb_res_no_shadow                  0x0200\r
+#define isc_spb_res_no_validity                        0x0400\r
+#define isc_spb_res_one_at_a_time              0x0800\r
+#define isc_spb_res_replace                            0x1000\r
+#define isc_spb_res_create                             0x2000\r
+#define isc_spb_res_use_all_space              0x4000\r
+\r
+/******************************************\r
+ * Parameters for isc_spb_res_access_mode  *\r
+ ******************************************/\r
+\r
+#define isc_spb_res_am_readonly                        isc_spb_prp_am_readonly\r
+#define isc_spb_res_am_readwrite               isc_spb_prp_am_readwrite\r
+\r
+/*******************************************\r
+ * Parameters for isc_info_svc_svr_db_info *\r
+ *******************************************/\r
+\r
+#define isc_spb_num_att                        5\r
+#define isc_spb_num_db                 6\r
+\r
+/*****************************************\r
+ * Parameters for isc_info_svc_db_stats  *\r
+ *****************************************/\r
+\r
+#define isc_spb_sts_data_pages         0x01\r
+#define isc_spb_sts_db_log                     0x02\r
+#define isc_spb_sts_hdr_pages          0x04\r
+#define isc_spb_sts_idx_pages          0x08\r
+#define isc_spb_sts_sys_relations      0x10\r
+#define isc_spb_sts_record_versions    0x20\r
+#define isc_spb_sts_table                      0x40\r
+\r
+/*************************/\r
+/* SQL information items */\r
+/*************************/\r
+\r
+#define isc_info_sql_select               4\r
+#define isc_info_sql_bind                 5\r
+#define isc_info_sql_num_variables        6\r
+#define isc_info_sql_describe_vars        7\r
+#define isc_info_sql_describe_end         8\r
+#define isc_info_sql_sqlda_seq            9\r
+#define isc_info_sql_message_seq          10\r
+#define isc_info_sql_type                 11\r
+#define isc_info_sql_sub_type             12\r
+#define isc_info_sql_scale                13\r
+#define isc_info_sql_length               14\r
+#define isc_info_sql_null_ind             15\r
+#define isc_info_sql_field                16\r
+#define isc_info_sql_relation             17\r
+#define isc_info_sql_owner                18\r
+#define isc_info_sql_alias                19\r
+#define isc_info_sql_sqlda_start          20\r
+#define isc_info_sql_stmt_type            21\r
+#define isc_info_sql_get_plan             22\r
+#define isc_info_sql_records             23\r
+#define isc_info_sql_batch_fetch         24\r
+\r
+/*********************************/\r
+/* SQL information return values */\r
+/*********************************/\r
+\r
+#define isc_info_sql_stmt_select          1\r
+#define isc_info_sql_stmt_insert          2\r
+#define isc_info_sql_stmt_update          3\r
+#define isc_info_sql_stmt_delete          4\r
+#define isc_info_sql_stmt_ddl             5\r
+#define isc_info_sql_stmt_get_segment     6\r
+#define isc_info_sql_stmt_put_segment     7\r
+#define isc_info_sql_stmt_exec_procedure  8\r
+#define isc_info_sql_stmt_start_trans     9\r
+#define isc_info_sql_stmt_commit          10\r
+#define isc_info_sql_stmt_rollback        11\r
+#define isc_info_sql_stmt_select_for_upd  12\r
+#define isc_info_sql_stmt_set_generator   13\r
+#define isc_info_sql_stmt_savepoint       14\r
+\r
+\r
+/***********************************/\r
+/* Server configuration key values */\r
+/***********************************/\r
+\r
+/* Not available in Firebird 1.5 */\r
+\r
+\r
+/**********************************************/\r
+/* Dynamic Data Definition Language operators */\r
+/**********************************************/\r
+\r
+/******************/\r
+/* Version number */\r
+/******************/\r
+\r
+#define isc_dyn_version_1                 1\r
+#define isc_dyn_eoc                       255\r
+\r
+/******************************/\r
+/* Operations (may be nested) */\r
+/******************************/\r
+\r
+#define isc_dyn_begin                     2\r
+#define isc_dyn_end                       3\r
+#define isc_dyn_if                        4\r
+#define isc_dyn_def_database              5\r
+#define isc_dyn_def_global_fld            6\r
+#define isc_dyn_def_local_fld             7\r
+#define isc_dyn_def_idx                   8\r
+#define isc_dyn_def_rel                   9\r
+#define isc_dyn_def_sql_fld               10\r
+#define isc_dyn_def_view                  12\r
+#define isc_dyn_def_trigger               15\r
+#define isc_dyn_def_security_class        120\r
+#define isc_dyn_def_dimension             140\r
+#define isc_dyn_def_generator             24\r
+#define isc_dyn_def_function              25\r
+#define isc_dyn_def_filter                26\r
+#define isc_dyn_def_function_arg          27\r
+#define isc_dyn_def_shadow                34\r
+#define isc_dyn_def_trigger_msg           17\r
+#define isc_dyn_def_file                  36\r
+#define isc_dyn_mod_database              39\r
+#define isc_dyn_mod_rel                   11\r
+#define isc_dyn_mod_global_fld            13\r
+#define isc_dyn_mod_idx                   102\r
+#define isc_dyn_mod_local_fld             14\r
+#define isc_dyn_mod_sql_fld              216\r
+#define isc_dyn_mod_view                  16\r
+#define isc_dyn_mod_security_class        122\r
+#define isc_dyn_mod_trigger               113\r
+#define isc_dyn_mod_trigger_msg           28\r
+#define isc_dyn_delete_database           18\r
+#define isc_dyn_delete_rel                19\r
+#define isc_dyn_delete_global_fld         20\r
+#define isc_dyn_delete_local_fld          21\r
+#define isc_dyn_delete_idx                22\r
+#define isc_dyn_delete_security_class     123\r
+#define isc_dyn_delete_dimensions         143\r
+#define isc_dyn_delete_trigger            23\r
+#define isc_dyn_delete_trigger_msg        29\r
+#define isc_dyn_delete_filter             32\r
+#define isc_dyn_delete_function           33\r
+#define isc_dyn_delete_shadow             35\r
+#define isc_dyn_grant                     30\r
+#define isc_dyn_revoke                    31\r
+#define isc_dyn_def_primary_key           37\r
+#define isc_dyn_def_foreign_key           38\r
+#define isc_dyn_def_unique                40\r
+#define isc_dyn_def_procedure             164\r
+#define isc_dyn_delete_procedure          165\r
+#define isc_dyn_def_parameter             135\r
+#define isc_dyn_delete_parameter          136\r
+#define isc_dyn_mod_procedure             175\r
+#define isc_dyn_def_log_file              176\r
+#define isc_dyn_def_cache_file            180\r
+#define isc_dyn_def_exception             181\r
+#define isc_dyn_mod_exception             182\r
+#define isc_dyn_del_exception             183\r
+#define isc_dyn_drop_log                  194\r
+#define isc_dyn_drop_cache                195\r
+#define isc_dyn_def_default_log           202\r
+\r
+/***********************/\r
+/* View specific stuff */\r
+/***********************/\r
+\r
+#define isc_dyn_view_blr                  43\r
+#define isc_dyn_view_source               44\r
+#define isc_dyn_view_relation             45\r
+#define isc_dyn_view_context              46\r
+#define isc_dyn_view_context_name         47\r
+\r
+/**********************/\r
+/* Generic attributes */\r
+/**********************/\r
+\r
+#define isc_dyn_rel_name                  50\r
+#define isc_dyn_fld_name                  51\r
+#define isc_dyn_new_fld_name             215\r
+#define isc_dyn_idx_name                  52\r
+#define isc_dyn_description               53\r
+#define isc_dyn_security_class            54\r
+#define isc_dyn_system_flag               55\r
+#define isc_dyn_update_flag               56\r
+#define isc_dyn_prc_name                  166\r
+#define isc_dyn_prm_name                  137\r
+#define isc_dyn_sql_object                196\r
+#define isc_dyn_fld_character_set_name    174\r
+\r
+/********************************/\r
+/* Relation specific attributes */\r
+/********************************/\r
+\r
+#define isc_dyn_rel_dbkey_length          61\r
+#define isc_dyn_rel_store_trig            62\r
+#define isc_dyn_rel_modify_trig           63\r
+#define isc_dyn_rel_erase_trig            64\r
+#define isc_dyn_rel_store_trig_source     65\r
+#define isc_dyn_rel_modify_trig_source    66\r
+#define isc_dyn_rel_erase_trig_source     67\r
+#define isc_dyn_rel_ext_file              68\r
+#define isc_dyn_rel_sql_protection        69\r
+#define isc_dyn_rel_constraint            162\r
+#define isc_dyn_delete_rel_constraint     163\r
+\r
+/************************************/\r
+/* Global field specific attributes */\r
+/************************************/\r
+\r
+#define isc_dyn_fld_type                  70\r
+#define isc_dyn_fld_length                71\r
+#define isc_dyn_fld_scale                 72\r
+#define isc_dyn_fld_sub_type              73\r
+#define isc_dyn_fld_segment_length        74\r
+#define isc_dyn_fld_query_header          75\r
+#define isc_dyn_fld_edit_string           76\r
+#define isc_dyn_fld_validation_blr        77\r
+#define isc_dyn_fld_validation_source     78\r
+#define isc_dyn_fld_computed_blr          79\r
+#define isc_dyn_fld_computed_source       80\r
+#define isc_dyn_fld_missing_value         81\r
+#define isc_dyn_fld_default_value         82\r
+#define isc_dyn_fld_query_name            83\r
+#define isc_dyn_fld_dimensions            84\r
+#define isc_dyn_fld_not_null              85\r
+#define isc_dyn_fld_precision             86\r
+#define isc_dyn_fld_char_length           172\r
+#define isc_dyn_fld_collation             173\r
+#define isc_dyn_fld_default_source        193\r
+#define isc_dyn_del_default               197\r
+#define isc_dyn_del_validation            198\r
+#define isc_dyn_single_validation         199\r
+#define isc_dyn_fld_character_set         203\r
+\r
+/***********************************/\r
+/* Local field specific attributes */\r
+/***********************************/\r
+\r
+#define isc_dyn_fld_source                90\r
+#define isc_dyn_fld_base_fld              91\r
+#define isc_dyn_fld_position              92\r
+#define isc_dyn_fld_update_flag           93\r
+\r
+/*****************************/\r
+/* Index specific attributes */\r
+/*****************************/\r
+\r
+#define isc_dyn_idx_unique                100\r
+#define isc_dyn_idx_inactive              101\r
+#define isc_dyn_idx_type                  103\r
+#define isc_dyn_idx_foreign_key           104\r
+#define isc_dyn_idx_ref_column            105\r
+#define isc_dyn_idx_statistic            204\r
+\r
+/*******************************/\r
+/* Trigger specific attributes */\r
+/*******************************/\r
+\r
+#define isc_dyn_trg_type                  110\r
+#define isc_dyn_trg_blr                   111\r
+#define isc_dyn_trg_source                112\r
+#define isc_dyn_trg_name                  114\r
+#define isc_dyn_trg_sequence              115\r
+#define isc_dyn_trg_inactive              116\r
+#define isc_dyn_trg_msg_number            117\r
+#define isc_dyn_trg_msg                   118\r
+\r
+/**************************************/\r
+/* Security Class specific attributes */\r
+/**************************************/\r
+\r
+#define isc_dyn_scl_acl                   121\r
+#define isc_dyn_grant_user                130\r
+#define isc_dyn_grant_user_explicit       219\r
+#define isc_dyn_grant_proc                186\r
+#define isc_dyn_grant_trig                187\r
+#define isc_dyn_grant_view                188\r
+#define isc_dyn_grant_options             132\r
+#define isc_dyn_grant_user_group          205\r
+#define isc_dyn_grant_role                218\r
+\r
+\r
+/**********************************/\r
+/* Dimension specific information */\r
+/**********************************/\r
+\r
+#define isc_dyn_dim_lower                 141\r
+#define isc_dyn_dim_upper                 142\r
+\r
+/****************************/\r
+/* File specific attributes */\r
+/****************************/\r
+\r
+#define isc_dyn_file_name                 125\r
+#define isc_dyn_file_start                126\r
+#define isc_dyn_file_length               127\r
+#define isc_dyn_shadow_number             128\r
+#define isc_dyn_shadow_man_auto           129\r
+#define isc_dyn_shadow_conditional        130\r
+\r
+/********************************/\r
+/* Log file specific attributes */\r
+/********************************/\r
+\r
+#define isc_dyn_log_file_sequence         177\r
+#define isc_dyn_log_file_partitions       178\r
+#define isc_dyn_log_file_serial           179\r
+#define isc_dyn_log_file_overflow         200\r
+#define isc_dyn_log_file_raw             201\r
+\r
+/***************************/\r
+/* Log specific attributes */\r
+/***************************/\r
+\r
+#define isc_dyn_log_group_commit_wait     189\r
+#define isc_dyn_log_buffer_size           190\r
+#define isc_dyn_log_check_point_length    191\r
+#define isc_dyn_log_num_of_buffers        192\r
+\r
+/********************************/\r
+/* Function specific attributes */\r
+/********************************/\r
+\r
+#define isc_dyn_function_name             145\r
+#define isc_dyn_function_type             146\r
+#define isc_dyn_func_module_name          147\r
+#define isc_dyn_func_entry_point          148\r
+#define isc_dyn_func_return_argument      149\r
+#define isc_dyn_func_arg_position         150\r
+#define isc_dyn_func_mechanism            151\r
+#define isc_dyn_filter_in_subtype         152\r
+#define isc_dyn_filter_out_subtype        153\r
+\r
+\r
+#define isc_dyn_description2             154\r
+#define isc_dyn_fld_computed_source2     155\r
+#define isc_dyn_fld_edit_string2         156\r
+#define isc_dyn_fld_query_header2        157\r
+#define isc_dyn_fld_validation_source2   158\r
+#define isc_dyn_trg_msg2                 159\r
+#define isc_dyn_trg_source2              160\r
+#define isc_dyn_view_source2             161\r
+#define isc_dyn_xcp_msg2                 184\r
+\r
+/*********************************/\r
+/* Generator specific attributes */\r
+/*********************************/\r
+\r
+#define isc_dyn_generator_name            95\r
+#define isc_dyn_generator_id              96\r
+\r
+/*********************************/\r
+/* Procedure specific attributes */\r
+/*********************************/\r
+\r
+#define isc_dyn_prc_inputs                167\r
+#define isc_dyn_prc_outputs               168\r
+#define isc_dyn_prc_source                169\r
+#define isc_dyn_prc_blr                   170\r
+#define isc_dyn_prc_source2               171\r
+\r
+/*********************************/\r
+/* Parameter specific attributes */\r
+/*********************************/\r
+\r
+#define isc_dyn_prm_number                138\r
+#define isc_dyn_prm_type                  139\r
+\r
+/********************************/\r
+/* Relation specific attributes */\r
+/********************************/\r
+\r
+#define isc_dyn_xcp_msg                   185\r
+\r
+/**********************************************/\r
+/* Cascading referential integrity values     */\r
+/**********************************************/\r
+#define isc_dyn_foreign_key_update        205\r
+#define isc_dyn_foreign_key_delete        206\r
+#define isc_dyn_foreign_key_cascade       207\r
+#define isc_dyn_foreign_key_default       208\r
+#define isc_dyn_foreign_key_null          209\r
+#define isc_dyn_foreign_key_none          210\r
+\r
+/***********************/\r
+/* SQL role values     */\r
+/***********************/\r
+#define isc_dyn_def_sql_role              211\r
+#define isc_dyn_sql_role_name             212\r
+#define isc_dyn_grant_admin_options       213\r
+#define isc_dyn_del_sql_role              214\r
+/* 215 & 216 are used some lines above. */\r
+\r
+/**********************************************/\r
+/* Generators again                           */\r
+/**********************************************/\r
+\r
+#ifndef __cplusplus                     /* c definitions */\r
+#define gds_dyn_delete_generator          217\r
+#else                                   /* c++ definitions */\r
+const unsigned char gds_dyn_delete_generator       = 217;\r
+#endif\r
+\r
+/****************************/\r
+/* Last $dyn value assigned */\r
+/****************************/\r
+\r
+#define isc_dyn_last_dyn_value            219\r
+\r
+/******************************************/\r
+/* Array slice description language (SDL) */\r
+/******************************************/\r
+\r
+#define isc_sdl_version1                  1\r
+#define isc_sdl_eoc                       255\r
+#define isc_sdl_relation                  2\r
+#define isc_sdl_rid                       3\r
+#define isc_sdl_field                     4\r
+#define isc_sdl_fid                       5\r
+#define isc_sdl_struct                    6\r
+#define isc_sdl_variable                  7\r
+#define isc_sdl_scalar                    8\r
+#define isc_sdl_tiny_integer              9\r
+#define isc_sdl_short_integer             10\r
+#define isc_sdl_long_integer              11\r
+#define isc_sdl_literal                   12\r
+#define isc_sdl_add                       13\r
+#define isc_sdl_subtract                  14\r
+#define isc_sdl_multiply                  15\r
+#define isc_sdl_divide                    16\r
+#define isc_sdl_negate                    17\r
+#define isc_sdl_eql                       18\r
+#define isc_sdl_neq                       19\r
+#define isc_sdl_gtr                       20\r
+#define isc_sdl_geq                       21\r
+#define isc_sdl_lss                       22\r
+#define isc_sdl_leq                       23\r
+#define isc_sdl_and                       24\r
+#define isc_sdl_or                        25\r
+#define isc_sdl_not                       26\r
+#define isc_sdl_while                     27\r
+#define isc_sdl_assignment                28\r
+#define isc_sdl_label                     29\r
+#define isc_sdl_leave                     30\r
+#define isc_sdl_begin                     31\r
+#define isc_sdl_end                       32\r
+#define isc_sdl_do3                       33\r
+#define isc_sdl_do2                       34\r
+#define isc_sdl_do1                       35\r
+#define isc_sdl_element                   36\r
+\r
+/********************************************/\r
+/* International text interpretation values */\r
+/********************************************/\r
+\r
+#define isc_interp_eng_ascii              0\r
+#define isc_interp_jpn_sjis               5\r
+#define isc_interp_jpn_euc                6\r
+\r
+/*******************/\r
+/* SQL definitions */\r
+/*******************/\r
+\r
+#define SQL_TEXT                           452\r
+#define SQL_VARYING                        448\r
+#define SQL_SHORT                          500\r
+#define SQL_LONG                           496\r
+#define SQL_FLOAT                          482\r
+#define SQL_DOUBLE                         480\r
+#define SQL_D_FLOAT                        530\r
+#define SQL_TIMESTAMP                      510\r
+#define SQL_BLOB                           520\r
+#define SQL_ARRAY                          540\r
+#define SQL_QUAD                           550\r
+#define SQL_TYPE_TIME                     560\r
+#define SQL_TYPE_DATE                      570\r
+#define SQL_INT64                         580\r
+\r
+/* Historical alias for pre V6 applications */\r
+#define SQL_DATE                       SQL_TIMESTAMP\r
+\r
+/*****************/\r
+/* Blob Subtypes */\r
+/*****************/\r
+\r
+/* types less than zero are reserved for customer use */\r
+\r
+#define isc_blob_untyped                   0\r
+\r
+/* internal subtypes */\r
+\r
+#define isc_blob_text                      1\r
+#define isc_blob_blr                       2\r
+#define isc_blob_acl                       3\r
+#define isc_blob_ranges                    4\r
+#define isc_blob_summary                   5\r
+#define isc_blob_format                    6\r
+#define isc_blob_tra                       7\r
+#define isc_blob_extfile                   8\r
+\r
+/* the range 20-30 is reserved for dBASE and Paradox types */\r
+\r
+#define isc_blob_formatted_memo            20\r
+#define isc_blob_paradox_ole               21\r
+#define isc_blob_graphic                   22\r
+#define isc_blob_dbase_ole                 23\r
+#define isc_blob_typed_binary              24\r
+\r
+/* Deprecated definitions maintained for compatibility only */\r
+\r
+#define isc_info_db_SQL_dialect           62\r
+#define isc_dpb_SQL_dialect               63\r
+#define isc_dpb_set_db_SQL_dialect        65\r
+\r
+\r
+#include "iberror.h"\r
+\r
+#endif /* JRD_IBASE_H */\r
+\r
diff --git a/stglibs/ibpp.lib/iberror.h b/stglibs/ibpp.lib/iberror.h
new file mode 100644 (file)
index 0000000..653beb6
--- /dev/null
@@ -0,0 +1,771 @@
+\r
+#ifndef _JRD_GEN_IBERROR_H\r
+#define _JRD_GEN_IBERROR_H\r
+/*\r
+ * The contents of this file are subject to the Interbase Public\r
+ * License Version 1.0 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy\r
+ * of the License at http://www.Inprise.com/IPL.html\r
+ * \r
+ * Software distributed under the License is distributed on an\r
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express\r
+ * or implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ * \r
+ * The content of this file was generated by the Firebird project\r
+ * using the program jrd/codes.epp\r
+ */\r
+/*\r
+ * \r
+ * *** WARNING *** - This file is automatically generated by codes.e - do not edit!\r
+ * \r
+ */\r
+/*\r
+ *     MODULE:         iberror.h\r
+ *     DESCRIPTION:    ISC error codes\r
+ *\r
+ */\r
+\r
+\r
+\r
+/***********************/\r
+/*   ISC Error Codes   */\r
+/***********************/\r
+\r
+#define isc_facility 20\r
+#define isc_base 335544320L\r
+#define isc_factor 1\r
+\r
+#define isc_arg_end            0       /* end of argument list */\r
+#define isc_arg_gds            1       /* generic DSRI status value */\r
+#define isc_arg_string         2       /* string argument */\r
+#define isc_arg_cstring        3       /* count & string argument */\r
+#define isc_arg_number         4       /* numeric argument (long) */\r
+#define isc_arg_interpreted    5       /* interpreted status code (string) */\r
+#define isc_arg_vms            6       /* VAX/VMS status code (long) */\r
+#define isc_arg_unix           7       /* UNIX error code */\r
+#define isc_arg_domain         8       /* Apollo/Domain error code */\r
+#define isc_arg_dos            9       /* MSDOS/OS2 error code */\r
+#define isc_arg_mpexl          10      /* HP MPE/XL error code */\r
+#define isc_arg_mpexl_ipc      11      /* HP MPE/XL IPC error code */\r
+#define isc_arg_next_mach      15      /* NeXT/Mach error code */\r
+#define isc_arg_netware        16      /* NetWare error code */\r
+#define isc_arg_win32          17      /* Win32 error code */\r
+#define isc_arg_warning        18      /* warning argument */\r
+\r
+#define isc_arith_except                     335544321L\r
+#define isc_bad_dbkey                        335544322L\r
+#define isc_bad_db_format                    335544323L\r
+#define isc_bad_db_handle                    335544324L\r
+#define isc_bad_dpb_content                  335544325L\r
+#define isc_bad_dpb_form                     335544326L\r
+#define isc_bad_req_handle                   335544327L\r
+#define isc_bad_segstr_handle                335544328L\r
+#define isc_bad_segstr_id                    335544329L\r
+#define isc_bad_tpb_content                  335544330L\r
+#define isc_bad_tpb_form                     335544331L\r
+#define isc_bad_trans_handle                 335544332L\r
+#define isc_bug_check                        335544333L\r
+#define isc_convert_error                    335544334L\r
+#define isc_db_corrupt                       335544335L\r
+#define isc_deadlock                         335544336L\r
+#define isc_excess_trans                     335544337L\r
+#define isc_from_no_match                    335544338L\r
+#define isc_infinap                          335544339L\r
+#define isc_infona                           335544340L\r
+#define isc_infunk                           335544341L\r
+#define isc_integ_fail                       335544342L\r
+#define isc_invalid_blr                      335544343L\r
+#define isc_io_error                         335544344L\r
+#define isc_lock_conflict                    335544345L\r
+#define isc_metadata_corrupt                 335544346L\r
+#define isc_not_valid                        335544347L\r
+#define isc_no_cur_rec                       335544348L\r
+#define isc_no_dup                           335544349L\r
+#define isc_no_finish                        335544350L\r
+#define isc_no_meta_update                   335544351L\r
+#define isc_no_priv                          335544352L\r
+#define isc_no_recon                         335544353L\r
+#define isc_no_record                        335544354L\r
+#define isc_no_segstr_close                  335544355L\r
+#define isc_obsolete_metadata                335544356L\r
+#define isc_open_trans                       335544357L\r
+#define isc_port_len                         335544358L\r
+#define isc_read_only_field                  335544359L\r
+#define isc_read_only_rel                    335544360L\r
+#define isc_read_only_trans                  335544361L\r
+#define isc_read_only_view                   335544362L\r
+#define isc_req_no_trans                     335544363L\r
+#define isc_req_sync                         335544364L\r
+#define isc_req_wrong_db                     335544365L\r
+#define isc_segment                          335544366L\r
+#define isc_segstr_eof                       335544367L\r
+#define isc_segstr_no_op                     335544368L\r
+#define isc_segstr_no_read                   335544369L\r
+#define isc_segstr_no_trans                  335544370L\r
+#define isc_segstr_no_write                  335544371L\r
+#define isc_segstr_wrong_db                  335544372L\r
+#define isc_sys_request                      335544373L\r
+#define isc_stream_eof                       335544374L\r
+#define isc_unavailable                      335544375L\r
+#define isc_unres_rel                        335544376L\r
+#define isc_uns_ext                          335544377L\r
+#define isc_wish_list                        335544378L\r
+#define isc_wrong_ods                        335544379L\r
+#define isc_wronumarg                        335544380L\r
+#define isc_imp_exc                          335544381L\r
+#define isc_random                           335544382L\r
+#define isc_fatal_conflict                   335544383L\r
+#define isc_badblk                           335544384L\r
+#define isc_invpoolcl                        335544385L\r
+#define isc_nopoolids                        335544386L\r
+#define isc_relbadblk                        335544387L\r
+#define isc_blktoobig                        335544388L\r
+#define isc_bufexh                           335544389L\r
+#define isc_syntaxerr                        335544390L\r
+#define isc_bufinuse                         335544391L\r
+#define isc_bdbincon                         335544392L\r
+#define isc_reqinuse                         335544393L\r
+#define isc_badodsver                        335544394L\r
+#define isc_relnotdef                        335544395L\r
+#define isc_fldnotdef                        335544396L\r
+#define isc_dirtypage                        335544397L\r
+#define isc_waifortra                        335544398L\r
+#define isc_doubleloc                        335544399L\r
+#define isc_nodnotfnd                        335544400L\r
+#define isc_dupnodfnd                        335544401L\r
+#define isc_locnotmar                        335544402L\r
+#define isc_badpagtyp                        335544403L\r
+#define isc_corrupt                          335544404L\r
+#define isc_badpage                          335544405L\r
+#define isc_badindex                         335544406L\r
+#define isc_dbbnotzer                        335544407L\r
+#define isc_tranotzer                        335544408L\r
+#define isc_trareqmis                        335544409L\r
+#define isc_badhndcnt                        335544410L\r
+#define isc_wrotpbver                        335544411L\r
+#define isc_wroblrver                        335544412L\r
+#define isc_wrodpbver                        335544413L\r
+#define isc_blobnotsup                       335544414L\r
+#define isc_badrelation                      335544415L\r
+#define isc_nodetach                         335544416L\r
+#define isc_notremote                        335544417L\r
+#define isc_trainlim                         335544418L\r
+#define isc_notinlim                         335544419L\r
+#define isc_traoutsta                        335544420L\r
+#define isc_connect_reject                   335544421L\r
+#define isc_dbfile                           335544422L\r
+#define isc_orphan                           335544423L\r
+#define isc_no_lock_mgr                      335544424L\r
+#define isc_ctxinuse                         335544425L\r
+#define isc_ctxnotdef                        335544426L\r
+#define isc_datnotsup                        335544427L\r
+#define isc_badmsgnum                        335544428L\r
+#define isc_badparnum                        335544429L\r
+#define isc_virmemexh                        335544430L\r
+#define isc_blocking_signal                  335544431L\r
+#define isc_lockmanerr                       335544432L\r
+#define isc_journerr                         335544433L\r
+#define isc_keytoobig                        335544434L\r
+#define isc_nullsegkey                       335544435L\r
+#define isc_sqlerr                           335544436L\r
+#define isc_wrodynver                        335544437L\r
+#define isc_funnotdef                        335544438L\r
+#define isc_funmismat                        335544439L\r
+#define isc_bad_msg_vec                      335544440L\r
+#define isc_bad_detach                       335544441L\r
+#define isc_noargacc_read                    335544442L\r
+#define isc_noargacc_write                   335544443L\r
+#define isc_read_only                        335544444L\r
+#define isc_ext_err                          335544445L\r
+#define isc_non_updatable                    335544446L\r
+#define isc_no_rollback                      335544447L\r
+#define isc_bad_sec_info                     335544448L\r
+#define isc_invalid_sec_info                 335544449L\r
+#define isc_misc_interpreted                 335544450L\r
+#define isc_update_conflict                  335544451L\r
+#define isc_unlicensed                       335544452L\r
+#define isc_obj_in_use                       335544453L\r
+#define isc_nofilter                         335544454L\r
+#define isc_shadow_accessed                  335544455L\r
+#define isc_invalid_sdl                      335544456L\r
+#define isc_out_of_bounds                    335544457L\r
+#define isc_invalid_dimension                335544458L\r
+#define isc_rec_in_limbo                     335544459L\r
+#define isc_shadow_missing                   335544460L\r
+#define isc_cant_validate                    335544461L\r
+#define isc_cant_start_journal               335544462L\r
+#define isc_gennotdef                        335544463L\r
+#define isc_cant_start_logging               335544464L\r
+#define isc_bad_segstr_type                  335544465L\r
+#define isc_foreign_key                      335544466L\r
+#define isc_high_minor                       335544467L\r
+#define isc_tra_state                        335544468L\r
+#define isc_trans_invalid                    335544469L\r
+#define isc_buf_invalid                      335544470L\r
+#define isc_indexnotdefined                  335544471L\r
+#define isc_login                            335544472L\r
+#define isc_invalid_bookmark                 335544473L\r
+#define isc_bad_lock_level                   335544474L\r
+#define isc_relation_lock                    335544475L\r
+#define isc_record_lock                      335544476L\r
+#define isc_max_idx                          335544477L\r
+#define isc_jrn_enable                       335544478L\r
+#define isc_old_failure                      335544479L\r
+#define isc_old_in_progress                  335544480L\r
+#define isc_old_no_space                     335544481L\r
+#define isc_no_wal_no_jrn                    335544482L\r
+#define isc_num_old_files                    335544483L\r
+#define isc_wal_file_open                    335544484L\r
+#define isc_bad_stmt_handle                  335544485L\r
+#define isc_wal_failure                      335544486L\r
+#define isc_walw_err                         335544487L\r
+#define isc_logh_small                       335544488L\r
+#define isc_logh_inv_version                 335544489L\r
+#define isc_logh_open_flag                   335544490L\r
+#define isc_logh_open_flag2                  335544491L\r
+#define isc_logh_diff_dbname                 335544492L\r
+#define isc_logf_unexpected_eof              335544493L\r
+#define isc_logr_incomplete                  335544494L\r
+#define isc_logr_header_small                335544495L\r
+#define isc_logb_small                       335544496L\r
+#define isc_wal_illegal_attach               335544497L\r
+#define isc_wal_invalid_wpb                  335544498L\r
+#define isc_wal_err_rollover                 335544499L\r
+#define isc_no_wal                           335544500L\r
+#define isc_drop_wal                         335544501L\r
+#define isc_stream_not_defined               335544502L\r
+#define isc_wal_subsys_error                 335544503L\r
+#define isc_wal_subsys_corrupt               335544504L\r
+#define isc_no_archive                       335544505L\r
+#define isc_shutinprog                       335544506L\r
+#define isc_range_in_use                     335544507L\r
+#define isc_range_not_found                  335544508L\r
+#define isc_charset_not_found                335544509L\r
+#define isc_lock_timeout                     335544510L\r
+#define isc_prcnotdef                        335544511L\r
+#define isc_prcmismat                        335544512L\r
+#define isc_wal_bugcheck                     335544513L\r
+#define isc_wal_cant_expand                  335544514L\r
+#define isc_codnotdef                        335544515L\r
+#define isc_xcpnotdef                        335544516L\r
+#define isc_except                           335544517L\r
+#define isc_cache_restart                    335544518L\r
+#define isc_bad_lock_handle                  335544519L\r
+#define isc_jrn_present                      335544520L\r
+#define isc_wal_err_rollover2                335544521L\r
+#define isc_wal_err_logwrite                 335544522L\r
+#define isc_wal_err_jrn_comm                 335544523L\r
+#define isc_wal_err_expansion                335544524L\r
+#define isc_wal_err_setup                    335544525L\r
+#define isc_wal_err_ww_sync                  335544526L\r
+#define isc_wal_err_ww_start                 335544527L\r
+#define isc_shutdown                         335544528L\r
+#define isc_existing_priv_mod                335544529L\r
+#define isc_primary_key_ref                  335544530L\r
+#define isc_primary_key_notnull              335544531L\r
+#define isc_ref_cnstrnt_notfound             335544532L\r
+#define isc_foreign_key_notfound             335544533L\r
+#define isc_ref_cnstrnt_update               335544534L\r
+#define isc_check_cnstrnt_update             335544535L\r
+#define isc_check_cnstrnt_del                335544536L\r
+#define isc_integ_index_seg_del              335544537L\r
+#define isc_integ_index_seg_mod              335544538L\r
+#define isc_integ_index_del                  335544539L\r
+#define isc_integ_index_mod                  335544540L\r
+#define isc_check_trig_del                   335544541L\r
+#define isc_check_trig_update                335544542L\r
+#define isc_cnstrnt_fld_del                  335544543L\r
+#define isc_cnstrnt_fld_rename               335544544L\r
+#define isc_rel_cnstrnt_update               335544545L\r
+#define isc_constaint_on_view                335544546L\r
+#define isc_invld_cnstrnt_type               335544547L\r
+#define isc_primary_key_exists               335544548L\r
+#define isc_systrig_update                   335544549L\r
+#define isc_not_rel_owner                    335544550L\r
+#define isc_grant_obj_notfound               335544551L\r
+#define isc_grant_fld_notfound               335544552L\r
+#define isc_grant_nopriv                     335544553L\r
+#define isc_nonsql_security_rel              335544554L\r
+#define isc_nonsql_security_fld              335544555L\r
+#define isc_wal_cache_err                    335544556L\r
+#define isc_shutfail                         335544557L\r
+#define isc_check_constraint                 335544558L\r
+#define isc_bad_svc_handle                   335544559L\r
+#define isc_shutwarn                         335544560L\r
+#define isc_wrospbver                        335544561L\r
+#define isc_bad_spb_form                     335544562L\r
+#define isc_svcnotdef                        335544563L\r
+#define isc_no_jrn                           335544564L\r
+#define isc_transliteration_failed           335544565L\r
+#define isc_start_cm_for_wal                 335544566L\r
+#define isc_wal_ovflow_log_required          335544567L\r
+#define isc_text_subtype                     335544568L\r
+#define isc_dsql_error                       335544569L\r
+#define isc_dsql_command_err                 335544570L\r
+#define isc_dsql_constant_err                335544571L\r
+#define isc_dsql_cursor_err                  335544572L\r
+#define isc_dsql_datatype_err                335544573L\r
+#define isc_dsql_decl_err                    335544574L\r
+#define isc_dsql_cursor_update_err           335544575L\r
+#define isc_dsql_cursor_open_err             335544576L\r
+#define isc_dsql_cursor_close_err            335544577L\r
+#define isc_dsql_field_err                   335544578L\r
+#define isc_dsql_internal_err                335544579L\r
+#define isc_dsql_relation_err                335544580L\r
+#define isc_dsql_procedure_err               335544581L\r
+#define isc_dsql_request_err                 335544582L\r
+#define isc_dsql_sqlda_err                   335544583L\r
+#define isc_dsql_var_count_err               335544584L\r
+#define isc_dsql_stmt_handle                 335544585L\r
+#define isc_dsql_function_err                335544586L\r
+#define isc_dsql_blob_err                    335544587L\r
+#define isc_collation_not_found              335544588L\r
+#define isc_collation_not_for_charset        335544589L\r
+#define isc_dsql_dup_option                  335544590L\r
+#define isc_dsql_tran_err                    335544591L\r
+#define isc_dsql_invalid_array               335544592L\r
+#define isc_dsql_max_arr_dim_exceeded        335544593L\r
+#define isc_dsql_arr_range_error             335544594L\r
+#define isc_dsql_trigger_err                 335544595L\r
+#define isc_dsql_subselect_err               335544596L\r
+#define isc_dsql_crdb_prepare_err            335544597L\r
+#define isc_specify_field_err                335544598L\r
+#define isc_num_field_err                    335544599L\r
+#define isc_col_name_err                     335544600L\r
+#define isc_where_err                        335544601L\r
+#define isc_table_view_err                   335544602L\r
+#define isc_distinct_err                     335544603L\r
+#define isc_key_field_count_err              335544604L\r
+#define isc_subquery_err                     335544605L\r
+#define isc_expression_eval_err              335544606L\r
+#define isc_node_err                         335544607L\r
+#define isc_command_end_err                  335544608L\r
+#define isc_index_name                       335544609L\r
+#define isc_exception_name                   335544610L\r
+#define isc_field_name                       335544611L\r
+#define isc_token_err                        335544612L\r
+#define isc_union_err                        335544613L\r
+#define isc_dsql_construct_err               335544614L\r
+#define isc_field_aggregate_err              335544615L\r
+#define isc_field_ref_err                    335544616L\r
+#define isc_order_by_err                     335544617L\r
+#define isc_return_mode_err                  335544618L\r
+#define isc_extern_func_err                  335544619L\r
+#define isc_alias_conflict_err               335544620L\r
+#define isc_procedure_conflict_error         335544621L\r
+#define isc_relation_conflict_err            335544622L\r
+#define isc_dsql_domain_err                  335544623L\r
+#define isc_idx_seg_err                      335544624L\r
+#define isc_node_name_err                    335544625L\r
+#define isc_table_name                       335544626L\r
+#define isc_proc_name                        335544627L\r
+#define isc_idx_create_err                   335544628L\r
+#define isc_wal_shadow_err                   335544629L\r
+#define isc_dependency                       335544630L\r
+#define isc_idx_key_err                      335544631L\r
+#define isc_dsql_file_length_err             335544632L\r
+#define isc_dsql_shadow_number_err           335544633L\r
+#define isc_dsql_token_unk_err               335544634L\r
+#define isc_dsql_no_relation_alias           335544635L\r
+#define isc_indexname                        335544636L\r
+#define isc_no_stream_plan                   335544637L\r
+#define isc_stream_twice                     335544638L\r
+#define isc_stream_not_found                 335544639L\r
+#define isc_collation_requires_text          335544640L\r
+#define isc_dsql_domain_not_found            335544641L\r
+#define isc_index_unused                     335544642L\r
+#define isc_dsql_self_join                   335544643L\r
+#define isc_stream_bof                       335544644L\r
+#define isc_stream_crack                     335544645L\r
+#define isc_db_or_file_exists                335544646L\r
+#define isc_invalid_operator                 335544647L\r
+#define isc_conn_lost                        335544648L\r
+#define isc_bad_checksum                     335544649L\r
+#define isc_page_type_err                    335544650L\r
+#define isc_ext_readonly_err                 335544651L\r
+#define isc_sing_select_err                  335544652L\r
+#define isc_psw_attach                       335544653L\r
+#define isc_psw_start_trans                  335544654L\r
+#define isc_invalid_direction                335544655L\r
+#define isc_dsql_var_conflict                335544656L\r
+#define isc_dsql_no_blob_array               335544657L\r
+#define isc_dsql_base_table                  335544658L\r
+#define isc_duplicate_base_table             335544659L\r
+#define isc_view_alias                       335544660L\r
+#define isc_index_root_page_full             335544661L\r
+#define isc_dsql_blob_type_unknown           335544662L\r
+#define isc_req_max_clones_exceeded          335544663L\r
+#define isc_dsql_duplicate_spec              335544664L\r
+#define isc_unique_key_violation             335544665L\r
+#define isc_srvr_version_too_old             335544666L\r
+#define isc_drdb_completed_with_errs         335544667L\r
+#define isc_dsql_procedure_use_err           335544668L\r
+#define isc_dsql_count_mismatch              335544669L\r
+#define isc_blob_idx_err                     335544670L\r
+#define isc_array_idx_err                    335544671L\r
+#define isc_key_field_err                    335544672L\r
+#define isc_no_delete                        335544673L\r
+#define isc_del_last_field                   335544674L\r
+#define isc_sort_err                         335544675L\r
+#define isc_sort_mem_err                     335544676L\r
+#define isc_version_err                      335544677L\r
+#define isc_inval_key_posn                   335544678L\r
+#define isc_no_segments_err                  335544679L\r
+#define isc_crrp_data_err                    335544680L\r
+#define isc_rec_size_err                     335544681L\r
+#define isc_dsql_field_ref                   335544682L\r
+#define isc_req_depth_exceeded               335544683L\r
+#define isc_no_field_access                  335544684L\r
+#define isc_no_dbkey                         335544685L\r
+#define isc_jrn_format_err                   335544686L\r
+#define isc_jrn_file_full                    335544687L\r
+#define isc_dsql_open_cursor_request         335544688L\r
+#define isc_ib_error                         335544689L\r
+#define isc_cache_redef                      335544690L\r
+#define isc_cache_too_small                  335544691L\r
+#define isc_log_redef                        335544692L\r
+#define isc_log_too_small                    335544693L\r
+#define isc_partition_too_small              335544694L\r
+#define isc_partition_not_supp               335544695L\r
+#define isc_log_length_spec                  335544696L\r
+#define isc_precision_err                    335544697L\r
+#define isc_scale_nogt                       335544698L\r
+#define isc_expec_short                      335544699L\r
+#define isc_expec_long                       335544700L\r
+#define isc_expec_ushort                     335544701L\r
+#define isc_like_escape_invalid              335544702L\r
+#define isc_svcnoexe                         335544703L\r
+#define isc_net_lookup_err                   335544704L\r
+#define isc_service_unknown                  335544705L\r
+#define isc_host_unknown                     335544706L\r
+#define isc_grant_nopriv_on_base             335544707L\r
+#define isc_dyn_fld_ambiguous                335544708L\r
+#define isc_dsql_agg_ref_err                 335544709L\r
+#define isc_complex_view                     335544710L\r
+#define isc_unprepared_stmt                  335544711L\r
+#define isc_expec_positive                   335544712L\r
+#define isc_dsql_sqlda_value_err             335544713L\r
+#define isc_invalid_array_id                 335544714L\r
+#define isc_extfile_uns_op                   335544715L\r
+#define isc_svc_in_use                       335544716L\r
+#define isc_err_stack_limit                  335544717L\r
+#define isc_invalid_key                      335544718L\r
+#define isc_net_init_error                   335544719L\r
+#define isc_loadlib_failure                  335544720L\r
+#define isc_network_error                    335544721L\r
+#define isc_net_connect_err                  335544722L\r
+#define isc_net_connect_listen_err           335544723L\r
+#define isc_net_event_connect_err            335544724L\r
+#define isc_net_event_listen_err             335544725L\r
+#define isc_net_read_err                     335544726L\r
+#define isc_net_write_err                    335544727L\r
+#define isc_integ_index_deactivate           335544728L\r
+#define isc_integ_deactivate_primary         335544729L\r
+#define isc_cse_not_supported                335544730L\r
+#define isc_tra_must_sweep                   335544731L\r
+#define isc_unsupported_network_drive        335544732L\r
+#define isc_io_create_err                    335544733L\r
+#define isc_io_open_err                      335544734L\r
+#define isc_io_close_err                     335544735L\r
+#define isc_io_read_err                      335544736L\r
+#define isc_io_write_err                     335544737L\r
+#define isc_io_delete_err                    335544738L\r
+#define isc_io_access_err                    335544739L\r
+#define isc_udf_exception                    335544740L\r
+#define isc_lost_db_connection               335544741L\r
+#define isc_no_write_user_priv               335544742L\r
+#define isc_token_too_long                   335544743L\r
+#define isc_max_att_exceeded                 335544744L\r
+#define isc_login_same_as_role_name          335544745L\r
+#define isc_reftable_requires_pk             335544746L\r
+#define isc_usrname_too_long                 335544747L\r
+#define isc_password_too_long                335544748L\r
+#define isc_usrname_required                 335544749L\r
+#define isc_password_required                335544750L\r
+#define isc_bad_protocol                     335544751L\r
+#define isc_dup_usrname_found                335544752L\r
+#define isc_usrname_not_found                335544753L\r
+#define isc_error_adding_sec_record          335544754L\r
+#define isc_error_modifying_sec_record       335544755L\r
+#define isc_error_deleting_sec_record        335544756L\r
+#define isc_error_updating_sec_db            335544757L\r
+#define isc_sort_rec_size_err                335544758L\r
+#define isc_bad_default_value                335544759L\r
+#define isc_invalid_clause                   335544760L\r
+#define isc_too_many_handles                 335544761L\r
+#define isc_optimizer_blk_exc                335544762L\r
+#define isc_invalid_string_constant          335544763L\r
+#define isc_transitional_date                335544764L\r
+#define isc_read_only_database               335544765L\r
+#define isc_must_be_dialect_2_and_up         335544766L\r
+#define isc_blob_filter_exception            335544767L\r
+#define isc_exception_access_violation       335544768L\r
+#define isc_exception_datatype_missalignment 335544769L\r
+#define isc_exception_array_bounds_exceeded  335544770L\r
+#define isc_exception_float_denormal_operand 335544771L\r
+#define isc_exception_float_divide_by_zero   335544772L\r
+#define isc_exception_float_inexact_result   335544773L\r
+#define isc_exception_float_invalid_operand  335544774L\r
+#define isc_exception_float_overflow         335544775L\r
+#define isc_exception_float_stack_check      335544776L\r
+#define isc_exception_float_underflow        335544777L\r
+#define isc_exception_integer_divide_by_zero 335544778L\r
+#define isc_exception_integer_overflow       335544779L\r
+#define isc_exception_unknown                335544780L\r
+#define isc_exception_stack_overflow         335544781L\r
+#define isc_exception_sigsegv                335544782L\r
+#define isc_exception_sigill                 335544783L\r
+#define isc_exception_sigbus                 335544784L\r
+#define isc_exception_sigfpe                 335544785L\r
+#define isc_ext_file_delete                  335544786L\r
+#define isc_ext_file_modify                  335544787L\r
+#define isc_adm_task_denied                  335544788L\r
+#define isc_extract_input_mismatch           335544789L\r
+#define isc_insufficient_svc_privileges      335544790L\r
+#define isc_file_in_use                      335544791L\r
+#define isc_service_att_err                  335544792L\r
+#define isc_ddl_not_allowed_by_db_sql_dial   335544793L\r
+#define isc_cancelled                        335544794L\r
+#define isc_unexp_spb_form                   335544795L\r
+#define isc_sql_dialect_datatype_unsupport   335544796L\r
+#define isc_svcnouser                        335544797L\r
+#define isc_depend_on_uncommitted_rel        335544798L\r
+#define isc_svc_name_missing                 335544799L\r
+#define isc_too_many_contexts                335544800L\r
+#define isc_datype_notsup                    335544801L\r
+#define isc_dialect_reset_warning            335544802L\r
+#define isc_dialect_not_changed              335544803L\r
+#define isc_database_create_failed           335544804L\r
+#define isc_inv_dialect_specified            335544805L\r
+#define isc_valid_db_dialects                335544806L\r
+#define isc_sqlwarn                          335544807L\r
+#define isc_dtype_renamed                    335544808L\r
+#define isc_extern_func_dir_error            335544809L\r
+#define isc_date_range_exceeded              335544810L\r
+#define isc_inv_client_dialect_specified     335544811L\r
+#define isc_valid_client_dialects            335544812L\r
+#define isc_optimizer_between_err            335544813L\r
+#define isc_service_not_supported            335544814L\r
+#define isc_generator_name                   335544815L\r
+#define isc_udf_name                         335544816L\r
+#define isc_bad_limit_param                  335544817L\r
+#define isc_bad_skip_param                   335544818L\r
+#define isc_io_32bit_exceeded_err            335544819L\r
+#define isc_invalid_savepoint                335544820L\r
+#define isc_dsql_column_pos_err              335544821L\r
+#define isc_dsql_agg_where_err               335544822L\r
+#define isc_dsql_agg_group_err               335544823L\r
+#define isc_dsql_agg_column_err              335544824L\r
+#define isc_dsql_agg_having_err              335544825L\r
+#define isc_dsql_agg_nested_err              335544826L\r
+#define isc_exec_sql_invalid_arg             335544827L\r
+#define isc_exec_sql_invalid_req             335544828L\r
+#define isc_exec_sql_invalid_var             335544829L\r
+#define isc_exec_sql_max_call_exceeded       335544830L\r
+#define isc_conf_access_denied               335544831L\r
+#define isc_gfix_db_name                     335740929L\r
+#define isc_gfix_invalid_sw                  335740930L\r
+#define isc_gfix_incmp_sw                    335740932L\r
+#define isc_gfix_replay_req                  335740933L\r
+#define isc_gfix_pgbuf_req                   335740934L\r
+#define isc_gfix_val_req                     335740935L\r
+#define isc_gfix_pval_req                    335740936L\r
+#define isc_gfix_trn_req                     335740937L\r
+#define isc_gfix_full_req                    335740940L\r
+#define isc_gfix_usrname_req                 335740941L\r
+#define isc_gfix_pass_req                    335740942L\r
+#define isc_gfix_subs_name                   335740943L\r
+#define isc_gfix_wal_req                     335740944L\r
+#define isc_gfix_sec_req                     335740945L\r
+#define isc_gfix_nval_req                    335740946L\r
+#define isc_gfix_type_shut                   335740947L\r
+#define isc_gfix_retry                       335740948L\r
+#define isc_gfix_retry_db                    335740951L\r
+#define isc_gfix_exceed_max                  335740991L\r
+#define isc_gfix_corrupt_pool                335740992L\r
+#define isc_gfix_mem_exhausted               335740993L\r
+#define isc_gfix_bad_pool                    335740994L\r
+#define isc_gfix_trn_not_valid               335740995L\r
+#define isc_gfix_unexp_eoi                   335741012L\r
+#define isc_gfix_recon_fail                  335741018L\r
+#define isc_gfix_trn_unknown                 335741036L\r
+#define isc_gfix_mode_req                    335741038L\r
+#define isc_gfix_opt_SQL_dialect             335741039L\r
+#define isc_dsql_dbkey_from_non_table        336003074L\r
+#define isc_dsql_transitional_numeric        336003075L\r
+#define isc_dsql_dialect_warning_expr        336003076L\r
+#define isc_sql_db_dialect_dtype_unsupport   336003077L\r
+#define isc_isc_sql_dialect_conflict_num     336003079L\r
+#define isc_dsql_warning_number_ambiguous    336003080L\r
+#define isc_dsql_warning_number_ambiguous1   336003081L\r
+#define isc_dsql_warn_precision_ambiguous    336003082L\r
+#define isc_dsql_warn_precision_ambiguous1   336003083L\r
+#define isc_dsql_warn_precision_ambiguous2   336003084L\r
+#define isc_dsql_ambiguous_field_name        336003085L\r
+#define isc_dsql_udf_return_pos_err          336003086L\r
+#define isc_dsql_invalid_label               336003087L\r
+#define isc_dsql_datatypes_not_comparable    336003088L\r
+#define isc_dyn_role_does_not_exist          336068796L\r
+#define isc_dyn_no_grant_admin_opt           336068797L\r
+#define isc_dyn_user_not_role_member         336068798L\r
+#define isc_dyn_delete_role_failed           336068799L\r
+#define isc_dyn_grant_role_to_user           336068800L\r
+#define isc_dyn_inv_sql_role_name            336068801L\r
+#define isc_dyn_dup_sql_role                 336068802L\r
+#define isc_dyn_kywd_spec_for_role           336068803L\r
+#define isc_dyn_roles_not_supported          336068804L\r
+#define isc_dyn_domain_name_exists           336068812L\r
+#define isc_dyn_field_name_exists            336068813L\r
+#define isc_dyn_dependency_exists            336068814L\r
+#define isc_dyn_dtype_invalid                336068815L\r
+#define isc_dyn_char_fld_too_small           336068816L\r
+#define isc_dyn_invalid_dtype_conversion     336068817L\r
+#define isc_dyn_dtype_conv_invalid           336068818L\r
+#define isc_dyn_zero_len_id                  336068820L\r
+#define isc_gbak_unknown_switch              336330753L\r
+#define isc_gbak_page_size_missing           336330754L\r
+#define isc_gbak_page_size_toobig            336330755L\r
+#define isc_gbak_redir_ouput_missing         336330756L\r
+#define isc_gbak_switches_conflict           336330757L\r
+#define isc_gbak_unknown_device              336330758L\r
+#define isc_gbak_no_protection               336330759L\r
+#define isc_gbak_page_size_not_allowed       336330760L\r
+#define isc_gbak_multi_source_dest           336330761L\r
+#define isc_gbak_filename_missing            336330762L\r
+#define isc_gbak_dup_inout_names             336330763L\r
+#define isc_gbak_inv_page_size               336330764L\r
+#define isc_gbak_db_specified                336330765L\r
+#define isc_gbak_db_exists                   336330766L\r
+#define isc_gbak_unk_device                  336330767L\r
+#define isc_gbak_blob_info_failed            336330772L\r
+#define isc_gbak_unk_blob_item               336330773L\r
+#define isc_gbak_get_seg_failed              336330774L\r
+#define isc_gbak_close_blob_failed           336330775L\r
+#define isc_gbak_open_blob_failed            336330776L\r
+#define isc_gbak_put_blr_gen_id_failed       336330777L\r
+#define isc_gbak_unk_type                    336330778L\r
+#define isc_gbak_comp_req_failed             336330779L\r
+#define isc_gbak_start_req_failed            336330780L\r
+#define isc_gbak_rec_failed                  336330781L\r
+#define isc_gbak_rel_req_failed              336330782L\r
+#define isc_gbak_db_info_failed              336330783L\r
+#define isc_gbak_no_db_desc                  336330784L\r
+#define isc_gbak_db_create_failed            336330785L\r
+#define isc_gbak_decomp_len_error            336330786L\r
+#define isc_gbak_tbl_missing                 336330787L\r
+#define isc_gbak_blob_col_missing            336330788L\r
+#define isc_gbak_create_blob_failed          336330789L\r
+#define isc_gbak_put_seg_failed              336330790L\r
+#define isc_gbak_rec_len_exp                 336330791L\r
+#define isc_gbak_inv_rec_len                 336330792L\r
+#define isc_gbak_exp_data_type               336330793L\r
+#define isc_gbak_gen_id_failed               336330794L\r
+#define isc_gbak_unk_rec_type                336330795L\r
+#define isc_gbak_inv_bkup_ver                336330796L\r
+#define isc_gbak_missing_bkup_desc           336330797L\r
+#define isc_gbak_string_trunc                336330798L\r
+#define isc_gbak_cant_rest_record            336330799L\r
+#define isc_gbak_send_failed                 336330800L\r
+#define isc_gbak_no_tbl_name                 336330801L\r
+#define isc_gbak_unexp_eof                   336330802L\r
+#define isc_gbak_db_format_too_old           336330803L\r
+#define isc_gbak_inv_array_dim               336330804L\r
+#define isc_gbak_xdr_len_expected            336330807L\r
+#define isc_gbak_open_bkup_error             336330817L\r
+#define isc_gbak_open_error                  336330818L\r
+#define isc_gbak_missing_block_fac           336330934L\r
+#define isc_gbak_inv_block_fac               336330935L\r
+#define isc_gbak_block_fac_specified         336330936L\r
+#define isc_gbak_missing_username            336330940L\r
+#define isc_gbak_missing_password            336330941L\r
+#define isc_gbak_missing_skipped_bytes       336330952L\r
+#define isc_gbak_inv_skipped_bytes           336330953L\r
+#define isc_gbak_err_restore_charset         336330965L\r
+#define isc_gbak_err_restore_collation       336330967L\r
+#define isc_gbak_read_error                  336330972L\r
+#define isc_gbak_write_error                 336330973L\r
+#define isc_gbak_db_in_use                   336330985L\r
+#define isc_gbak_sysmemex                    336330990L\r
+#define isc_gbak_restore_role_failed         336331002L\r
+#define isc_gbak_role_op_missing             336331005L\r
+#define isc_gbak_page_buffers_missing        336331010L\r
+#define isc_gbak_page_buffers_wrong_param    336331011L\r
+#define isc_gbak_page_buffers_restore        336331012L\r
+#define isc_gbak_inv_size                    336331014L\r
+#define isc_gbak_file_outof_sequence         336331015L\r
+#define isc_gbak_join_file_missing           336331016L\r
+#define isc_gbak_stdin_not_supptd            336331017L\r
+#define isc_gbak_stdout_not_supptd           336331018L\r
+#define isc_gbak_bkup_corrupt                336331019L\r
+#define isc_gbak_unk_db_file_spec            336331020L\r
+#define isc_gbak_hdr_write_failed            336331021L\r
+#define isc_gbak_disk_space_ex               336331022L\r
+#define isc_gbak_size_lt_min                 336331023L\r
+#define isc_gbak_svc_name_missing            336331025L\r
+#define isc_gbak_not_ownr                    336331026L\r
+#define isc_gbak_mode_req                    336331031L\r
+#define isc_gbak_just_data                   336331033L\r
+#define isc_gbak_data_only                   336331034L\r
+#define isc_gsec_cant_open_db                336723983L\r
+#define isc_gsec_switches_error              336723984L\r
+#define isc_gsec_no_op_spec                  336723985L\r
+#define isc_gsec_no_usr_name                 336723986L\r
+#define isc_gsec_err_add                     336723987L\r
+#define isc_gsec_err_modify                  336723988L\r
+#define isc_gsec_err_find_mod                336723989L\r
+#define isc_gsec_err_rec_not_found           336723990L\r
+#define isc_gsec_err_delete                  336723991L\r
+#define isc_gsec_err_find_del                336723992L\r
+#define isc_gsec_err_find_disp               336723996L\r
+#define isc_gsec_inv_param                   336723997L\r
+#define isc_gsec_op_specified                336723998L\r
+#define isc_gsec_pw_specified                336723999L\r
+#define isc_gsec_uid_specified               336724000L\r
+#define isc_gsec_gid_specified               336724001L\r
+#define isc_gsec_proj_specified              336724002L\r
+#define isc_gsec_org_specified               336724003L\r
+#define isc_gsec_fname_specified             336724004L\r
+#define isc_gsec_mname_specified             336724005L\r
+#define isc_gsec_lname_specified             336724006L\r
+#define isc_gsec_inv_switch                  336724008L\r
+#define isc_gsec_amb_switch                  336724009L\r
+#define isc_gsec_no_op_specified             336724010L\r
+#define isc_gsec_params_not_allowed          336724011L\r
+#define isc_gsec_incompat_switch             336724012L\r
+#define isc_gsec_inv_username                336724044L\r
+#define isc_gsec_inv_pw_length               336724045L\r
+#define isc_gsec_db_specified                336724046L\r
+#define isc_gsec_db_admin_specified          336724047L\r
+#define isc_gsec_db_admin_pw_specified       336724048L\r
+#define isc_gsec_sql_role_specified          336724049L\r
+#define isc_license_no_file                  336789504L\r
+#define isc_license_op_specified             336789523L\r
+#define isc_license_op_missing               336789524L\r
+#define isc_license_inv_switch               336789525L\r
+#define isc_license_inv_switch_combo         336789526L\r
+#define isc_license_inv_op_combo             336789527L\r
+#define isc_license_amb_switch               336789528L\r
+#define isc_license_inv_parameter            336789529L\r
+#define isc_license_param_specified          336789530L\r
+#define isc_license_param_req                336789531L\r
+#define isc_license_syntx_error              336789532L\r
+#define isc_license_dup_id                   336789534L\r
+#define isc_license_inv_id_key               336789535L\r
+#define isc_license_err_remove               336789536L\r
+#define isc_license_err_update               336789537L\r
+#define isc_license_err_convert              336789538L\r
+#define isc_license_err_unk                  336789539L\r
+#define isc_license_svc_err_add              336789540L\r
+#define isc_license_svc_err_remove           336789541L\r
+#define isc_license_eval_exists              336789563L\r
+#define isc_gstat_unknown_switch             336920577L\r
+#define isc_gstat_retry                      336920578L\r
+#define isc_gstat_wrong_ods                  336920579L\r
+#define isc_gstat_unexpected_eof             336920580L\r
+#define isc_gstat_open_err                   336920605L\r
+#define isc_gstat_read_err                   336920606L\r
+#define isc_gstat_sysmemex                   336920607L\r
+#define isc_err_max                          713\r
+\r
+#endif /* JRD_GEN_IBERROR_H */\r
diff --git a/stglibs/ibpp.lib/ibpp.h b/stglibs/ibpp.lib/ibpp.h
new file mode 100644 (file)
index 0000000..7795c7d
--- /dev/null
@@ -0,0 +1,929 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: ibpp.h,v 1.3 2007/10/28 11:17:44 nobunaga Exp $\r
+//     Subject : IBPP public header file. This is _the_ only file you include in\r
+//                       your application files when developing with IBPP.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+//     Contributor(s):\r
+//\r
+//             Olivier Mascia, main coding\r
+//             Matt Hortman, initial linux port\r
+//             Mark Jordan, design contributions\r
+//             Maxim Abrashkin, enhancement patches\r
+//             Torsten Martinsen, enhancement patches\r
+//             Michael Hieke, darwin (OS X) port, enhancement patches\r
+//             Val Samko, enhancement patches and debugging\r
+//             Mike Nordell, invaluable C++ advices\r
+//             Claudio Valderrama, help with not-so-well documented IB/FB features\r
+//             Many others, excellent suggestions, bug finding, and support\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     Tabulations should be set every four characters when editing this file.\r
+//\r
+//     When compiling a project using IBPP, the following defines should be made\r
+//     on the command-line (or in makefiles) according to the OS platform and\r
+//     compiler used.\r
+//\r
+//     Select the platform:    IBPP_WINDOWS | IBPP_LINUX | IBPP_DARWIN\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef __IBPP_H__\r
+#define __IBPP_H__\r
+\r
+#if !defined(IBPP_WINDOWS) && !defined(IBPP_LINUX) && !defined(IBPP_DARWIN)\r
+#error Please define IBPP_WINDOWS/IBPP_LINUX/IBPP_DARWIN before compiling !\r
+#endif\r
+\r
+#if !defined(__BCPLUSPLUS__) && !defined(__GNUC__) && !defined(_MSC_VER) && !defined(__DMC__)
+#error Your compiler is not recognized.\r
+#endif\r
+\r
+#if defined(IBPP_LINUX) || defined(IBPP_DARWIN)\r
+#define IBPP_UNIX      // IBPP_UNIX stands as a common denominator to *NIX flavours\r
+#endif\r
+\r
+// IBPP is written for 32 bits systems or higher.\r
+// The standard type 'int' is assumed to be at least 32 bits.\r
+// And the standard type 'short' is assumed to be exactly 16 bits.\r
+// Everywhere possible, where the exact size of an integer does not matter,\r
+// the standard type 'int' is used. And where an exact integer size is required\r
+// the standard exact precision types definitions of C 99 standard are used.\r
+\r
+#if defined(_MSC_VER) || defined(__DMC__) || defined(__BCPLUSPLUS__)\r
+// C99 §7.18.1.1 Exact-width integer types (only those used by IBPP)\r
+#if defined(_MSC_VER) && (_MSC_VER < 1300)     // MSVC 6 should be < 1300\r
+       typedef short int16_t;\r
+       typedef int int32_t;\r
+       typedef unsigned int uint32_t;\r
+#else\r
+       typedef __int16 int16_t;\r
+       typedef __int32 int32_t;\r
+       typedef unsigned __int32 uint32_t;\r
+#endif\r
+       typedef __int64 int64_t;\r
+#else\r
+       #include <os_int.h>                     // C99 (§7.18) integer types definitions\r
+#endif\r
+\r
+#if !defined(_)\r
+#define _(s)   s\r
+#endif\r
+\r
+#include <exception>\r
+#include <string>\r
+#include <vector>\r
+\r
+namespace IBPP\r
+{\r
+       //      Typically you use this constant in a call IBPP::CheckVersion as in:\r
+       //      if (! IBPP::CheckVersion(IBPP::Version)) { throw .... ; }\r
+       const uint32_t Version = (2<<24) + (5<<16) + (3<<8) + 0; // Version == 2.5.3.0\r
+\r
+       //      Dates range checking\r
+       const int MinDate = -693594;    //  1 JAN 0001\r
+       const int MaxDate = 2958464;    // 31 DEC 9999\r
+       \r
+       //      Transaction Access Modes\r
+       enum TAM {amWrite, amRead};\r
+\r
+       //      Transaction Isolation Levels\r
+       enum TIL {ilConcurrency, ilReadDirty, ilReadCommitted, ilConsistency};\r
+\r
+       //      Transaction Lock Resolution\r
+       enum TLR {lrWait, lrNoWait};\r
+\r
+       // Transaction Table Reservation\r
+       enum TTR {trSharedWrite, trSharedRead, trProtectedWrite, trProtectedRead};\r
+\r
+       //      Prepared Statement Types\r
+       enum STT {stUnknown, stUnsupported,\r
+               stSelect, stInsert, stUpdate, stDelete, stDDL, stExecProcedure,\r
+               stSelectUpdate, stSetGenerator, stSavePoint};\r
+\r
+       //      SQL Data Types\r
+       enum SDT {sdArray, sdBlob, sdDate, sdTime, sdTimestamp, sdString,\r
+               sdSmallint, sdInteger, sdLargeint, sdFloat, sdDouble};\r
+\r
+       //      Array Data Types\r
+       enum ADT {adDate, adTime, adTimestamp, adString,\r
+               adBool, adInt16, adInt32, adInt64, adFloat, adDouble};\r
+\r
+       // Database::Shutdown Modes\r
+       enum DSM {dsForce, dsDenyTrans, dsDenyAttach};\r
+\r
+       // Service::StartBackup && Service::StartRestore Flags\r
+       enum BRF {\r
+               brVerbose = 0x1,\r
+               // Backup flags\r
+               brIgnoreChecksums = 0x100, brIgnoreLimbo = 0x200,\r
+               brMetadataOnly = 0x400, brNoGarbageCollect = 0x800,\r
+               brNonTransportable = 0x1000, brConvertExtTables = 0x2000,\r
+               // Restore flags\r
+               brReplace = 0x10000, brDeactivateIdx = 0x20000,\r
+               brNoShadow = 0x40000, brNoValidity = 0x80000,\r
+               brPerTableCommit = 0x100000, brUseAllSpace = 0x200000\r
+       };\r
+\r
+       // Service::Repair Flags\r
+       enum RPF\r
+       {\r
+               // Mandatory and mutually exclusives\r
+               rpMendRecords = 0x1, rpValidatePages = 0x2, rpValidateFull = 0x4,\r
+               // Options\r
+               rpReadOnly = 0x100, rpIgnoreChecksums = 0x200, rpKillShadows = 0x400\r
+       };\r
+\r
+       // TransactionFactory Flags\r
+       enum TFF {tfIgnoreLimbo = 0x1, tfAutoCommit = 0x2, tfNoAutoUndo = 0x4};\r
+\r
+       /* IBPP never return any error codes. It throws exceptions.\r
+        * On database engine reported errors, an IBPP::SQLException is thrown.\r
+        * In all other cases, IBPP throws IBPP::LogicException.\r
+        * Also note that the runtime and the language might also throw exceptions\r
+        * while executing some IBPP methods. A failing new operator will throw\r
+        * std::bad_alloc, IBPP does nothing to alter the standard behaviour.\r
+        *\r
+        *                    std::exception\r
+        *                           |\r
+        *                   IBPP::Exception\r
+        *                 /                 \\r
+        *    IBPP::LogicException    IBPP::SQLException\r
+        *             |\r
+        *      IBPP::WrongType\r
+        */\r
+\r
+       class Exception : public std::exception\r
+       {\r
+       public:\r
+               virtual const char* Origin() const throw() = 0;\r
+               virtual const char* ErrorMessage() const throw() = 0;   // Deprecated, use what()\r
+               virtual const char* what() const throw() = 0;\r
+               virtual ~Exception() throw();\r
+       };\r
+\r
+       class LogicException : public Exception\r
+       {\r
+       public:\r
+               virtual ~LogicException() throw();\r
+       };\r
+\r
+       class SQLException : public Exception\r
+       {\r
+       public:\r
+               virtual int SqlCode() const throw() = 0;\r
+               virtual int EngineCode() const throw() = 0;\r
+               \r
+               virtual ~SQLException() throw();\r
+       };\r
+\r
+       class WrongType : public LogicException\r
+       {\r
+       public:\r
+               virtual ~WrongType() throw();\r
+       };\r
+       \r
+       /* Classes Date, Time, Timestamp and DBKey are 'helper' classes.  They help\r
+        * in retrieving or setting some special SQL types. Dates, times and dbkeys\r
+        * are often read and written as strings in SQL scripts. When programming\r
+        * with IBPP, we handle those data with these specific classes, which\r
+        * enhance their usefullness and free us of format problems (M/D/Y, D/M/Y,\r
+        * Y-M-D ?, and so on...). */\r
+\r
+       /* Class Date represent purely a Date (no time part specified). It is\r
+        * usefull in interactions with the SQL DATE type of Interbase.  You can add\r
+        * or substract a number from a Date, that will modify it to represent the\r
+        * correct date, X days later or sooner. All the Y2K details taken into\r
+        * account.\r
+        * The full range goes from integer values IBPP::MinDate to IBPP::MaxDate\r
+        * which means from 01 Jan 0001 to 31 Dec 9999. ( Which is inherently\r
+        * incorrect as this assumes Gregorian calendar. ) */\r
+       \r
+       class Timestamp;        // Cross-reference between Timestamp, Date and Time\r
+       \r
+       class Date\r
+       {\r
+       protected:\r
+               int mDate;      // The date : 1 == 1 Jan 1900\r
+\r
+       public:\r
+               void Clear()    { mDate = MinDate - 1; };\r
+               void Today();\r
+               void SetDate(int year, int month, int day);\r
+               void SetDate(int dt);\r
+               void GetDate(int& year, int& month, int& day) const;\r
+               int GetDate() const     { return mDate; }\r
+               int Year() const;\r
+               int Month() const;\r
+               int Day() const;\r
+               void Add(int days);\r
+               void StartOfMonth();\r
+               void EndOfMonth();\r
+       \r
+               Date()                  { Clear(); };\r
+               Date(int dt)    { SetDate(dt); }\r
+               Date(int year, int month, int day);\r
+               Date(const Date&);                                                      // Copy Constructor\r
+               Date& operator=(const Timestamp&);                      // Timestamp Assignment operator\r
+               Date& operator=(const Date&);                           // Date Assignment operator\r
+\r
+               bool operator==(const Date& rv) const { return mDate == rv.GetDate(); }\r
+               bool operator!=(const Date& rv) const { return mDate != rv.GetDate(); }\r
+               bool operator<(const Date& rv) const { return mDate < rv.GetDate(); }\r
+               bool operator>(const Date& rv) const { return mDate > rv.GetDate(); }\r
+\r
+               virtual ~Date() { };\r
+       };\r
+\r
+       /* Class Time represent purely a Time. It is usefull in interactions\r
+        * with the SQL TIME type of Interbase. */\r
+\r
+       class Time\r
+       {\r
+       protected:\r
+               int mTime;      // The time, in ten-thousandths of seconds since midnight\r
+\r
+       public:\r
+               void Clear()    { mTime = 0; }\r
+               void Now();\r
+               void SetTime(int hour, int minute, int second, int tenthousandths = 0);\r
+               void SetTime(int tm);\r
+               void GetTime(int& hour, int& minute, int& second) const;\r
+               void GetTime(int& hour, int& minute, int& second, int& tenthousandths) const;\r
+               int GetTime() const     { return mTime; }\r
+               int Hours() const;\r
+               int Minutes() const;\r
+               int Seconds() const;\r
+               int SubSeconds() const;         // Actually tenthousandths of seconds\r
+               Time()                  { Clear(); }\r
+               Time(int tm)    { SetTime(tm); }\r
+               Time(int hour, int minute, int second, int tenthousandths = 0);\r
+               Time(const Time&);                                                      // Copy Constructor\r
+               Time& operator=(const Timestamp&);                      // Timestamp Assignment operator\r
+               Time& operator=(const Time&);                           // Time Assignment operator\r
+\r
+               bool operator==(const Time& rv) const { return mTime == rv.GetTime(); }\r
+               bool operator!=(const Time& rv) const { return mTime != rv.GetTime(); }\r
+               bool operator<(const Time& rv) const { return mTime < rv.GetTime(); }\r
+               bool operator>(const Time& rv) const { return mTime > rv.GetTime(); }\r
+\r
+               virtual ~Time() { };\r
+       };\r
+\r
+       /* Class Timestamp represent a date AND a time. It is usefull in\r
+        * interactions with the SQL TIMESTAMP type of Interbase. This class\r
+        * inherits from Date and Time and completely inline implements its small\r
+        * specific details. */\r
+\r
+       class Timestamp : public Date, public Time\r
+       {\r
+       public:\r
+               void Clear()    { Date::Clear(); Time::Clear(); }\r
+               void Today()    { Date::Today(); Time::Clear(); }\r
+               void Now()              { Date::Today(); Time::Now(); }\r
+\r
+               Timestamp()             { Clear(); }\r
+\r
+               Timestamp(int y, int m, int d)\r
+                       { Date::SetDate(y, m, d); Time::Clear(); }\r
+\r
+               Timestamp(int y, int mo, int d, int h, int mi, int s, int t = 0)\r
+                       { Date::SetDate(y, mo, d); Time::SetTime(h, mi, s, t); }\r
+\r
+               Timestamp(const Timestamp& rv)\r
+                       : Date(rv.mDate), Time(rv.mTime) {}     // Copy Constructor\r
+\r
+               Timestamp(const Date& rv)\r
+                       { mDate = rv.GetDate(); mTime = 0; }\r
+\r
+               Timestamp(const Time& rv)\r
+                       { mDate = 0; mTime = rv.GetTime(); }\r
+\r
+               Timestamp& operator=(const Timestamp& rv)       // Timestamp Assignment operator\r
+                       { mDate = rv.mDate; mTime = rv.mTime; return *this; }\r
+\r
+               Timestamp& operator=(const Date& rv)            // Date Assignment operator\r
+                       { mDate = rv.GetDate(); return *this; }\r
+\r
+               Timestamp& operator=(const Time& rv)            // Time Assignment operator\r
+                       { mTime = rv.GetTime(); return *this; }\r
+\r
+               bool operator==(const Timestamp& rv) const\r
+                       { return (mDate == rv.GetDate()) && (mTime == rv.GetTime()); }\r
+\r
+               bool operator!=(const Timestamp& rv) const\r
+                       { return (mDate != rv.GetDate()) || (mTime != rv.GetTime()); }\r
+\r
+               bool operator<(const Timestamp& rv) const\r
+                       { return (mDate < rv.GetDate()) ||\r
+                               (mDate == rv.GetDate() && mTime < rv.GetTime()); }\r
+\r
+               bool operator>(const Timestamp& rv) const\r
+                       { return (mDate > rv.GetDate()) ||\r
+                               (mDate == rv.GetDate() && mTime > rv.GetTime()); }\r
+\r
+               ~Timestamp() { }\r
+       };\r
+\r
+       /* Class DBKey can store a DBKEY, that special value which the hidden\r
+        * RDB$DBKEY can give you from a select statement. A DBKey is nothing\r
+        * specific to IBPP. It's a feature of the Firebird database engine. See its\r
+        * documentation for more information. */\r
+\r
+       class DBKey\r
+       {\r
+       private:\r
+               std::string mDBKey;                     // Stores the binary DBKey\r
+               mutable std::string mString;// String (temporary) representation of it\r
+\r
+       public:\r
+               void Clear();\r
+               int Size() const        { return (int)mDBKey.size(); }\r
+               void SetKey(const void*, int size);\r
+               void GetKey(void*, int size) const;\r
+               const char* AsString() const;\r
+\r
+               DBKey& operator=(const DBKey&); // Assignment operator\r
+               DBKey(const DBKey&);                    // Copy Constructor\r
+               DBKey() { }\r
+               ~DBKey() { }\r
+       };\r
+\r
+       /* Class User wraps all the information about a user that the engine can manage. */\r
+\r
+       class User\r
+       {\r
+       public:\r
+               std::string username;\r
+               std::string password;\r
+               std::string firstname;\r
+               std::string middlename;\r
+               std::string lastname;\r
+               uint32_t userid;                // Only relevant on unixes\r
+               uint32_t groupid;               // Only relevant on unixes\r
+\r
+       private:\r
+               void copyfrom(const User& r);\r
+\r
+       public:\r
+               void clear();\r
+               User& operator=(const User& r)  { copyfrom(r); return *this; }\r
+               User(const User& r)                             { copyfrom(r); }\r
+               User() : userid(0), groupid(0)  { }\r
+               ~User() { };\r
+       };\r
+\r
+       //      Interface Wrapper\r
+       template <class T>\r
+       class Ptr\r
+       {\r
+       private:\r
+               T* mObject;\r
+\r
+       public:\r
+               void clear()\r
+               {\r
+                       if (mObject != 0) { mObject->Release(); mObject = 0; }\r
+               }\r
+\r
+               T* intf() const                                         { return mObject; }\r
+               T* operator->() const                           { return mObject; }\r
+\r
+               bool operator==(const T* p) const       { return mObject == p; }\r
+               bool operator==(const Ptr& r) const     { return mObject == r.mObject; }\r
+               bool operator!=(const T* p) const       { return mObject != p; }\r
+               bool operator!=(const Ptr& r) const     { return mObject != r.mObject; }\r
+\r
+               Ptr& operator=(T* p)\r
+               {\r
+                       // AddRef _before_ Release gives correct behaviour on self-assigns\r
+                       T* tmp = (p == 0 ? 0 : p->AddRef());    // Take care of 0\r
+                       if (mObject != 0) mObject->Release();\r
+                       mObject = tmp; return *this;\r
+               }\r
+\r
+               Ptr& operator=(const Ptr& r)\r
+               {\r
+                       // AddRef _before_ Release gives correct behaviour on self-assigns\r
+                       T* tmp = (r.intf() == 0 ? 0 : r->AddRef());// Take care of 0\r
+                       if (mObject != 0) mObject->Release();\r
+                       mObject = tmp; return *this;\r
+               }\r
+\r
+               Ptr(T* p) : mObject(p == 0 ? 0 : p->AddRef()) { }\r
+               Ptr(const Ptr& r) : mObject(r.intf() == 0 ? 0 : r->AddRef()) {  }\r
+\r
+               Ptr() : mObject(0) { }\r
+               ~Ptr() { clear(); }\r
+       };\r
+\r
+       //      --- Interface Classes --- //\r
+\r
+       /* Interfaces IBlob, IArray, IService, IDatabase, ITransaction and\r
+        * IStatement are at the core of IBPP. Though it is possible to program your\r
+        * applications by using theses interfaces directly (as was the case with\r
+        * IBPP 1.x), you should refrain from using them and prefer the new IBPP\r
+        * Objects Blob, Array, ... (without the I in front). Those new objects are\r
+        * typedef'd right after each interface class definition as you can read\r
+        * below. If you program using the Blob (instead of the IBlob interface\r
+        * itself), you'll never have to care about AddRef/Release and you'll never\r
+        * have to care about deleting your objects. */\r
+\r
+       class IBlob;                    typedef Ptr<IBlob> Blob;\r
+       class IArray;                   typedef Ptr<IArray> Array;\r
+       class IService;                 typedef Ptr<IService> Service;\r
+       class IDatabase;                typedef Ptr<IDatabase> Database;\r
+       class ITransaction;             typedef Ptr<ITransaction> Transaction;\r
+       class IStatement;               typedef Ptr<IStatement> Statement;\r
+       class IEvents;                  typedef Ptr<IEvents> Events;\r
+       class IRow;                             typedef Ptr<IRow> Row;\r
+\r
+       /* IBlob is the interface to the blob capabilities of IBPP. Blob is the\r
+        * object class you actually use in your programming. In Firebird, at the\r
+        * row level, a blob is merely a handle to a blob, stored elsewhere in the\r
+        * database. Blob allows you to retrieve such a handle and then read from or\r
+        * write to the blob, much in the same manner than you would do with a file. */\r
+\r
+       class IBlob\r
+       {\r
+       public:\r
+               virtual void Create() = 0;\r
+               virtual void Open() = 0;\r
+               virtual void Close() = 0;\r
+               virtual void Cancel() = 0;\r
+               virtual int Read(void*, int size) = 0;\r
+               virtual void Write(const void*, int size) = 0;\r
+               virtual void Info(int* Size, int* Largest, int* Segments) = 0;\r
+       \r
+               virtual void Save(const std::string& data) = 0;\r
+               virtual void Load(std::string& data) = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IBlob* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+               virtual ~IBlob() { };\r
+       };\r
+\r
+       /*      IArray is the interface to the array capabilities of IBPP. Array is the\r
+       * object class you actually use in your programming. With an Array object, you\r
+       * can create, read and write Interbase Arrays, as a whole or in slices. */\r
+\r
+       class IArray\r
+       {\r
+       public:\r
+               virtual void Describe(const std::string& table, const std::string& column) = 0;\r
+               virtual void ReadTo(ADT, void* buffer, int elemcount) = 0;\r
+               virtual void WriteFrom(ADT, const void* buffer, int elemcount) = 0;\r
+               virtual SDT ElementType() = 0;\r
+               virtual int ElementSize() = 0;\r
+               virtual int ElementScale() = 0;\r
+               virtual int Dimensions() = 0;\r
+               virtual void Bounds(int dim, int* low, int* high) = 0;\r
+               virtual void SetBounds(int dim, int low, int high) = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IArray* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+               virtual ~IArray() { };\r
+       };\r
+\r
+       /* IService is the interface to the service capabilities of IBPP. Service is\r
+        * the object class you actually use in your programming. With a Service\r
+        * object, you can do some maintenance work of databases and servers\r
+        * (backup, restore, create/update users, ...) */\r
+\r
+       class IService\r
+       {\r
+       public:\r
+           virtual void Connect() = 0;\r
+               virtual bool Connected() = 0;\r
+               virtual void Disconnect() = 0;\r
+\r
+               virtual void GetVersion(std::string& version) = 0;\r
+\r
+               virtual void AddUser(const User&) = 0;\r
+               virtual void GetUser(User&) = 0;\r
+               virtual void GetUsers(std::vector<User>&) = 0;\r
+               virtual void ModifyUser(const User&) = 0;\r
+               virtual void RemoveUser(const std::string& username) = 0;\r
+\r
+               virtual void SetPageBuffers(const std::string& dbfile, int buffers) = 0;\r
+               virtual void SetSweepInterval(const std::string& dbfile, int sweep) = 0;\r
+               virtual void SetSyncWrite(const std::string& dbfile, bool) = 0;\r
+               virtual void SetReadOnly(const std::string& dbfile, bool) = 0;\r
+               virtual void SetReserveSpace(const std::string& dbfile, bool) = 0;\r
+\r
+               virtual void Shutdown(const std::string& dbfile, DSM mode, int sectimeout) = 0;\r
+               virtual void Restart(const std::string& dbfile) = 0;\r
+               virtual void Sweep(const std::string& dbfile) = 0;\r
+               virtual void Repair(const std::string& dbfile, RPF flags) = 0;\r
+\r
+               virtual void StartBackup(const std::string& dbfile,\r
+                       const std::string& bkfile, BRF flags = BRF(0)) = 0;\r
+               virtual void StartRestore(const std::string& bkfile, const std::string& dbfile,\r
+                       int pagesize = 0, BRF flags = BRF(0)) = 0;\r
+\r
+               virtual const char* WaitMsg() = 0;      // With reporting (does not block)\r
+               virtual void Wait() = 0;                        // Without reporting (does block)\r
+\r
+               virtual IService* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+               virtual ~IService() { };\r
+       };\r
+\r
+       /*      IDatabase is the interface to the database connections in IBPP. Database\r
+        * is the object class you actually use in your programming. With a Database\r
+        * object, you can create/drop/connect databases. */\r
+\r
+       class EventInterface;   // Cross-reference between EventInterface and IDatabase\r
+       \r
+       class IDatabase\r
+       {\r
+       public:\r
+               virtual const char* ServerName() const = 0;\r
+               virtual const char* DatabaseName() const = 0;\r
+               virtual const char* Username() const = 0;\r
+               virtual const char* UserPassword() const = 0;\r
+               virtual const char* RoleName() const = 0;\r
+               virtual const char* CharSet() const = 0;\r
+               virtual const char* CreateParams() const = 0;\r
+\r
+               virtual void Info(int* ODS, int* ODSMinor, int* PageSize,\r
+                       int* Pages,     int* Buffers, int* Sweep, bool* Sync,\r
+                       bool* Reserve) = 0;\r
+               virtual void Statistics(int* Fetches, int* Marks,\r
+                       int* Reads, int* Writes) = 0;\r
+               virtual void Counts(int* Insert, int* Update, int* Delete, \r
+                       int* ReadIdx, int* ReadSeq) = 0;\r
+               virtual void Users(std::vector<std::string>& users) = 0;\r
+               virtual int Dialect() = 0;\r
+\r
+               virtual void Create(int dialect) = 0;\r
+               virtual void Connect() = 0;\r
+               virtual bool Connected() = 0;\r
+               virtual void Inactivate() = 0;\r
+               virtual void Disconnect() = 0;\r
+               virtual void Drop() = 0;\r
+\r
+               virtual IDatabase* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IDatabase() { };\r
+       };\r
+\r
+       /* ITransaction is the interface to the transaction connections in IBPP.\r
+        * Transaction is the object class you actually use in your programming. A\r
+        * Transaction object can be associated with more than one Database,\r
+        * allowing for distributed transactions spanning multiple databases,\r
+        * possibly located on different servers. IBPP is one among the few\r
+        * programming interfaces to Firebird that allows you to support distributed\r
+        * transactions. */\r
+\r
+       class ITransaction\r
+       {\r
+       public:\r
+           virtual void AttachDatabase(Database db, TAM am = amWrite,\r
+                       TIL il = ilConcurrency, TLR lr = lrWait, TFF flags = TFF(0)) = 0;\r
+           virtual void DetachDatabase(Database db) = 0;\r
+               virtual void AddReservation(Database db,\r
+                               const std::string& table, TTR tr) = 0;\r
+\r
+               virtual void Start() = 0;\r
+               virtual bool Started() = 0;\r
+           virtual void Commit() = 0;\r
+           virtual void Rollback() = 0;\r
+           virtual void CommitRetain() = 0;\r
+               virtual void RollbackRetain() = 0;\r
+\r
+               virtual ITransaction* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~ITransaction() { };\r
+       };\r
+\r
+       /*\r
+        *      Class Row can hold all the values of a row (from a SELECT for instance).\r
+        */\r
+\r
+       class IRow\r
+       {\r
+       public:\r
+               virtual void SetNull(int) = 0;\r
+               virtual void Set(int, bool) = 0;\r
+               virtual void Set(int, const void*, int) = 0;            // byte buffers\r
+               virtual void Set(int, const char*) = 0;                         // c-string\r
+               virtual void Set(int, const std::string&) = 0;\r
+               virtual void Set(int, int16_t) = 0;\r
+               virtual void Set(int, int32_t) = 0;\r
+               virtual void Set(int, int64_t) = 0;\r
+               virtual void Set(int, float) = 0;\r
+               virtual void Set(int, double) = 0;\r
+               virtual void Set(int, const Timestamp&) = 0;\r
+               virtual void Set(int, const Date&) = 0;\r
+               virtual void Set(int, const Time&) = 0;\r
+               virtual void Set(int, const DBKey&) = 0;\r
+               virtual void Set(int, const Blob&) = 0;\r
+               virtual void Set(int, const Array&) = 0;\r
+\r
+               virtual bool IsNull(int) = 0;\r
+               virtual bool Get(int, bool&) = 0;\r
+               virtual bool Get(int, void*, int&) = 0; // byte buffers\r
+               virtual bool Get(int, std::string&) = 0;\r
+               virtual bool Get(int, int16_t&) = 0;\r
+               virtual bool Get(int, int32_t&) = 0;\r
+               virtual bool Get(int, int64_t&) = 0;\r
+               virtual bool Get(int, float&) = 0;\r
+               virtual bool Get(int, double&) = 0;\r
+               virtual bool Get(int, Timestamp&) = 0;\r
+               virtual bool Get(int, Date&) = 0;\r
+               virtual bool Get(int, Time&) = 0;\r
+               virtual bool Get(int, DBKey&) = 0;\r
+               virtual bool Get(int, Blob&) = 0;\r
+               virtual bool Get(int, Array&) = 0;\r
+\r
+               virtual bool IsNull(const std::string&) = 0;\r
+               virtual bool Get(const std::string&, bool&) = 0;\r
+               virtual bool Get(const std::string&, void*, int&) = 0;  // byte buffers\r
+               virtual bool Get(const std::string&, std::string&) = 0;\r
+               virtual bool Get(const std::string&, int16_t&) = 0;\r
+               virtual bool Get(const std::string&, int32_t&) = 0;\r
+               virtual bool Get(const std::string&, int64_t&) = 0;\r
+               virtual bool Get(const std::string&, float&) = 0;\r
+               virtual bool Get(const std::string&, double&) = 0;\r
+               virtual bool Get(const std::string&, Timestamp&) = 0;\r
+               virtual bool Get(const std::string&, Date&) = 0;\r
+               virtual bool Get(const std::string&, Time&) = 0;\r
+               virtual bool Get(const std::string&, DBKey&) = 0;\r
+               virtual bool Get(const std::string&, Blob&) = 0;\r
+               virtual bool Get(const std::string&, Array&) = 0;\r
+\r
+               virtual int ColumnNum(const std::string&) = 0;\r
+               virtual const char* ColumnName(int) = 0;\r
+               virtual const char* ColumnAlias(int) = 0;\r
+               virtual const char* ColumnTable(int) = 0;\r
+               virtual SDT ColumnType(int) = 0;\r
+               virtual int ColumnSubtype(int) = 0;\r
+               virtual int ColumnSize(int) = 0;\r
+               virtual int ColumnScale(int) = 0;\r
+               virtual int Columns() = 0;\r
+               \r
+               virtual bool ColumnUpdated(int) = 0;\r
+               virtual bool Updated() = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IRow* Clone() = 0;\r
+               virtual IRow* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IRow() {};\r
+       };\r
+\r
+       /* IStatement is the interface to the statements execution in IBPP.\r
+        * Statement is the object class you actually use in your programming. A\r
+        * Statement object is the work horse of IBPP. All your data manipulation\r
+        * statements will be done through it. It is also used to access the result\r
+        * set of a query (when the statement is such), one row at a time and in\r
+        * strict forward direction. */\r
+\r
+       class IStatement\r
+       {\r
+       public:\r
+               virtual void Prepare(const std::string&) = 0;\r
+               virtual void Execute() = 0;\r
+               virtual void Execute(const std::string&) = 0;\r
+               virtual void ExecuteImmediate(const std::string&) = 0;\r
+               virtual void CursorExecute(const std::string& cursor) = 0;\r
+               virtual void CursorExecute(const std::string& cursor, const std::string&) = 0;\r
+               virtual bool Fetch() = 0;\r
+               virtual bool Fetch(Row&) = 0;\r
+               virtual int AffectedRows() = 0;\r
+               virtual void Close() = 0;\r
+               virtual std::string& Sql() = 0;\r
+               virtual STT Type() = 0;\r
+\r
+               virtual void SetNull(int) = 0;\r
+               virtual void Set(int, bool) = 0;\r
+               virtual void Set(int, const void*, int) = 0;            // byte buffers\r
+               virtual void Set(int, const char*) = 0;                         // c-string\r
+               virtual void Set(int, const std::string&) = 0;\r
+               virtual void Set(int, int16_t value) = 0;\r
+               virtual void Set(int, int32_t value) = 0;\r
+               virtual void Set(int, int64_t value) = 0;\r
+               virtual void Set(int, float value) = 0;\r
+               virtual void Set(int, double value) = 0;\r
+               virtual void Set(int, const Timestamp& value) = 0;\r
+               virtual void Set(int, const Date& value) = 0;\r
+               virtual void Set(int, const Time& value) = 0;\r
+               virtual void Set(int, const DBKey& value) = 0;\r
+               virtual void Set(int, const Blob& value) = 0;\r
+               virtual void Set(int, const Array& value) = 0;\r
+\r
+               virtual bool IsNull(int) = 0;\r
+               virtual bool Get(int, bool&) = 0;\r
+               virtual bool Get(int, void*, int&) = 0; // byte buffers\r
+               virtual bool Get(int, std::string&) = 0;\r
+               virtual bool Get(int, int16_t&) = 0;\r
+               virtual bool Get(int, int32_t&) = 0;\r
+               virtual bool Get(int, int64_t&) = 0;\r
+               virtual bool Get(int, float&) = 0;\r
+               virtual bool Get(int, double&) = 0;\r
+               virtual bool Get(int, Timestamp& value) = 0;\r
+               virtual bool Get(int, Date& value) = 0;\r
+               virtual bool Get(int, Time& value) = 0;\r
+               virtual bool Get(int, DBKey& value) = 0;\r
+               virtual bool Get(int, Blob& value) = 0;\r
+               virtual bool Get(int, Array& value) = 0;\r
+\r
+               virtual bool IsNull(const std::string&) = 0;\r
+               virtual bool Get(const std::string&, bool&) = 0;\r
+               virtual bool Get(const std::string&, void*, int&) = 0;  // byte buffers\r
+               virtual bool Get(const std::string&, std::string&) = 0;\r
+               virtual bool Get(const std::string&, int16_t&) = 0;\r
+               virtual bool Get(const std::string&, int32_t&) = 0;\r
+               virtual bool Get(const std::string&, int64_t&) = 0;\r
+               virtual bool Get(const std::string&, float&) = 0;\r
+               virtual bool Get(const std::string&, double&) = 0;\r
+               virtual bool Get(const std::string&, Timestamp& value) = 0;\r
+               virtual bool Get(const std::string&, Date& value) = 0;\r
+               virtual bool Get(const std::string&, Time& value) = 0;\r
+               virtual bool Get(const std::string&, DBKey& value) = 0;\r
+               virtual bool Get(const std::string&, Blob& value) = 0;\r
+               virtual bool Get(const std::string&, Array& value) = 0;\r
+\r
+               virtual int ColumnNum(const std::string&) = 0;\r
+               virtual const char* ColumnName(int) = 0;\r
+               virtual const char* ColumnAlias(int) = 0;\r
+               virtual const char* ColumnTable(int) = 0;\r
+               virtual SDT ColumnType(int) = 0;\r
+               virtual int ColumnSubtype(int) = 0;\r
+               virtual int ColumnSize(int) = 0;\r
+               virtual int ColumnScale(int) = 0;\r
+               virtual int Columns() = 0;\r
+\r
+               virtual SDT ParameterType(int) = 0;\r
+               virtual int ParameterSubtype(int) = 0;\r
+               virtual int ParameterSize(int) = 0;\r
+               virtual int ParameterScale(int) = 0;\r
+               virtual int Parameters() = 0;\r
+\r
+               virtual void Plan(std::string&) = 0;\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+               virtual Transaction TransactionPtr() const = 0;\r
+\r
+               virtual IStatement* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IStatement() { };\r
+\r
+               // DEPRECATED METHODS (WON'T BE AVAILABLE IN VERSIONS 3.x)\r
+               virtual bool Get(int, char*) = 0;                                       // DEPRECATED\r
+               virtual bool Get(const std::string&, char*) = 0;        // DEPRECATED\r
+               virtual bool Get(int, bool*) = 0;                                       // DEPRECATED\r
+               virtual bool Get(const std::string&, bool*) = 0;        // DEPRECATED\r
+               virtual bool Get(int, int16_t*) = 0;                            // DEPRECATED\r
+               virtual bool Get(const std::string&, int16_t*) = 0;     // DEPRECATED\r
+               virtual bool Get(int, int32_t*) = 0;                            // DEPRECATED\r
+               virtual bool Get(const std::string&, int32_t*) = 0;     // DEPRECATED\r
+               virtual bool Get(int, int64_t*) = 0;                            // DEPRECATED\r
+               virtual bool Get(const std::string&, int64_t*) = 0;     // DEPRECATED\r
+               virtual bool Get(int, float*) = 0;                                      // DEPRECATED\r
+               virtual bool Get(const std::string&, float*) = 0;       // DEPRECATED\r
+               virtual bool Get(int, double*) = 0;                                     // DEPRECATED\r
+               virtual bool Get(const std::string&, double*) = 0;      // DEPRECATED\r
+       };\r
+       \r
+       class IEvents\r
+       {\r
+       public:\r
+               virtual void Add(const std::string&, EventInterface*) = 0;\r
+               virtual void Drop(const std::string&) = 0;\r
+               virtual void List(std::vector<std::string>&) = 0;\r
+               virtual void Clear() = 0;                               // Drop all events\r
+               virtual void Dispatch() = 0;                    // Dispatch events (calls handlers)\r
+\r
+               virtual Database DatabasePtr() const = 0;\r
+\r
+               virtual IEvents* AddRef() = 0;\r
+               virtual void Release() = 0;\r
+\r
+           virtual ~IEvents() { };\r
+       };\r
+       \r
+       /* Class EventInterface is merely a pure interface.\r
+        * It is _not_ implemented by IBPP. It is only a base class definition from\r
+        * which your own event interface classes have to derive from.\r
+        * Please read the reference guide at http://www.ibpp.org for more info. */\r
+\r
+       class EventInterface\r
+       {\r
+       public:\r
+               virtual void ibppEventHandler(Events, const std::string&, int) = 0;\r
+               virtual ~EventInterface() { };\r
+       };\r
+\r
+       //      --- Factories ---\r
+       //      These methods are the only way to get one of the above\r
+       //      Interfaces.  They are at the heart of how you program using IBPP.  For\r
+       //      instance, to get access to a database, you'll write code similar to this:\r
+       //      {\r
+       //              Database db = DatabaseFactory("server", "databasename",\r
+       //                                              "user", "password");\r
+       //              db->Connect();\r
+       //              ...\r
+       //              db->Disconnect();\r
+       //      }\r
+\r
+       Service ServiceFactory(const std::string& ServerName,\r
+               const std::string& UserName, const std::string& UserPassword);\r
+\r
+       Database DatabaseFactory(const std::string& ServerName,\r
+               const std::string& DatabaseName, const std::string& UserName,\r
+                       const std::string& UserPassword, const std::string& RoleName,\r
+                               const std::string& CharSet, const std::string& CreateParams);\r
+\r
+       inline Database DatabaseFactory(const std::string& ServerName,\r
+               const std::string& DatabaseName, const std::string& UserName,\r
+                       const std::string& UserPassword)\r
+               { return DatabaseFactory(ServerName, DatabaseName, UserName, UserPassword, "", "", ""); }\r
+\r
+       Transaction TransactionFactory(Database db, TAM am = amWrite,\r
+               TIL il = ilConcurrency, TLR lr = lrWait, TFF flags = TFF(0));\r
+\r
+       Statement StatementFactory(Database db, Transaction tr,\r
+               const std::string& sql);\r
+\r
+       inline Statement StatementFactory(Database db, Transaction tr)\r
+               { return StatementFactory(db, tr, ""); }\r
+\r
+       Blob BlobFactory(Database db, Transaction tr);\r
+       \r
+       Array ArrayFactory(Database db, Transaction tr);\r
+       \r
+       Events EventsFactory(Database db);\r
+\r
+       /* IBPP uses a self initialization system. Each time an object that may\r
+        * require the usage of the Interbase client C-API library is used, the\r
+        * library internal handling details are automatically initialized, if not\r
+        * already done. You can kick this initialization at the start of an\r
+        * application by calling IBPP::CheckVersion(). This is recommended, because\r
+        * IBPP::CheckVersion will assure you that YOUR code has been compiled\r
+        * against a compatible version of the library. */\r
+\r
+       bool CheckVersion(uint32_t);\r
+       int GDSVersion();\r
+       \r
+       /* On Win32 platform, ClientLibSearchPaths() allows to setup\r
+        * one or multiple additional paths (separated with a ';') where IBPP\r
+        * will look for the client library (before the default implicit search\r
+        * locations). This is usefull for applications distributed with a 'private'\r
+        * copy of Firebird, when the registry is useless to identify the location\r
+        * from where to attempt loading the fbclient.dll / gds32.dll.\r
+        * If called, this function must be called *early* by the application,\r
+        * before *any* other function or object methods of IBPP.\r
+        * Currently, this is a NO-OP on platforms other than Win32. */\r
+        \r
+       void ClientLibSearchPaths(const std::string&);\r
+\r
+       /* Finally, here are some date and time conversion routines used by IBPP and\r
+        * that may be helpful at the application level. They do not depend on\r
+        * anything related to Firebird/Interbase. Just a bonus. dtoi and itod\r
+        * return false on invalid parameters or out of range conversions. */\r
+\r
+       bool dtoi(int date, int* py, int* pm, int* pd);\r
+       bool itod(int* pdate, int year, int month, int day);\r
+       void ttoi(int itime, int* phour, int* pminute, int* psecond, int* ptt);\r
+       void itot(int* ptime, int hour, int minute, int second = 0, int tenthousandths = 0);\r
+\r
+}\r
+\r
+#endif\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/libibpp.so b/stglibs/ibpp.lib/libibpp.so
new file mode 100755 (executable)
index 0000000..7169ab5
Binary files /dev/null and b/stglibs/ibpp.lib/libibpp.so differ
diff --git a/stglibs/ibpp.lib/row.cpp b/stglibs/ibpp.lib/row.cpp
new file mode 100644 (file)
index 0000000..fa6939a
--- /dev/null
@@ -0,0 +1,1580 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: row.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, Row class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <math.h>\r
+#include <time.h>\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void RowImpl::SetNull(int param)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::SetNull", _("The row is not initialized."));\r
+       if (param < 1 || param > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::SetNull", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[param-1]);\r
+       if (! (var->sqltype & 1))\r
+               throw LogicExceptionImpl("Row::SetNull", _("This column can't be null."));\r
+\r
+       *var->sqlind = -1;      // Set the column to SQL NULL\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, bool value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[bool]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivBool, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const char* cstring)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[char*]", _("The row is not initialized."));\r
+       if (cstring == 0)\r
+               throw LogicExceptionImpl("Row::Set[char*]", _("null char* pointer detected."));\r
+\r
+       SetValue(param, ivByte, cstring, (int)strlen(cstring));\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const void* bindata, int len)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[void*]", _("The row is not initialized."));\r
+       if (bindata == 0)\r
+               throw LogicExceptionImpl("Row::Set[void*]", _("null char* pointer detected."));\r
+       if (len < 0)\r
+               throw LogicExceptionImpl("Row::Set[void*]", _("Length must be >= 0"));\r
+               \r
+       SetValue(param, ivByte, bindata, len);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const std::string& s)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[string]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivString, (void*)&s);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, int16_t value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[int16_t]", _("The row is not initialized."));\r
+                                                                                       \r
+       SetValue(param, ivInt16, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, int32_t value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[int32_t]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivInt32, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, int64_t value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[int64_t]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivInt64, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, float value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[float]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivFloat, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, double value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[double]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivDouble, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Timestamp& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Timestamp]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivTimestamp, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Date& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Date]", _("The row is not initialized."));\r
+\r
+       if (mDialect == 1)\r
+       {\r
+               // In dialect 1, IBPP::Date is supposed to work with old 'DATE'\r
+               // fields which are actually ISC_TIMESTAMP.\r
+               IBPP::Timestamp timestamp(value);\r
+               SetValue(param, ivTimestamp, &timestamp);\r
+       }\r
+       else\r
+       {\r
+               // Dialect 3\r
+               SetValue(param, ivDate, (void*)&value);\r
+       }\r
+\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Time& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Time]", _("The row is not initialized."));\r
+       if (mDialect == 1)\r
+               throw LogicExceptionImpl("Row::Set[Time]", _("Requires use of a dialect 3 database."));\r
+\r
+       SetValue(param, ivTime, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Blob& blob)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Blob]", _("The row is not initialized."));\r
+       if (mDatabase != 0 && blob->DatabasePtr() != mDatabase)\r
+               throw LogicExceptionImpl("Row::Set[Blob]",\r
+                       _("IBlob and Row attached to different databases"));\r
+       if (mTransaction != 0 && blob->TransactionPtr() != mTransaction)\r
+               throw LogicExceptionImpl("Row::Set[Blob]",\r
+                       _("IBlob and Row attached to different transactions"));\r
+\r
+       SetValue(param, ivBlob, blob.intf());\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Array& array)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Array]", _("The row is not initialized."));\r
+       if (mDatabase != 0 && array->DatabasePtr() != mDatabase)\r
+               throw LogicExceptionImpl("Row::Set[Array]",\r
+                       _("IArray and Row attached to different databases"));\r
+       if (mTransaction != 0 && array->TransactionPtr() != mTransaction)\r
+               throw LogicExceptionImpl("Row::Set[Array]",\r
+                       _("IArray and Row attached to different transactions"));\r
+\r
+       SetValue(param, ivArray, (void*)array.intf());\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::DBKey& key)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[DBKey]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivDBKey, (void*)&key);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+/*\r
+void RowImpl::Set(int param, const IBPP::Value& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Value]", _("The row is not initialized."));\r
+\r
+       //SetValue(param, ivDBKey, (void*)&key);\r
+       //mUpdated[param-1] = true;\r
+}\r
+*/\r
+\r
+bool RowImpl::IsNull(int column)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));\r
+       if (column < 1 || column > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::IsNull", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[column-1]);\r
+       return ((var->sqltype & 1) && *(var->sqlind) != 0) ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, bool& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivBool);\r
+       if (pvalue != 0)\r
+               retvalue = (*(char*)pvalue == 0 ? false : true);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, char* retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));\r
+\r
+       int sqllen;\r
+       void* pvalue = GetValue(column, ivByte, &sqllen);\r
+       if (pvalue != 0)\r
+       {\r
+               memcpy(retvalue, pvalue, sqllen);\r
+               retvalue[sqllen] = '\0';\r
+       }\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, void* bindata, int& userlen)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+       if (bindata == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));\r
+       if (userlen < 0)\r
+               throw LogicExceptionImpl("Row::Get", _("Length must be >= 0"));\r
+\r
+       int sqllen;\r
+       void* pvalue = GetValue(column, ivByte, &sqllen);\r
+       if (pvalue != 0)\r
+       {\r
+               // userlen says how much bytes the user can accept\r
+               // let's shorten it, if there is less bytes available\r
+               if (sqllen < userlen) userlen = sqllen;\r
+               memcpy(bindata, pvalue, userlen);\r
+       }\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, std::string& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivString, &retvalue);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, int16_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivInt16);\r
+       if (pvalue != 0)\r
+               retvalue = *(int16_t*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, int32_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivInt32);\r
+       if (pvalue != 0)\r
+               retvalue = *(int32_t*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, int64_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivInt64);\r
+       if (pvalue != 0)\r
+               retvalue = *(int64_t*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, float& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivFloat);\r
+       if (pvalue != 0)\r
+               retvalue = *(float*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, double& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivDouble);\r
+       if (pvalue != 0)\r
+               retvalue = *(double*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Timestamp& timestamp)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivTimestamp, (void*)&timestamp);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Date& date)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       if (mDialect == 1)\r
+       {\r
+               // Dialect 1. IBPP::Date is supposed to work with old 'DATE'\r
+               // fields which are actually ISC_TIMESTAMP.\r
+               IBPP::Timestamp timestamp;\r
+               void* pvalue = GetValue(column, ivTimestamp, (void*)&timestamp);\r
+               if (pvalue != 0) date = timestamp;\r
+               return pvalue == 0 ? true : false;\r
+       }\r
+       else\r
+       {\r
+               void* pvalue = GetValue(column, ivDate, (void*)&date);\r
+               return pvalue == 0 ? true : false;\r
+       }\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Time& time)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivTime, (void*)&time);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Blob& retblob)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivBlob, (void*)retblob.intf());\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::DBKey& retkey)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivDBKey, (void*)&retkey);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Array& retarray)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivArray, (void*)retarray.intf());\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+/*\r
+const IBPP::Value RowImpl::Get(int column)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       //void* value = GetValue(column, ivArray, (void*)retarray.intf());\r
+       //return value == 0 ? true : false;\r
+       return IBPP::Value();\r
+}\r
+*/\r
+\r
+bool RowImpl::IsNull(const std::string& name)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));\r
+\r
+       return IsNull(ColumnNum(name));\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, bool& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, char* retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get[char*]", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, void* retvalue, int& count)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get[void*,int]", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue, count);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, std::string& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::GetString", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, int16_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, int32_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, int64_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, float& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, double& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Timestamp& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Date& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Time& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string&name, IBPP::Blob& retblob)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retblob);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::DBKey& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Array& retarray)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retarray);\r
+}\r
+\r
+/*\r
+const IBPP::Value RowImpl::Get(const std::string& name)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name));\r
+}\r
+*/\r
+\r
+int RowImpl::Columns()\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Columns", _("The row is not initialized."));\r
+\r
+       return mDescrArea->sqld;\r
+}\r
+\r
+int RowImpl::ColumnNum(const std::string& name)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnNum", _("The row is not initialized."));\r
+       if (name.empty())\r
+               throw LogicExceptionImpl("Row::ColumnNum", _("Column name <empty> not found."));\r
+\r
+       XSQLVAR* var;\r
+       char Uname[sizeof(var->sqlname)+1];             // Max size of sqlname + '\0'\r
+\r
+       // Local upper case copy of the column name\r
+       size_t len = name.length();\r
+       if (len > sizeof(var->sqlname)) len = sizeof(var->sqlname);\r
+       strncpy(Uname, name.c_str(), len);\r
+       Uname[len] = '\0';\r
+       char* p = Uname;\r
+       while (*p != '\0') { *p = char(toupper(*p)); ++p; }\r
+\r
+       // Loop through the columns of the descriptor\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               var = &(mDescrArea->sqlvar[i]);\r
+               if (var->sqlname_length != (int16_t)len) continue;\r
+               if (strncmp(Uname, var->sqlname, len) == 0) return i+1;\r
+       }\r
+\r
+       // Failed finding the column name, let's retry using the aliases\r
+       char Ualias[sizeof(var->aliasname)+1];          // Max size of aliasname + '\0'\r
+\r
+       // Local upper case copy of the column name\r
+       len = name.length();\r
+       if (len > sizeof(var->aliasname)) len = sizeof(var->aliasname);\r
+       strncpy(Ualias, name.c_str(), len);\r
+       Ualias[len] = '\0';\r
+       p = Ualias;\r
+       while (*p != '\0') { *p = char(toupper(*p)); ++p; }\r
+\r
+       // Loop through the columns of the descriptor\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               var = &(mDescrArea->sqlvar[i]);\r
+               if (var->aliasname_length != (int16_t)len) continue;\r
+               if (strncmp(Ualias, var->aliasname, len) == 0) return i+1;\r
+       }\r
+\r
+       throw LogicExceptionImpl("Row::ColumnNum", _("Could not find matching column."));\r
+#ifdef __DMC__\r
+       return 0;       // DMC errronously warns here about a missing return\r
+#endif\r
+}\r
+\r
+/*\r
+ColumnName, ColumnAlias, ColumnTable : all these 3 have a mistake.\r
+Ideally, the strings should be stored elsewhere (like _Numerics and so on) to\r
+take into account the final '\0' which needs to be added. For now, we insert\r
+the '\0' in the original data, which will cut the 32th character. Not terribly\r
+bad, but should be cleanly rewritten.\r
+*/\r
+\r
+const char* RowImpl::ColumnName(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnName", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumName", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       if (var->sqlname_length >= 31) var->sqlname_length = 31;\r
+       var->sqlname[var->sqlname_length] = '\0';\r
+       return var->sqlname;\r
+}\r
+\r
+const char* RowImpl::ColumnAlias(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnAlias", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnAlias", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       if (var->aliasname_length >= 31) var->aliasname_length = 31;\r
+       var->aliasname[var->aliasname_length] = '\0';\r
+       return var->aliasname;\r
+}\r
+\r
+const char* RowImpl::ColumnTable(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnTable", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnTable", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       if (var->relname_length >= 31) var->relname_length = 31;\r
+       var->relname[var->relname_length] = '\0';\r
+       return var->relname;\r
+}\r
+\r
+IBPP::SDT RowImpl::ColumnType(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnType", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnType", _("Variable index out of range."));\r
+\r
+       IBPP::SDT value;\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+\r
+       switch (var->sqltype & ~1)\r
+       {\r
+               case SQL_TEXT :      value = IBPP::sdString;    break;\r
+               case SQL_VARYING :   value = IBPP::sdString;    break;\r
+               case SQL_SHORT :     value = IBPP::sdSmallint;  break;\r
+               case SQL_LONG :      value = IBPP::sdInteger;   break;\r
+               case SQL_INT64 :     value = IBPP::sdLargeint;  break;\r
+               case SQL_FLOAT :     value = IBPP::sdFloat;     break;\r
+               case SQL_DOUBLE :    value = IBPP::sdDouble;    break;\r
+               case SQL_TIMESTAMP : value = IBPP::sdTimestamp; break;\r
+               case SQL_TYPE_DATE : value = IBPP::sdDate;      break;\r
+               case SQL_TYPE_TIME : value = IBPP::sdTime;      break;\r
+               case SQL_BLOB :      value = IBPP::sdBlob;      break;\r
+               case SQL_ARRAY :     value = IBPP::sdArray;     break;\r
+               default : throw LogicExceptionImpl("Row::ColumnType",\r
+                                               _("Found an unknown sqltype !"));\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+int RowImpl::ColumnSubtype(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnSubtype", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnSubtype", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       return (int)var->sqlsubtype;\r
+}\r
+\r
+int RowImpl::ColumnSize(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnSize", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnSize", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+    return var->sqllen;\r
+}\r
+\r
+int RowImpl::ColumnScale(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnScale", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnScale", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+    return -var->sqlscale;\r
+}\r
+\r
+bool RowImpl::ColumnUpdated(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnUpdated", _("Variable index out of range."));\r
+\r
+       return mUpdated[varnum-1];\r
+}\r
+\r
+bool RowImpl::Updated()\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));\r
+\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+               if (mUpdated[i]) return true;\r
+       return false;\r
+}\r
+\r
+IBPP::Database RowImpl::DatabasePtr() const\r
+{\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::Transaction RowImpl::TransactionPtr() const\r
+{\r
+       return mTransaction;\r
+}\r
+\r
+IBPP::IRow* RowImpl::Clone()\r
+{\r
+       // By definition the clone of an IBPP Row is a new row (so refcount=0).\r
+\r
+       RowImpl* clone = new RowImpl(*this);\r
+       return clone;\r
+}\r
+\r
+IBPP::IRow* RowImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void RowImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void RowImpl::SetValue(int varnum, IITYPE ivType, const void* value, int userlen)\r
+{\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("RowImpl::SetValue", _("Variable index out of range."));\r
+       if (value == 0)\r
+               throw LogicExceptionImpl("RowImpl::SetValue", _("Unexpected null pointer detected."));\r
+\r
+       int16_t len;\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       switch (var->sqltype & ~1)\r
+       {\r
+               case SQL_TEXT :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               std::string* svalue = (std::string*)value;\r
+                               len = (int16_t)svalue->length();\r
+                               if (len > var->sqllen) len = var->sqllen;\r
+                               strncpy(var->sqldata, svalue->c_str(), len);\r
+                               while (len < var->sqllen) var->sqldata[len++] = ' ';\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               if (userlen > var->sqllen) userlen = var->sqllen;\r
+                               memcpy(var->sqldata, value, userlen);\r
+                               while (userlen < var->sqllen) var->sqldata[userlen++] = ' ';\r
+                       }\r
+                       else if (ivType == ivDBKey)\r
+                       {\r
+                               IBPP::DBKey* key = (IBPP::DBKey*)value;\r
+                               key->GetKey(var->sqldata, var->sqllen);\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               var->sqldata[0] = *(bool*)value ? 'T' : 'F';\r
+                               len = 1;\r
+                               while (len < var->sqllen) var->sqldata[len++] = ' ';\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_VARYING :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               std::string* svalue = (std::string*)value;\r
+                               len = (int16_t)svalue->length();\r
+                               if (len > var->sqllen) len = var->sqllen;\r
+                               *(int16_t*)var->sqldata = (int16_t)len;\r
+                               strncpy(var->sqldata+2, svalue->c_str(), len);\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               if (userlen > var->sqllen) userlen = var->sqllen;\r
+                               *(int16_t*)var->sqldata = (int16_t)userlen;\r
+                               memcpy(var->sqldata+2, value, userlen);\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               *(int16_t*)var->sqldata = (int16_t)1;\r
+                               var->sqldata[2] = *(bool*)value ? 'T' : 'F';\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_SHORT :\r
+                       if (ivType == ivBool)\r
+                       {\r
+                               *(int16_t*)var->sqldata = int16_t(*(bool*)value ? 1 : 0);\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               *(int16_t*)var->sqldata = *(int16_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               if (*(int32_t*)value < consts::min16 || *(int32_t*)value > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               *(int16_t*)var->sqldata = (int16_t)*(int32_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               if (*(int64_t*)value < consts::min16 || *(int64_t*)value > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               *(int16_t*)var->sqldata = (int16_t)*(int64_t*)value;\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int16_t*)var->sqldata =\r
+                                       (int16_t)floor(*(float*)value * multiplier + 0.5);\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int16_t*)var->sqldata =\r
+                                       (int16_t)floor(*(double*)value * multiplier + 0.5);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_LONG :\r
+                       if (ivType == ivBool)\r
+                       {\r
+                               *(ISC_LONG*)var->sqldata = *(bool*)value ? 1 : 0;\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               *(ISC_LONG*)var->sqldata = *(int16_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               *(ISC_LONG*)var->sqldata = *(ISC_LONG*)value;\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               if (*(int64_t*)value < consts::min32 || *(int64_t*)value > consts::max32)\r
+                                       throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               *(ISC_LONG*)var->sqldata = (ISC_LONG)*(int64_t*)value;\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(ISC_LONG*)var->sqldata =\r
+                                       (ISC_LONG)floor(*(float*)value * multiplier + 0.5);\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(ISC_LONG*)var->sqldata =\r
+                                       (ISC_LONG)floor(*(double*)value * multiplier + 0.5);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_INT64 :\r
+                       if (ivType == ivBool)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(bool*)value ? 1 : 0;\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(int16_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(int32_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(int64_t*)value;\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int64_t*)var->sqldata =\r
+                                       (int64_t)floor(*(float*)value * multiplier + 0.5);\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int64_t*)var->sqldata =\r
+                                       (int64_t)floor(*(double*)value * multiplier + 0.5);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_FLOAT :\r
+                       if (ivType != ivFloat || var->sqlscale != 0)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                       _("Incompatible types."));\r
+                       *(float*)var->sqldata = *(float*)value;\r
+                       break;\r
+\r
+               case SQL_DOUBLE :\r
+                       if (ivType != ivDouble)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       if (var->sqlscale != 0)\r
+                       {\r
+                               // Round to scale of NUMERIC(x,y)\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(double*)var->sqldata =\r
+                                       floor(*(double*)value * multiplier + 0.5) / multiplier;\r
+                       }\r
+                       else *(double*)var->sqldata = *(double*)value;\r
+                       break;\r
+\r
+               case SQL_TIMESTAMP :\r
+                       if (ivType != ivTimestamp)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       encodeTimestamp(*(ISC_TIMESTAMP*)var->sqldata, *(IBPP::Timestamp*)value);\r
+                       break;\r
+\r
+               case SQL_TYPE_DATE :\r
+                       if (ivType != ivDate)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       encodeDate(*(ISC_DATE*)var->sqldata, *(IBPP::Date*)value);\r
+                       break;\r
+\r
+               case SQL_TYPE_TIME :\r
+                       if (ivType != ivTime)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                                       _("Incompatible types."));\r
+                       encodeTime(*(ISC_TIME*)var->sqldata, *(IBPP::Time*)value);\r
+                       break;\r
+\r
+               case SQL_BLOB :\r
+                       if (ivType == ivBlob)\r
+                       {\r
+                               BlobImpl* blob = (BlobImpl*)value;\r
+                               blob->GetId((ISC_QUAD*)var->sqldata);\r
+                       }\r
+                       else if (ivType == ivString)\r
+                       {\r
+                               BlobImpl blob(mDatabase, mTransaction);\r
+                               blob.Save(*(std::string*)value);\r
+                               blob.GetId((ISC_QUAD*)var->sqldata);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_ARRAY :\r
+                       if (ivType != ivArray)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       {\r
+                               ArrayImpl* array = (ArrayImpl*)value;\r
+                               array->GetId((ISC_QUAD*)var->sqldata);\r
+                               // When an array has been affected to a column, we want to reset\r
+                               // its ID. This way, the next WriteFrom() on the same Array object\r
+                               // will allocate a new ID. This protects against storing the same\r
+                               // array ID in multiple columns or rows.\r
+                               array->ResetId();\r
+                       }\r
+                       break;\r
+\r
+               default : throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("The field uses an unsupported SQL type !"));\r
+       }\r
+\r
+       if (var->sqltype & 1) *var->sqlind = 0;         // Remove the 0 flag\r
+}\r
+\r
+void* RowImpl::GetValue(int varnum, IITYPE ivType, void* retvalue)\r
+{\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("RowImpl::GetValue", _("Variable index out of range."));\r
+\r
+       void* value;\r
+       int len;\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+\r
+       // When there is no value (SQL NULL)\r
+       if ((var->sqltype & 1) && *(var->sqlind) != 0) return 0;\r
+\r
+       switch (var->sqltype & ~1)\r
+       {\r
+               case SQL_TEXT :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               // In case of ivString, 'void* retvalue' points to a std::string where we\r
+                               // will directly store the data.\r
+                               std::string* str = (std::string*)retvalue;\r
+                               str->erase();\r
+                               str->append(var->sqldata, var->sqllen);\r
+                               value = retvalue;       // value != 0 means 'not null'\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               // In case of ivByte, void* retvalue points to an int where we\r
+                               // will store the len of the available data\r
+                               if (retvalue != 0) *(int*)retvalue = var->sqllen;\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivDBKey)\r
+                       {\r
+                               IBPP::DBKey* key = (IBPP::DBKey*)retvalue;\r
+                               key->SetKey(var->sqldata, var->sqllen);\r
+                               value = retvalue;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               mBools[varnum-1] = 0;\r
+                               if (var->sqllen >= 1)\r
+                               {\r
+                                       char c = var->sqldata[0];\r
+                                       if (c == 't' || c == 'T' || c == 'y' || c == 'Y' ||     c == '1')\r
+                                               mBools[varnum-1] = 1;\r
+                               }\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_VARYING :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               // In case of ivString, 'void* retvalue' points to a std::string where we\r
+                               // will directly store the data.\r
+                               std::string* str = (std::string*)retvalue;\r
+                               str->erase();\r
+                               str->append(var->sqldata+2, (int32_t)*(int16_t*)var->sqldata);\r
+                               value = retvalue;\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               // In case of ivByte, void* retvalue points to an int where we\r
+                               // will store the len of the available data\r
+                               if (retvalue != 0) *(int*)retvalue = (int)*(int16_t*)var->sqldata;\r
+                               value = var->sqldata+2;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               mBools[varnum-1] = 0;\r
+                               len = *(int16_t*)var->sqldata;\r
+                               if (len >= 1)\r
+                               {\r
+                                       char c = var->sqldata[2];\r
+                                       if (c == 't' || c == 'T' || c == 'y' || c == 'Y' ||     c == '1')\r
+                                               mBools[varnum-1] = 1;\r
+                               }\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_SHORT :\r
+                       if (ivType == ivInt16)\r
+                       {\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               if (*(int16_t*)var->sqldata == 0) mBools[varnum-1] = 0;\r
+                               else mBools[varnum-1] = 1;\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               mInt32s[varnum-1] = *(int16_t*)var->sqldata;\r
+                               value = &mInt32s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               mInt64s[varnum-1] = *(int16_t*)var->sqldata;\r
+                               value = &mInt64s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mFloats[varnum-1] = (float)(*(int16_t*)var->sqldata / divisor);\r
+\r
+                               value = &mFloats[varnum-1];\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] = *(int16_t*)var->sqldata / divisor;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_LONG :\r
+                       if (ivType == ivInt32)\r
+                       {\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               if (*(int32_t*)var->sqldata == 0) mBools[varnum-1] = 0;\r
+                               else mBools[varnum-1] = 1;\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               int32_t tmp = *(int32_t*)var->sqldata;\r
+                               if (tmp < consts::min16 || tmp > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               mInt16s[varnum-1] = (int16_t)tmp;\r
+                               value = &mInt16s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               mInt64s[varnum-1] = *(int32_t*)var->sqldata;\r
+                               value = &mInt64s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mFloats[varnum-1] = (float)(*(int32_t*)var->sqldata / divisor);\r
+                               value = &mFloats[varnum-1];\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] = *(int32_t*)var->sqldata / divisor;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_INT64 :\r
+                       if (ivType == ivInt64)\r
+                       {\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               if (*(int64_t*)var->sqldata == 0) mBools[varnum-1] = 0;\r
+                               else mBools[varnum-1] = 1;\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               int64_t tmp = *(int64_t*)var->sqldata;\r
+                               if (tmp < consts::min16 || tmp > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               mInt16s[varnum-1] = (int16_t)tmp;\r
+                               value = &mInt16s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               int64_t tmp = *(int64_t*)var->sqldata;\r
+                               if (tmp < consts::min32 || tmp > consts::max32)\r
+                                       throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               mInt32s[varnum-1] = (int32_t)tmp;\r
+                               value = &mInt32s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mFloats[varnum-1] = (float)(*(int64_t*)var->sqldata / divisor);\r
+                               value = &mFloats[varnum-1];\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] = *(int64_t*)var->sqldata / divisor;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_FLOAT :\r
+                       if (ivType != ivFloat)\r
+                               throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       value = var->sqldata;\r
+                       break;\r
+\r
+               case SQL_DOUBLE :\r
+                       if (ivType != ivDouble)\r
+                               throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       if (var->sqlscale != 0)\r
+                       {\r
+                               // Round to scale y of NUMERIC(x,y)\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] =\r
+                                       floor(*(double*)var->sqldata * multiplier + 0.5) / multiplier;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else value = var->sqldata;\r
+                       break;\r
+\r
+               case SQL_TIMESTAMP :\r
+                       if (ivType != ivTimestamp)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       decodeTimestamp(*(IBPP::Timestamp*)retvalue, *(ISC_TIMESTAMP*)var->sqldata);\r
+                       value = retvalue;\r
+                       break;\r
+\r
+               case SQL_TYPE_DATE :\r
+                       if (ivType != ivDate)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       decodeDate(*(IBPP::Date*)retvalue, *(ISC_DATE*)var->sqldata);\r
+                       value = retvalue;\r
+                       break;\r
+\r
+               case SQL_TYPE_TIME :\r
+                       if (ivType != ivTime)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       decodeTime(*(IBPP::Time*)retvalue, *(ISC_TIME*)var->sqldata);\r
+                       value = retvalue;\r
+                       break;\r
+\r
+               case SQL_BLOB :\r
+                       if (ivType == ivBlob)\r
+                       {\r
+                               BlobImpl* blob = (BlobImpl*)retvalue;\r
+                               blob->SetId((ISC_QUAD*)var->sqldata);\r
+                               value = retvalue;\r
+                       }\r
+                       else if (ivType == ivString)\r
+                       {\r
+                               BlobImpl blob(mDatabase, mTransaction);\r
+                               blob.SetId((ISC_QUAD*)var->sqldata);\r
+                               std::string* str = (std::string*)retvalue;\r
+                               blob.Load(*str);\r
+                               value = retvalue;\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+                       \r
+               case SQL_ARRAY :\r
+                       if (ivType != ivArray)\r
+                               throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                                       _("Incompatible types."));\r
+                       {\r
+                               ArrayImpl* array = (ArrayImpl*)retvalue;\r
+                               array->SetId((ISC_QUAD*)var->sqldata);\r
+                               value = retvalue;\r
+                       }\r
+                       break;\r
+\r
+               default : throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Found an unknown sqltype !"));\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+void RowImpl::Free()\r
+{\r
+       if (mDescrArea != 0)\r
+       {\r
+               for (int i = 0; i < mDescrArea->sqln; i++)\r
+               {\r
+                       XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
+                       if (var->sqldata != 0)\r
+                       {\r
+                               switch (var->sqltype & ~1)\r
+                               {\r
+                                       case SQL_ARRAY :\r
+                                       case SQL_BLOB :         delete (ISC_QUAD*) var->sqldata; break;\r
+                                       case SQL_TIMESTAMP :delete (ISC_TIMESTAMP*) var->sqldata; break;\r
+                                       case SQL_TYPE_TIME :delete (ISC_TIME*) var->sqldata; break;\r
+                                       case SQL_TYPE_DATE :delete (ISC_DATE*) var->sqldata; break;\r
+                                       case SQL_TEXT :\r
+                                       case SQL_VARYING :      delete [] var->sqldata; break;\r
+                                       case SQL_SHORT :        delete (int16_t*) var->sqldata; break;\r
+                                       case SQL_LONG :         delete (int32_t*) var->sqldata; break;\r
+                                       case SQL_INT64 :        delete (int64_t*) var->sqldata; break;\r
+                                       case SQL_FLOAT :        delete (float*) var->sqldata; break;\r
+                                       case SQL_DOUBLE :       delete (double*) var->sqldata; break;\r
+                                       default : throw LogicExceptionImpl("RowImpl::Free",\r
+                                                               _("Found an unknown sqltype !"));\r
+                               }\r
+                       }\r
+                       if (var->sqlind != 0) delete var->sqlind;\r
+               }\r
+               delete [] (char*)mDescrArea;\r
+               mDescrArea = 0;\r
+       }\r
+\r
+       mNumerics.clear();\r
+       mFloats.clear();\r
+       mInt64s.clear();\r
+       mInt32s.clear();\r
+       mInt16s.clear();\r
+       mBools.clear();\r
+       mStrings.clear();\r
+       mUpdated.clear();\r
+\r
+       mDialect = 0;\r
+       mDatabase = 0;\r
+       mTransaction = 0;\r
+}\r
+\r
+void RowImpl::Resize(int n)\r
+{\r
+       const int size = XSQLDA_LENGTH(n);\r
+\r
+       Free();\r
+    mDescrArea = (XSQLDA*) new char[size];\r
+\r
+       memset(mDescrArea, 0, size);\r
+       mNumerics.resize(n);\r
+       mFloats.resize(n);\r
+       mInt64s.resize(n);\r
+       mInt32s.resize(n);\r
+       mInt16s.resize(n);\r
+       mBools.resize(n);\r
+       mStrings.resize(n);\r
+       mUpdated.resize(n);\r
+       for (int i = 0; i < n; i++)\r
+       {\r
+               mNumerics[i] = 0.0;\r
+               mFloats[i] = 0.0;\r
+               mInt64s[i] = 0;\r
+               mInt32s[i] = 0;\r
+               mInt16s[i] = 0;\r
+               mBools[i] = 0;\r
+               mStrings[i].erase();\r
+               mUpdated[i] = false;\r
+       }\r
+\r
+       mDescrArea->version = SQLDA_VERSION1;\r
+       mDescrArea->sqln = (int16_t)n;\r
+}\r
+\r
+void RowImpl::AllocVariables()\r
+{\r
+       int i;\r
+       for (i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
+               switch (var->sqltype & ~1)\r
+               {\r
+                       case SQL_ARRAY :\r
+                       case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_QUAD));\r
+                                                               break;\r
+                       case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_TIMESTAMP));\r
+                                                               break;\r
+                       case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_TIME));\r
+                                                               break;\r
+                       case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_DATE));\r
+                                                               break;\r
+                       case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];\r
+                                                               memset(var->sqldata, ' ', var->sqllen);\r
+                                                               var->sqldata[var->sqllen] = '\0';\r
+                                                               break;\r
+                       case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];\r
+                                                               memset(var->sqldata, 0, 2);\r
+                                                               memset(var->sqldata+2, ' ', var->sqllen);\r
+                                                               var->sqldata[var->sqllen+2] = '\0';\r
+                                                               break;\r
+                       case SQL_SHORT :        var->sqldata = (char*) new int16_t(0); break;\r
+                       case SQL_LONG :         var->sqldata = (char*) new int32_t(0); break;\r
+                       case SQL_INT64 :        var->sqldata = (char*) new int64_t(0); break;\r
+                       case SQL_FLOAT :        var->sqldata = (char*) new float(0.0); break;\r
+                       case SQL_DOUBLE :       var->sqldata = (char*) new double(0.0); break;\r
+                       default : throw LogicExceptionImpl("RowImpl::AllocVariables",\r
+                                               _("Found an unknown sqltype !"));\r
+               }\r
+               if (var->sqltype & 1) var->sqlind = new short(-1);      // 0 indicator\r
+       }\r
+}\r
+\r
+bool RowImpl::MissingValues()\r
+{\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+               if (! mUpdated[i]) return true;\r
+       return false;\r
+}\r
+\r
+RowImpl& RowImpl::operator=(const RowImpl& copied)\r
+{\r
+       Free();\r
+\r
+       const int n = copied.mDescrArea->sqln;\r
+       const int size = XSQLDA_LENGTH(n);\r
+\r
+       // Initial brute copy\r
+    mDescrArea = (XSQLDA*) new char[size];\r
+       memcpy(mDescrArea, copied.mDescrArea, size);\r
+\r
+       // Copy of the columns data\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
+               XSQLVAR* org = &(copied.mDescrArea->sqlvar[i]);\r
+               switch (var->sqltype & ~1)\r
+               {\r
+                       case SQL_ARRAY :\r
+                       case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_QUAD));\r
+                                                               break;\r
+                       case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIMESTAMP));\r
+                                                               break;\r
+                       case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIME));\r
+                                                               break;\r
+                       case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_DATE));\r
+                                                               break;\r
+                       case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];\r
+                                                               memcpy(var->sqldata, org->sqldata, var->sqllen+1);\r
+                                                               break;\r
+                       case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];\r
+                                                               memcpy(var->sqldata, org->sqldata, var->sqllen+3);\r
+                                                               break;\r
+                       case SQL_SHORT :        var->sqldata = (char*) new int16_t(*(int16_t*)org->sqldata); break;\r
+                       case SQL_LONG :         var->sqldata = (char*) new int32_t(*(int32_t*)org->sqldata); break;\r
+                       case SQL_INT64 :        var->sqldata = (char*) new int64_t(*(int64_t*)org->sqldata); break;\r
+                       case SQL_FLOAT :        var->sqldata = (char*) new float(*(float*)org->sqldata); break;\r
+                       case SQL_DOUBLE :       var->sqldata = (char*) new double(*(double*)org->sqldata); break;\r
+                       default : throw LogicExceptionImpl("RowImpl::Ctor",\r
+                                               _("Found an unknown sqltype !"));\r
+               }\r
+               if (var->sqltype & 1) var->sqlind = new short(*org->sqlind);    // 0 indicator\r
+       }\r
+\r
+       // Pointers init, real data copy\r
+       mNumerics = copied.mNumerics;\r
+       mFloats = copied.mFloats;\r
+       mInt64s = copied.mInt64s;\r
+       mInt32s = copied.mInt32s;\r
+       mInt16s = copied.mInt16s;\r
+       mBools = copied.mBools;\r
+       mStrings = copied.mStrings;\r
+\r
+       mDialect = copied.mDialect;\r
+       mDatabase = copied.mDatabase;\r
+       mTransaction = copied.mTransaction;\r
+       \r
+       return *this;\r
+}\r
+\r
+RowImpl::RowImpl(const RowImpl& copied)\r
+       : IBPP::IRow(), mRefCount(0), mDescrArea(0)\r
+{\r
+       // mRefCount and mDescrArea are set to 0 before using the assignment operator\r
+       *this = copied;         // The assignment operator does the real copy\r
+}\r
+\r
+RowImpl::RowImpl(int dialect, int n, DatabaseImpl* db, TransactionImpl* tr)\r
+       : mRefCount(0), mDescrArea(0)\r
+{\r
+       Resize(n);\r
+       mDialect = dialect;\r
+       mDatabase = db;\r
+       mTransaction = tr;\r
+}\r
+\r
+RowImpl::~RowImpl()\r
+{\r
+       try { Free(); }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/service.cpp b/stglibs/ibpp.lib/service.cpp
new file mode 100644 (file)
index 0000000..26726ea
--- /dev/null
@@ -0,0 +1,774 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: service.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $\r
+//     Subject : IBPP, Service class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+using namespace ibpp_internals;\r
+\r
+#ifdef IBPP_UNIX\r
+#include <unistd.h>\r
+#define Sleep(x) usleep(x)\r
+#endif\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void ServiceImpl::Connect()\r
+{\r
+       if (mHandle     != 0) return;   // Already connected\r
+       \r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mUserName.empty())\r
+               throw LogicExceptionImpl("Service::Connect", _("Unspecified user name."));\r
+       if (mUserPassword.empty())\r
+               throw LogicExceptionImpl("Service::Connect", _("Unspecified user password."));\r
+\r
+       // Attach to the Service Manager\r
+       IBS status;\r
+       SPB spb;\r
+       std::string connect;\r
+\r
+       // Build a SPB based on the     properties\r
+       spb.Insert(isc_spb_version);\r
+       spb.Insert(isc_spb_current_version);\r
+       spb.InsertString(isc_spb_user_name, 1, mUserName.c_str());\r
+       spb.InsertString(isc_spb_password, 1, mUserPassword.c_str());\r
+\r
+       if (! mServerName.empty())\r
+       {\r
+               connect = mServerName;\r
+               connect += ":";\r
+       }\r
+\r
+       connect += "service_mgr";\r
+\r
+       (*gds.Call()->m_service_attach)(status.Self(), (short)connect.size(), (char*)connect.c_str(),\r
+               &mHandle, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+       {\r
+               mHandle = 0;            // Should be, but better be     sure...\r
+               throw SQLExceptionImpl(status, "Service::Connect", _("isc_service_attach failed"));\r
+       }\r
+}\r
+\r
+void ServiceImpl::Disconnect()\r
+{\r
+       if (mHandle     == 0) return; // Already disconnected\r
+       \r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+\r
+       IBS status;\r
+\r
+       // Detach from the service manager\r
+       (*gds.Call()->m_service_detach)(status.Self(), &mHandle);\r
+\r
+       // Set mHandle to 0 now, just in case we need to throw, because Disconnect()\r
+       // is called from Service destructor and we want to maintain a coherent state.\r
+       mHandle = 0;\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Disconnect", _("isc_service_detach failed"));\r
+}\r
+\r
+void ServiceImpl::GetVersion(std::string& version)\r
+{\r
+       // Based on a patch provided by Torsten Martinsen (SourceForge 'bullestock')\r
+\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Service::GetVersion", _("Service is not connected."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+       RB result(250);\r
+\r
+       spb.Insert(isc_info_svc_server_version);\r
+\r
+       (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0, spb.Size(), spb.Self(),\r
+               result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::GetVersion", _("isc_service_query failed"));\r
+\r
+       result.GetString(isc_info_svc_server_version, version);\r
+}\r
+\r
+void ServiceImpl::AddUser(const IBPP::User& user)\r
+{\r
+       if (gds.Call()->mGDSVersion >= 60 && mHandle == 0)\r
+               throw LogicExceptionImpl("Service::AddUser", _("Service is not connected."));\r
+       if (user.username.empty())\r
+               throw LogicExceptionImpl("Service::AddUser", _("Username required."));\r
+       if (user.password.empty())\r
+               throw LogicExceptionImpl("Service::AddUser", _("Password required."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+       spb.Insert(isc_action_svc_add_user);\r
+       spb.InsertString(isc_spb_sec_username, 2, user.username.c_str());\r
+       spb.InsertString(isc_spb_sec_password, 2, user.password.c_str());\r
+       if (! user.firstname.empty())\r
+                       spb.InsertString(isc_spb_sec_firstname, 2, user.firstname.c_str());\r
+       if (! user.middlename.empty())\r
+                       spb.InsertString(isc_spb_sec_middlename, 2, user.middlename.c_str());\r
+       if (! user.lastname.empty())\r
+                       spb.InsertString(isc_spb_sec_lastname, 2, user.lastname.c_str());\r
+       if (user.userid != 0)\r
+                       spb.InsertQuad(isc_spb_sec_userid, (int32_t)user.userid);\r
+       if (user.groupid != 0)\r
+                       spb.InsertQuad(isc_spb_sec_groupid, (int32_t)user.groupid);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::AddUser", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::ModifyUser(const IBPP::User& user)\r
+{\r
+       if (gds.Call()->mGDSVersion >= 60 && mHandle == 0)\r
+               throw LogicExceptionImpl("Service::ModifyUser", _("Service is not connected."));\r
+       if (user.username.empty())\r
+               throw LogicExceptionImpl("Service::ModifyUser", _("Username required."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_modify_user);\r
+       spb.InsertString(isc_spb_sec_username, 2, user.username.c_str());\r
+       if (! user.password.empty())\r
+                       spb.InsertString(isc_spb_sec_password, 2, user.password.c_str());\r
+       if (! user.firstname.empty())\r
+                       spb.InsertString(isc_spb_sec_firstname, 2, user.firstname.c_str());\r
+       if (! user.middlename.empty())\r
+                       spb.InsertString(isc_spb_sec_middlename, 2, user.middlename.c_str());\r
+       if (! user.lastname.empty())\r
+                       spb.InsertString(isc_spb_sec_lastname, 2, user.lastname.c_str());\r
+       if (user.userid != 0)\r
+                       spb.InsertQuad(isc_spb_sec_userid, (int32_t)user.userid);\r
+       if (user.groupid != 0)\r
+                       spb.InsertQuad(isc_spb_sec_groupid, (int32_t)user.groupid);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::ModifyUser", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::RemoveUser(const std::string& username)\r
+{\r
+\r
+       if (gds.Call()->mGDSVersion >= 60 && mHandle == 0)\r
+               throw LogicExceptionImpl("Service::RemoveUser", _("Service is not connected."));\r
+       if (username.empty())\r
+               throw LogicExceptionImpl("Service::RemoveUser", _("Username required."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_delete_user);\r
+       spb.InsertString(isc_spb_sec_username, 2, username.c_str());\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::RemoveUser", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::GetUser(IBPP::User& user)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Service::GetUser", _("Service is not connected."));\r
+       if (user.username.empty())\r
+               throw LogicExceptionImpl("Service::GetUser", _("Username required."));\r
+\r
+       SPB spb;\r
+       spb.Insert(isc_action_svc_display_user);\r
+       spb.InsertString(isc_spb_sec_username, 2, user.username.c_str());\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::GetUser", _("isc_service_start failed"));\r
+\r
+       RB result(8000);\r
+       char request[] = {isc_info_svc_get_users};\r
+       status.Reset();\r
+       (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0,\r
+               sizeof(request), request, result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::GetUser", _("isc_service_query failed"));\r
+\r
+       char* p = result.Self();\r
+       if (*p != isc_info_svc_get_users)\r
+               throw SQLExceptionImpl(status, "Service::GetUser", _("isc_service_query returned unexpected answer"));\r
+\r
+       p += 3; // Skips the 'isc_info_svc_get_users' and its total length\r
+       user.clear();\r
+       while (*p != isc_info_end)\r
+       {\r
+               if (*p == isc_spb_sec_userid)\r
+               {\r
+                       user.userid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
+                       p += 5;\r
+               }\r
+               else if (*p == isc_spb_sec_groupid)\r
+               {\r
+                       user.groupid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
+                       p += 5;\r
+               }\r
+               else\r
+               {\r
+                       unsigned short len = (unsigned short)(*gds.Call()->m_vax_integer)(p+1, 2);\r
+                       switch (*p)\r
+                       {\r
+                       case isc_spb_sec_username :\r
+                               // For each user, this is the first element returned\r
+                               if (len != 0) user.username.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_password :\r
+                               if (len != 0) user.password.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_firstname :\r
+                               if (len != 0) user.firstname.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_middlename :\r
+                               if (len != 0) user.middlename.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_lastname :\r
+                               if (len != 0) user.lastname.assign(p+3, len);\r
+                               break;\r
+                       }\r
+                       p += (3 + len);\r
+               }\r
+    }\r
+}\r
+\r
+void ServiceImpl::GetUsers(std::vector<IBPP::User>& users)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Service::GetUsers", _("Service is not connected."));\r
+\r
+       SPB spb;\r
+       spb.Insert(isc_action_svc_display_user);\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::GetUsers", _("isc_service_start failed"));\r
+\r
+       RB result(8000);\r
+       char request[] = {isc_info_svc_get_users};\r
+       status.Reset();\r
+       (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0,\r
+               sizeof(request), request, result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::GetUsers", _("isc_service_query failed"));\r
+\r
+       users.clear();\r
+       char* p = result.Self();\r
+       if (*p != isc_info_svc_get_users)\r
+               throw SQLExceptionImpl(status, "Service::GetUsers", _("isc_service_query returned unexpected answer"));\r
+\r
+       p += 3; // Skips the 'isc_info_svc_get_users' and its total length\r
+       IBPP::User user;\r
+       while (*p != isc_info_end)\r
+       {\r
+               if (*p == isc_spb_sec_userid)\r
+               {\r
+                       user.userid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
+                       p += 5;\r
+               }\r
+               else if (*p == isc_spb_sec_groupid)\r
+               {\r
+                       user.groupid = (uint32_t)(*gds.Call()->m_vax_integer)(p+1, 4);\r
+                       p += 5;\r
+               }\r
+               else\r
+               {\r
+                       unsigned short len = (unsigned short)(*gds.Call()->m_vax_integer)(p+1, 2);\r
+                       switch (*p)\r
+                       {\r
+                       case isc_spb_sec_username :\r
+                               // For each user, this is the first element returned\r
+                               if (! user.username.empty()) users.push_back(user);     // Flush previous user\r
+                               user.clear();\r
+                               if (len != 0) user.username.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_password :\r
+                               if (len != 0) user.password.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_firstname :\r
+                               if (len != 0) user.firstname.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_middlename :\r
+                               if (len != 0) user.middlename.assign(p+3, len);\r
+                               break;\r
+                       case isc_spb_sec_lastname :\r
+                               if (len != 0) user.lastname.assign(p+3, len);\r
+                               break;\r
+                       }\r
+                       p += (3 + len);\r
+               }\r
+    }\r
+       if (! user.username.empty()) users.push_back(user);     // Flush last user\r
+}\r
+\r
+void ServiceImpl::SetPageBuffers(const std::string& dbfile, int buffers)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::SetPageBuffers", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::SetPageBuffers", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       spb.InsertQuad(isc_spb_prp_page_buffers, buffers);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::SetPageBuffers", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::SetSweepInterval(const std::string& dbfile, int sweep)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::SetSweepInterval", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::SetSweepInterval", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       spb.InsertQuad(isc_spb_prp_sweep_interval, sweep);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::SetSweepInterval", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::SetSyncWrite(const std::string& dbfile, bool sync)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::SetSyncWrite", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::SetSyncWrite", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       if (sync) spb.InsertByte(isc_spb_prp_write_mode, (char)isc_spb_prp_wm_sync);\r
+       else spb.InsertByte(isc_spb_prp_write_mode, (char)isc_spb_prp_wm_async);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::SetSyncWrite", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::SetReadOnly(const std::string& dbfile, bool readonly)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::SetReadOnly", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::SetReadOnly", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       if (readonly) spb.InsertByte(isc_spb_prp_access_mode, (char)isc_spb_prp_am_readonly);\r
+       else spb.InsertByte(isc_spb_prp_access_mode, (char)isc_spb_prp_am_readwrite);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::SetReadOnly", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::SetReserveSpace(const std::string& dbfile, bool reserve)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::SetReserveSpace", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::SetReserveSpace", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       if (reserve) spb.InsertByte(isc_spb_prp_reserve_space, (char)isc_spb_prp_res);\r
+       else spb.InsertByte(isc_spb_prp_reserve_space, (char)isc_spb_prp_res_use_full);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::SetReserveSpace", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::Shutdown(const std::string& dbfile, IBPP::DSM mode, int sectimeout)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::Shutdown", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::Shutdown", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       switch (mode)\r
+       {\r
+               case IBPP::dsDenyAttach :\r
+                       spb.InsertQuad(isc_spb_prp_deny_new_attachments, sectimeout);\r
+                       break;\r
+               case IBPP::dsDenyTrans :\r
+                       spb.InsertQuad(isc_spb_prp_deny_new_transactions, sectimeout);\r
+                       break;\r
+               case IBPP::dsForce :\r
+                       spb.InsertQuad(isc_spb_prp_shutdown_db, sectimeout);\r
+                       break;\r
+       }\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Shutdown", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::Restart(const std::string& dbfile)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::Restart", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::Restart", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_properties);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       spb.InsertQuad(isc_spb_options, isc_spb_prp_db_online);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Restart", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::Sweep(const std::string& dbfile)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::Sweep", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::Sweep", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_repair);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       spb.InsertQuad(isc_spb_options, isc_spb_rpr_sweep_db);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Sweep", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::Repair(const std::string& dbfile, IBPP::RPF flags)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::Repair", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::Repair", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_repair);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+\r
+       unsigned int mask;\r
+       if (flags & IBPP::rpValidateFull) mask = (isc_spb_rpr_full | isc_spb_rpr_validate_db);\r
+       else if (flags & IBPP::rpValidatePages) mask = isc_spb_rpr_validate_db;\r
+       else if (flags & IBPP::rpMendRecords) mask = isc_spb_rpr_mend_db;\r
+       else throw LogicExceptionImpl("Service::Repair",\r
+               _("One of rpMendRecords, rpValidatePages, rpValidateFull is required."));\r
+\r
+       if (flags & IBPP::rpReadOnly)                   mask |= isc_spb_rpr_check_db;\r
+       if (flags & IBPP::rpIgnoreChecksums)    mask |= isc_spb_rpr_ignore_checksum;\r
+       if (flags & IBPP::rpKillShadows)                mask |= isc_spb_rpr_kill_shadows;\r
+       \r
+       spb.InsertQuad(isc_spb_options, mask);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Repair", _("isc_service_start failed"));\r
+\r
+       Wait();\r
+}\r
+\r
+void ServiceImpl::StartBackup(const std::string& dbfile,\r
+       const std::string& bkfile, IBPP::BRF flags)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::Backup", _("Service is not connected."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::Backup", _("Main database file must be specified."));\r
+       if (bkfile.empty())\r
+               throw LogicExceptionImpl("Service::Backup", _("Backup file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_backup);\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       spb.InsertString(isc_spb_bkp_file, 2, bkfile.c_str());\r
+       if (flags & IBPP::brVerbose) spb.Insert(isc_spb_verbose);\r
+\r
+       unsigned int mask = 0;\r
+       if (flags & IBPP::brIgnoreChecksums)    mask |= isc_spb_bkp_ignore_checksums;\r
+       if (flags & IBPP::brIgnoreLimbo)                mask |= isc_spb_bkp_ignore_limbo;\r
+       if (flags & IBPP::brMetadataOnly)               mask |= isc_spb_bkp_metadata_only;\r
+       if (flags & IBPP::brNoGarbageCollect)   mask |= isc_spb_bkp_no_garbage_collect;\r
+       if (flags & IBPP::brNonTransportable)   mask |= isc_spb_bkp_non_transportable;\r
+       if (flags & IBPP::brConvertExtTables)   mask |= isc_spb_bkp_convert;\r
+       if (mask != 0) spb.InsertQuad(isc_spb_options, mask);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Backup", _("isc_service_start failed"));\r
+}\r
+\r
+void ServiceImpl::StartRestore(const std::string& bkfile, const std::string& dbfile,\r
+       int     pagesize, IBPP::BRF flags)\r
+{\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+       if (mHandle     == 0)\r
+               throw LogicExceptionImpl("Service::Restore", _("Service is not connected."));\r
+       if (bkfile.empty())\r
+               throw LogicExceptionImpl("Service::Restore", _("Backup file must be specified."));\r
+       if (dbfile.empty())\r
+               throw LogicExceptionImpl("Service::Restore", _("Main database file must be specified."));\r
+\r
+       IBS status;\r
+       SPB spb;\r
+\r
+       spb.Insert(isc_action_svc_restore);\r
+       spb.InsertString(isc_spb_bkp_file, 2, bkfile.c_str());\r
+       spb.InsertString(isc_spb_dbname, 2, dbfile.c_str());\r
+       if (flags & IBPP::brVerbose) spb.Insert(isc_spb_verbose);\r
+       if (pagesize != 0) spb.InsertQuad(isc_spb_res_page_size, pagesize);\r
+\r
+       unsigned int mask;\r
+       if (flags & IBPP::brReplace) mask = isc_spb_res_replace;\r
+               else mask = isc_spb_res_create; // Safe default mode\r
+\r
+       if (flags & IBPP::brDeactivateIdx)      mask |= isc_spb_res_deactivate_idx;\r
+       if (flags & IBPP::brNoShadow)           mask |= isc_spb_res_no_shadow;\r
+       if (flags & IBPP::brNoValidity)         mask |= isc_spb_res_no_validity;\r
+       if (flags & IBPP::brPerTableCommit)     mask |= isc_spb_res_one_at_a_time;\r
+       if (flags & IBPP::brUseAllSpace)        mask |= isc_spb_res_use_all_space;\r
+       if (mask != 0) spb.InsertQuad(isc_spb_options, mask);\r
+\r
+       (*gds.Call()->m_service_start)(status.Self(), &mHandle, 0, spb.Size(), spb.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Service::Restore", _("isc_service_start failed"));\r
+}\r
+\r
+const char* ServiceImpl::WaitMsg()\r
+{\r
+       IBS status;\r
+       SPB req;\r
+       RB result(1024);\r
+\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+\r
+       req.Insert(isc_info_svc_line);  // Request one line of textual output\r
+\r
+       // _service_query will only block until a line of result is available\r
+       // (or until the end of the task if it does not report information)\r
+       (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0, 0,\r
+               req.Size(),     req.Self(),     result.Size(), result.Self());\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "ServiceImpl::Wait", _("isc_service_query failed"));\r
+\r
+       // If message length is zero bytes,     task is finished\r
+       if (result.GetString(isc_info_svc_line, mWaitMessage) == 0) return 0;\r
+\r
+       // Task is not finished, but we have something to report\r
+       return mWaitMessage.c_str();\r
+}\r
+\r
+void ServiceImpl::Wait()\r
+{\r
+       IBS status;\r
+       SPB spb;\r
+       RB result(1024);\r
+       std::string msg;\r
+\r
+       if (gds.Call()->mGDSVersion < 60)\r
+               throw LogicExceptionImpl("Service", _("Requires the version 6 of GDS32.DLL"));\r
+\r
+       spb.Insert(isc_info_svc_line);\r
+       for (;;)\r
+       {\r
+               // Sleeps 1 millisecond upfront. This will release the remaining\r
+               // timeslot of the thread. Doing so will give a good chance for small\r
+               // services tasks to finish before we check if they are still running.\r
+               // The deal is to limit (in that particular case) the number of loops\r
+               // polling _service_query that will happen.\r
+\r
+               Sleep(1);\r
+\r
+               // _service_query will only block until a line of result is available\r
+               // (or until the end of the task if it does not report information) \r
+               (*gds.Call()->m_service_query)(status.Self(), &mHandle, 0, 0,   0,\r
+                       spb.Size(),     spb.Self(),     result.Size(), result.Self());\r
+               if (status.Errors())\r
+                       throw SQLExceptionImpl(status, "ServiceImpl::Wait", _("isc_service_query failed"));\r
+\r
+               // If message length is zero bytes,     task is finished\r
+               if (result.GetString(isc_info_svc_line, msg) == 0) return;\r
+\r
+               status.Reset();\r
+               result.Reset();\r
+       }\r
+}\r
+\r
+IBPP::IService* ServiceImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void ServiceImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void ServiceImpl::SetServerName(const char* newName)\r
+{\r
+       if (newName == 0) mServerName.erase();\r
+       else mServerName = newName;\r
+}\r
+\r
+void ServiceImpl::SetUserName(const char* newName)\r
+{\r
+       if (newName == 0) mUserName.erase();\r
+       else mUserName = newName;\r
+}\r
+\r
+void ServiceImpl::SetUserPassword(const char* newPassword)\r
+{\r
+       if (newPassword == 0) mUserPassword.erase();\r
+       else mUserPassword = newPassword;\r
+}\r
+\r
+ServiceImpl::ServiceImpl(const std::string& ServerName,\r
+                       const std::string& UserName, const std::string& UserPassword)\r
+       :       mRefCount(0), mHandle(0),\r
+               mServerName(ServerName), mUserName(UserName), mUserPassword(UserPassword)\r
+{\r
+}\r
+\r
+ServiceImpl::~ServiceImpl()\r
+{\r
+       try { if (Connected()) Disconnect(); }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     Eof\r
+//\r
diff --git a/stglibs/ibpp.lib/statement.cpp b/stglibs/ibpp.lib/statement.cpp
new file mode 100644 (file)
index 0000000..1a3031f
--- /dev/null
@@ -0,0 +1,1307 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: statement.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, Service class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void StatementImpl::Prepare(const std::string& sql)\r
+{\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Statement::Prepare", _("An IDatabase must be attached."));\r
+       if (mDatabase->GetHandle() == 0)\r
+               throw LogicExceptionImpl("Statement::Prepare", _("IDatabase must be connected."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Statement::Prepare", _("An ITransaction must be attached."));\r
+       if (mTransaction->GetHandle() == 0)\r
+               throw LogicExceptionImpl("Statement::Prepare", _("ITransaction must be started."));\r
+       if (sql.empty())\r
+               throw LogicExceptionImpl("Statement::Prepare", _("SQL statement can't be 0."));\r
+\r
+       // Saves the SQL sentence, only for reporting reasons in case of errors\r
+       mSql = sql;\r
+\r
+       IBS status;\r
+\r
+       // Free all resources currently attached to this Statement, then allocate\r
+       // a new statement descriptor.\r
+       Close();\r
+       (*gds.Call()->m_dsql_allocate_statement)(status.Self(), mDatabase->GetHandlePtr(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Statement::Prepare",\r
+                       _("isc_dsql_allocate_statement failed"));\r
+\r
+       // Empirical estimate of parameters count and output columns count.\r
+       // This is by far not an exact estimation, which would require parsing the\r
+       // SQL statement. If the SQL statement contains '?' and ',' in string\r
+       // constants, this count will obviously be wrong, but it will be exagerated.\r
+       // It won't hurt. We just try to not have to re-allocate those descriptors later.\r
+       // So we prefer to get them a little bit larger than needed than the other way.\r
+       int16_t inEstimate = 0;\r
+       int16_t outEstimate = 1;\r
+       for (size_t i = 0; i < strlen(sql.c_str()); i++)\r
+       {\r
+               if (sql[i] == '?') ++inEstimate;\r
+               if (sql[i] == ',') ++outEstimate;\r
+       }\r
+\r
+       /*\r
+       DebugStream()<< "Prepare(\""<< sql<< "\")"<< fds;\r
+       DebugStream()<< _("Estimation: ")<< inEstimate<< _(" IN parameters and ")\r
+                       << outEstimate<< _(" OUT columns")<< fds;\r
+       */\r
+\r
+       // Allocates output descriptor and prepares the statement\r
+       mOutRow = new RowImpl(mDatabase->Dialect(), outEstimate, mDatabase, mTransaction);\r
+       mOutRow->AddRef();\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_dsql_prepare)(status.Self(), mTransaction->GetHandlePtr(),\r
+               &mHandle, (short)sql.length(), const_cast<char*>(sql.c_str()),\r
+                       short(mDatabase->Dialect()), mOutRow->Self());\r
+       if (status.Errors())\r
+       {\r
+               Close();\r
+               std::string context = "Statement::Prepare( ";\r
+               context.append(mSql).append(" )");\r
+               throw SQLExceptionImpl(status, context.c_str(),\r
+                       _("isc_dsql_prepare failed"));\r
+       }\r
+\r
+       // Read what kind of statement was prepared\r
+       status.Reset();\r
+       char itemsReq[] = {isc_info_sql_stmt_type};\r
+       char itemsRes[8];\r
+       (*gds.Call()->m_dsql_sql_info)(status.Self(), &mHandle, 1, itemsReq,\r
+               sizeof(itemsRes), itemsRes);\r
+       if (status.Errors())\r
+       {\r
+               Close();\r
+               throw SQLExceptionImpl(status, "Statement::Prepare",\r
+                       _("isc_dsql_sql_info failed"));\r
+       }\r
+       if (itemsRes[0] == isc_info_sql_stmt_type)\r
+       {\r
+               switch (itemsRes[3])\r
+               {\r
+                       case isc_info_sql_stmt_select :         mType = IBPP::stSelect; break;\r
+                       case isc_info_sql_stmt_insert :         mType = IBPP::stInsert; break;\r
+                       case isc_info_sql_stmt_update :         mType = IBPP::stUpdate; break;\r
+                       case isc_info_sql_stmt_delete :         mType = IBPP::stDelete; break;\r
+                       case isc_info_sql_stmt_ddl :            mType = IBPP::stDDL; break;\r
+                       case isc_info_sql_stmt_exec_procedure : mType = IBPP::stExecProcedure; break;\r
+                       case isc_info_sql_stmt_select_for_upd : mType = IBPP::stSelectUpdate; break;\r
+                       case isc_info_sql_stmt_set_generator :  mType = IBPP::stSetGenerator; break;\r
+                       case isc_info_sql_stmt_savepoint :      mType = IBPP::stSavePoint; break;\r
+                       default : mType = IBPP::stUnsupported;\r
+               }\r
+       }\r
+       if (mType == IBPP::stUnknown || mType == IBPP::stUnsupported)\r
+       {\r
+               Close();\r
+               throw LogicExceptionImpl("Statement::Prepare",\r
+                       _("Unknown or unsupported statement type"));\r
+       }\r
+\r
+       if (mOutRow->Columns() == 0)\r
+       {\r
+               // Get rid of the output descriptor, if it wasn't required (no output)\r
+               mOutRow->Release();\r
+               mOutRow = 0;\r
+               /*\r
+               DebugStream()<< _("Dropped output descriptor which was not required")<< fds;\r
+               */\r
+       }\r
+       else if (mOutRow->Columns() > mOutRow->AllocatedSize())\r
+       {\r
+               // Resize the output descriptor (which is too small).\r
+               // The statement does not need to be prepared again, though the\r
+               // output columns must be described again.\r
+\r
+               /*\r
+               DebugStream()<< _("Resize output descriptor from ")\r
+                       << mOutRow->AllocatedSize()<< _(" to ")<< mOutRow->Columns()<< fds;\r
+               */\r
+\r
+               mOutRow->Resize(mOutRow->Columns());\r
+               status.Reset();\r
+               (*gds.Call()->m_dsql_describe)(status.Self(), &mHandle, 1, mOutRow->Self());\r
+               if (status.Errors())\r
+               {\r
+                       Close();\r
+                       throw SQLExceptionImpl(status, "Statement::Prepare",\r
+                               _("isc_dsql_describe failed"));\r
+               }\r
+       }\r
+\r
+       if (inEstimate > 0)\r
+       {\r
+               // Ready an input descriptor\r
+               mInRow = new RowImpl(mDatabase->Dialect(), inEstimate, mDatabase, mTransaction);\r
+               mInRow->AddRef();\r
+\r
+               status.Reset();\r
+               (*gds.Call()->m_dsql_describe_bind)(status.Self(), &mHandle, 1, mInRow->Self());\r
+               if (status.Errors())\r
+               {\r
+                       Close();\r
+                       throw SQLExceptionImpl(status, "Statement::Prepare",\r
+                               _("isc_dsql_describe_bind failed"));\r
+               }\r
+\r
+               if (mInRow->Columns() == 0)\r
+               {\r
+                       // Get rid of the input descriptor, if it wasn't required (no parameters)\r
+                       mInRow->Release();\r
+                       mInRow = 0;\r
+                       /*\r
+                       DebugStream()<< _("Dropped input descriptor which was not required")<< fds;\r
+                       */\r
+               }\r
+               else if (mInRow->Columns() > mInRow->AllocatedSize())\r
+               {\r
+                       // Resize the input descriptor (which is too small).\r
+                       // The statement does not need to be prepared again, though the\r
+                       // parameters must be described again.\r
+\r
+                       /*\r
+                       DebugStream()<< _("Resize input descriptor from ")\r
+                                       << mInRow->AllocatedSize()<< _(" to ")\r
+                                       << mInRow->Columns()<< fds;\r
+                       */\r
+\r
+                       mInRow->Resize(mInRow->Columns());\r
+                       status.Reset();\r
+                       (*gds.Call()->m_dsql_describe_bind)(status.Self(), &mHandle, 1, mInRow->Self());\r
+                       if (status.Errors())\r
+                       {\r
+                               Close();\r
+                               throw SQLExceptionImpl(status, "Statement::Prepare",\r
+                                       _("isc_dsql_describe_bind failed"));\r
+                       }\r
+               }\r
+       }\r
+\r
+       // Allocates variables of the input descriptor\r
+       if (mInRow != 0)\r
+       {\r
+               // Turn on 'can be NULL' on each input parameter\r
+               for (int i = 0; i < mInRow->Columns(); i++)\r
+               {\r
+                       XSQLVAR* var = &(mInRow->Self()->sqlvar[i]);\r
+                       if (! (var->sqltype & 1)) var->sqltype += short(1);\r
+               }\r
+               mInRow->AllocVariables();\r
+       }\r
+\r
+       // Allocates variables of the output descriptor\r
+       if (mOutRow != 0) mOutRow->AllocVariables();\r
+}\r
+\r
+void StatementImpl::Plan(std::string& plan)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Plan", _("No statement has been prepared."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Statement::Plan", _("A Database must be attached."));\r
+       if (mDatabase->GetHandle() == 0)\r
+               throw LogicExceptionImpl("Statement::Plan", _("Database must be connected."));\r
+\r
+       IBS status;\r
+       RB result(4096);\r
+       char itemsReq[] = {isc_info_sql_get_plan};\r
+\r
+       (*gds.Call()->m_dsql_sql_info)(status.Self(), &mHandle, 1, itemsReq,\r
+                                                                  result.Size(), result.Self());\r
+       if (status.Errors()) throw SQLExceptionImpl(status,\r
+                                                               "Statement::Plan", _("isc_dsql_sql_info failed."));\r
+\r
+       result.GetString(isc_info_sql_get_plan, plan);\r
+       if (plan[0] == '\n') plan.erase(0, 1);\r
+}\r
+\r
+void StatementImpl::Execute(const std::string& sql)\r
+{\r
+       if (! sql.empty()) Prepare(sql);\r
+\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Execute",\r
+                       _("No statement has been prepared."));\r
+\r
+       // Check that a value has been set for each input parameter\r
+       if (mInRow != 0 && mInRow->MissingValues())\r
+               throw LogicExceptionImpl("Statement::Execute",\r
+                       _("All parameters must be specified."));\r
+\r
+       CursorFree();   // Free a previous 'cursor' if any\r
+\r
+       IBS status;\r
+       if (mType == IBPP::stSelect)\r
+       {\r
+               // Could return a result set (none, single or multi rows)\r
+               (*gds.Call()->m_dsql_execute)(status.Self(), mTransaction->GetHandlePtr(),\r
+                       &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self());\r
+               if (status.Errors())\r
+               {\r
+                       //Close();      Commented because Execute error should not free the statement\r
+                       std::string context = "Statement::Execute( ";\r
+                       context.append(mSql).append(" )");\r
+                       throw SQLExceptionImpl(status, context.c_str(),\r
+                               _("isc_dsql_execute failed"));\r
+               }\r
+               if (mOutRow != 0)\r
+               {\r
+                       mResultSetAvailable = true;\r
+                       mCursorOpened = true;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               // Should return at most a single row\r
+               (*gds.Call()->m_dsql_execute2)(status.Self(), mTransaction->GetHandlePtr(),\r
+                       &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self(),\r
+                       mOutRow == 0 ? 0 : mOutRow->Self());\r
+               if (status.Errors())\r
+               {\r
+                       //Close();      Commented because Execute error should not free the statement\r
+                       std::string context = "Statement::Execute( ";\r
+                       context.append(mSql).append(" )");\r
+                       throw SQLExceptionImpl(status, context.c_str(),\r
+                               _("isc_dsql_execute2 failed"));\r
+               }\r
+       }\r
+}\r
+\r
+void StatementImpl::CursorExecute(const std::string& cursor, const std::string& sql)\r
+{\r
+       if (cursor.empty())\r
+               throw LogicExceptionImpl("Statement::CursorExecute", _("Cursor name can't be 0."));\r
+\r
+       if (! sql.empty()) Prepare(sql);\r
+\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::CursorExecute", _("No statement has been prepared."));\r
+       if (mType != IBPP::stSelectUpdate)\r
+               throw LogicExceptionImpl("Statement::CursorExecute", _("Statement must be a SELECT FOR UPDATE."));\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::CursorExecute", _("Statement would return no rows."));\r
+\r
+       // Check that a value has been set for each input parameter\r
+       if (mInRow != 0 && mInRow->MissingValues())\r
+               throw LogicExceptionImpl("Statement::CursorExecute",\r
+                       _("All parameters must be specified."));\r
+\r
+       CursorFree();   // Free a previous 'cursor' if any\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_dsql_execute)(status.Self(), mTransaction->GetHandlePtr(),\r
+               &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self());\r
+       if (status.Errors())\r
+       {\r
+               //Close();      Commented because Execute error should not free the statement\r
+               std::string context = "Statement::CursorExecute( ";\r
+               context.append(mSql).append(" )");\r
+               throw SQLExceptionImpl(status, context.c_str(),\r
+                       _("isc_dsql_execute failed"));\r
+       }\r
+\r
+       status.Reset();\r
+       (*gds.Call()->m_dsql_set_cursor_name)(status.Self(), &mHandle, const_cast<char*>(cursor.c_str()), 0);\r
+       if (status.Errors())\r
+       {\r
+               //Close();      Commented because Execute error should not free the statement\r
+               throw SQLExceptionImpl(status, "Statement::CursorExecute",\r
+                       _("isc_dsql_set_cursor_name failed"));\r
+       }\r
+\r
+       mResultSetAvailable = true;\r
+       mCursorOpened = true;\r
+}\r
+\r
+void StatementImpl::ExecuteImmediate(const std::string& sql)\r
+{\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Statement::ExecuteImmediate", _("An IDatabase must be attached."));\r
+       if (mDatabase->GetHandle() == 0)\r
+               throw LogicExceptionImpl("Statement::ExecuteImmediate", _("IDatabase must be connected."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Statement::ExecuteImmediate", _("An ITransaction must be attached."));\r
+       if (mTransaction->GetHandle() == 0)\r
+               throw LogicExceptionImpl("Statement::ExecuteImmediate", _("ITransaction must be started."));\r
+       if (sql.empty())\r
+               throw LogicExceptionImpl("Statement::ExecuteImmediate", _("SQL statement can't be 0."));\r
+\r
+       IBS status;\r
+       Close();\r
+    (*gds.Call()->m_dsql_execute_immediate)(status.Self(), mDatabase->GetHandlePtr(),\r
+       mTransaction->GetHandlePtr(), 0, const_cast<char*>(sql.c_str()),\r
+               short(mDatabase->Dialect()), 0);\r
+    if (status.Errors())\r
+       {\r
+               std::string context = "Statement::ExecuteImmediate( ";\r
+               context.append(sql).append(" )");\r
+               throw SQLExceptionImpl(status, context.c_str(),\r
+                       _("isc_dsql_execute_immediate failed"));\r
+       }\r
+}\r
+\r
+int StatementImpl::AffectedRows()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::AffectedRows", _("No statement has been prepared."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Statement::AffectedRows", _("A Database must be attached."));\r
+       if (mDatabase->GetHandle() == 0)\r
+               throw LogicExceptionImpl("Statement::AffectedRows", _("Database must be connected."));\r
+\r
+       int count;\r
+       IBS status;\r
+       RB result;\r
+       char itemsReq[] = {isc_info_sql_records};\r
+\r
+       (*gds.Call()->m_dsql_sql_info)(status.Self(), &mHandle, 1, itemsReq,\r
+               result.Size(), result.Self());\r
+       if (status.Errors()) throw SQLExceptionImpl(status,\r
+                       "Statement::AffectedRows", _("isc_dsql_sql_info failed."));\r
+\r
+       if (mType == IBPP::stInsert)\r
+                       count = result.GetValue(isc_info_sql_records, isc_info_req_insert_count);\r
+       else if (mType == IBPP::stUpdate)\r
+                       count = result.GetValue(isc_info_sql_records, isc_info_req_update_count);\r
+       else if (mType == IBPP::stDelete)\r
+                       count = result.GetValue(isc_info_sql_records, isc_info_req_delete_count);\r
+       else if (mType == IBPP::stSelect)\r
+                       count = result.GetValue(isc_info_sql_records, isc_info_req_select_count);\r
+       else    count = 0;      // Returns zero count for unknown cases\r
+\r
+       return count;\r
+}\r
+\r
+bool StatementImpl::Fetch()\r
+{\r
+       if (! mResultSetAvailable)\r
+               throw LogicExceptionImpl("Statement::Fetch",\r
+                       _("No statement has been executed or no result set available."));\r
+\r
+       IBS status;\r
+       int code = (*gds.Call()->m_dsql_fetch)(status.Self(), &mHandle, 1, mOutRow->Self());\r
+       if (code == 100)        // This special code means "no more rows"\r
+       {\r
+               mResultSetAvailable = false;\r
+               // Oddly enough, fetching rows up to the last one seems to open\r
+               // an 'implicit' cursor that needs to be closed.\r
+               mCursorOpened = true;\r
+               CursorFree();   // Free the explicit or implicit cursor/result-set\r
+               return false;\r
+       }\r
+       if (status.Errors())\r
+       {\r
+               Close();\r
+               throw SQLExceptionImpl(status, "Statement::Fetch",\r
+                       _("isc_dsql_fetch failed."));\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+bool StatementImpl::Fetch(IBPP::Row& row)\r
+{\r
+       if (! mResultSetAvailable)\r
+               throw LogicExceptionImpl("Statement::Fetch(row)",\r
+                       _("No statement has been executed or no result set available."));\r
+\r
+       RowImpl* rowimpl = new RowImpl(*mOutRow);\r
+       row = rowimpl;\r
+\r
+       IBS status;\r
+       int code = (*gds.Call()->m_dsql_fetch)(status.Self(), &mHandle, 1,\r
+                                       rowimpl->Self());\r
+       if (code == 100)        // This special code means "no more rows"\r
+       {\r
+               mResultSetAvailable = false;\r
+               // Oddly enough, fetching rows up to the last one seems to open\r
+               // an 'implicit' cursor that needs to be closed.\r
+               mCursorOpened = true;\r
+               CursorFree();   // Free the explicit or implicit cursor/result-set\r
+               row.clear();\r
+               return false;\r
+       }\r
+       if (status.Errors())\r
+       {\r
+               Close();\r
+               row.clear();\r
+               throw SQLExceptionImpl(status, "Statement::Fetch(row)",\r
+                       _("isc_dsql_fetch failed."));\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+void StatementImpl::Close()\r
+{\r
+       // Free all statement resources.\r
+       // Used before preparing a new statement or from destructor.\r
+\r
+       if (mInRow != 0) { mInRow->Release(); mInRow = 0; }\r
+       if (mOutRow != 0) { mOutRow->Release(); mOutRow = 0; }\r
+\r
+       mResultSetAvailable = false;\r
+       mCursorOpened = false;\r
+       mType = IBPP::stUnknown;\r
+\r
+       if (mHandle != 0)\r
+       {\r
+               IBS status;\r
+               (*gds.Call()->m_dsql_free_statement)(status.Self(), &mHandle, DSQL_drop);\r
+               mHandle = 0;\r
+               if (status.Errors())\r
+                       throw SQLExceptionImpl(status, "Statement::Close(DSQL_drop)",\r
+                               _("isc_dsql_free_statement failed."));\r
+       }\r
+}\r
+\r
+void StatementImpl::SetNull(int param)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::SetNull", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::SetNull", _("The statement does not take parameters."));\r
+\r
+       mInRow->SetNull(param);\r
+}\r
+\r
+void StatementImpl::Set(int param, bool value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[bool]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[bool]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, const char* cstring)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[char*]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[char*]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, cstring);\r
+}\r
+\r
+void StatementImpl::Set(int param, const void* bindata, int len)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[void*]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[void*]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, bindata, len);\r
+}\r
+\r
+void StatementImpl::Set(int param, const std::string& s)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[string]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[string]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, s);\r
+}\r
+\r
+void StatementImpl::Set(int param, int16_t value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[int16_t]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[int16_t]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, int32_t value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[int32_t]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[int32_t]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, int64_t value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[int64_t]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[int64_t]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, float value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[float]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[float]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, double value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[double]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[double]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, const IBPP::Timestamp& value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Timestamp]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Timestamp]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, const IBPP::Date& value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Date]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Date]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, const IBPP::Time& value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Time]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Time]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+\r
+void StatementImpl::Set(int param, const IBPP::Blob& blob)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Blob]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Blob]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, blob);\r
+}\r
+\r
+void StatementImpl::Set(int param, const IBPP::Array& array)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Array]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Array]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, array);\r
+}\r
+\r
+void StatementImpl::Set(int param, const IBPP::DBKey& key)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[DBKey]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[DBKey]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, key);\r
+}\r
+\r
+/*\r
+void StatementImpl::Set(int param, const IBPP::Value& value)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Value]", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Set[Value]", _("The statement does not take parameters."));\r
+\r
+       mInRow->Set(param, value);\r
+}\r
+*/\r
+\r
+bool StatementImpl::IsNull(int column)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::IsNull", _("The row is not initialized."));\r
+\r
+       return mOutRow->IsNull(column);\r
+}\r
+\r
+bool StatementImpl::Get(int column, bool* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(column, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, bool& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, char* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, void* bindata, int& userlen)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, bindata, userlen);\r
+}\r
+\r
+bool StatementImpl::Get(int column, std::string& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, int16_t* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(column, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, int16_t& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, int32_t* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(column, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, int32_t& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, int64_t* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(column, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, int64_t& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, float* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(column, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, float& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, double* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(column, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, double& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(int column, IBPP::Timestamp& timestamp)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, timestamp);\r
+}\r
+\r
+bool StatementImpl::Get(int column, IBPP::Date& date)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, date);\r
+}\r
+\r
+bool StatementImpl::Get(int column, IBPP::Time& time)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, time);\r
+}\r
+\r
+bool StatementImpl::Get(int column, IBPP::Blob& blob)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, blob);\r
+}\r
+\r
+bool StatementImpl::Get(int column, IBPP::DBKey& key)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, key);\r
+}\r
+\r
+bool StatementImpl::Get(int column, IBPP::Array& array)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column, array);\r
+}\r
+\r
+/*\r
+const IBPP::Value StatementImpl::Get(int column)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(column);\r
+}\r
+*/\r
+\r
+bool StatementImpl::IsNull(const std::string& name)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::IsNull", _("The row is not initialized."));\r
+\r
+       return mOutRow->IsNull(name);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, bool* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(name, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, bool& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, char* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get[char*]", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, void* retvalue, int& count)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get[void*,int]", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue, count);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, std::string& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::GetString", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, int16_t* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(name, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, int16_t& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, int32_t* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(name, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, int32_t& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, int64_t* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(name, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, int64_t& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, float* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(name, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, float& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, double* retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("Null pointer detected"));\r
+\r
+       return mOutRow->Get(name, *retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, double& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, IBPP::Timestamp& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, IBPP::Date& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, IBPP::Time& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string&name, IBPP::Blob& retblob)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retblob);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, IBPP::DBKey& retvalue)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retvalue);\r
+}\r
+\r
+bool StatementImpl::Get(const std::string& name, IBPP::Array& retarray)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name, retarray);\r
+}\r
+\r
+/*\r
+const IBPP::Value StatementImpl::Get(const std::string& name)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Get", _("The row is not initialized."));\r
+\r
+       return mOutRow->Get(name);\r
+}\r
+*/\r
+\r
+int StatementImpl::Columns()\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized."));\r
+\r
+       return mOutRow->Columns();\r
+}\r
+\r
+int StatementImpl::ColumnNum(const std::string& name)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnNum", _("The row is not initialized."));\r
+\r
+       return mOutRow->ColumnNum(name);\r
+}\r
+\r
+const char* StatementImpl::ColumnName(int varnum)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized."));\r
+\r
+       return mOutRow->ColumnName(varnum);\r
+}\r
+\r
+const char* StatementImpl::ColumnAlias(int varnum)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized."));\r
+\r
+       return mOutRow->ColumnAlias(varnum);\r
+}\r
+\r
+const char* StatementImpl::ColumnTable(int varnum)\r
+{\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized."));\r
+\r
+       return mOutRow->ColumnTable(varnum);\r
+}\r
+\r
+IBPP::SDT StatementImpl::ColumnType(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnType", _("No statement has been prepared."));\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnType", _("The statement does not return results."));\r
+\r
+    return mOutRow->ColumnType(varnum);\r
+}\r
+\r
+int StatementImpl::ColumnSubtype(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnSubtype", _("No statement has been prepared."));\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnSubtype", _("The statement does not return results."));\r
+\r
+    return mOutRow->ColumnSubtype(varnum);\r
+}\r
+\r
+int StatementImpl::ColumnSize(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnSize", _("No statement has been prepared."));\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnSize", _("The row is not initialized."));\r
+\r
+       return mOutRow->ColumnSize(varnum);\r
+}\r
+\r
+int StatementImpl::ColumnScale(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnScale", _("No statement has been prepared."));\r
+       if (mOutRow == 0)\r
+               throw LogicExceptionImpl("Statement::ColumnScale", _("The row is not initialized."));\r
+\r
+       return mOutRow->ColumnScale(varnum);\r
+}\r
+\r
+int StatementImpl::Parameters()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::Parameters", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::Parameters", _("The statement uses no parameters."));\r
+\r
+       return mInRow->Columns();\r
+}\r
+\r
+IBPP::SDT StatementImpl::ParameterType(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterType", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterType", _("The statement uses no parameters."));\r
+\r
+    return mInRow->ColumnType(varnum);\r
+}\r
+\r
+int StatementImpl::ParameterSubtype(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterSubtype", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterSubtype", _("The statement uses no parameters."));\r
+\r
+    return mInRow->ColumnSubtype(varnum);\r
+}\r
+\r
+int StatementImpl::ParameterSize(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterSize", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterSize", _("The statement uses no parameters."));\r
+\r
+       return mInRow->ColumnSize(varnum);\r
+}\r
+\r
+int StatementImpl::ParameterScale(int varnum)\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterScale", _("No statement has been prepared."));\r
+       if (mInRow == 0)\r
+               throw LogicExceptionImpl("Statement::ParameterScale", _("The statement uses no parameters."));\r
+\r
+       return mInRow->ColumnScale(varnum);\r
+}\r
+\r
+IBPP::Database StatementImpl::DatabasePtr() const\r
+{\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::Transaction StatementImpl::TransactionPtr() const\r
+{\r
+       return mTransaction;\r
+}\r
+\r
+IBPP::IStatement* StatementImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+\r
+       return this;\r
+}\r
+\r
+void StatementImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void StatementImpl::AttachDatabaseImpl(DatabaseImpl* database)\r
+{\r
+       if (database == 0)\r
+               throw LogicExceptionImpl("Statement::AttachDatabase",\r
+                       _("Can't attach a 0 IDatabase object."));\r
+\r
+       if (mDatabase != 0) mDatabase->DetachStatementImpl(this);\r
+       mDatabase = database;\r
+       mDatabase->AttachStatementImpl(this);\r
+}\r
+\r
+void StatementImpl::DetachDatabaseImpl()\r
+{\r
+       if (mDatabase == 0) return;\r
+\r
+       Close();\r
+       mDatabase->DetachStatementImpl(this);\r
+       mDatabase = 0;\r
+}\r
+\r
+void StatementImpl::AttachTransactionImpl(TransactionImpl* transaction)\r
+{\r
+       if (transaction == 0)\r
+               throw LogicExceptionImpl("Statement::AttachTransaction",\r
+                       _("Can't attach a 0 ITransaction object."));\r
+\r
+       if (mTransaction != 0) mTransaction->DetachStatementImpl(this);\r
+       mTransaction = transaction;\r
+       mTransaction->AttachStatementImpl(this);\r
+}\r
+\r
+void StatementImpl::DetachTransactionImpl()\r
+{\r
+       if (mTransaction == 0) return;\r
+\r
+       Close();\r
+       mTransaction->DetachStatementImpl(this);\r
+       mTransaction = 0;\r
+}\r
+\r
+void StatementImpl::CursorFree()\r
+{\r
+       if (mCursorOpened)\r
+       {\r
+               mCursorOpened = false;\r
+               if (mHandle != 0)\r
+               {\r
+                       IBS status;\r
+                       (*gds.Call()->m_dsql_free_statement)(status.Self(), &mHandle, DSQL_close);\r
+                       if (status.Errors())\r
+                               throw SQLExceptionImpl(status, "StatementImpl::CursorFree(DSQL_close)",\r
+                                       _("isc_dsql_free_statement failed."));\r
+               }\r
+       }\r
+}\r
+\r
+StatementImpl::StatementImpl(DatabaseImpl* database, TransactionImpl* transaction,\r
+       const std::string& sql)\r
+       : mRefCount(0), mHandle(0), mDatabase(0), mTransaction(0),\r
+       mInRow(0), mOutRow(0),\r
+       mResultSetAvailable(false), mCursorOpened(false), mType(IBPP::stUnknown)\r
+{\r
+       AttachDatabaseImpl(database);\r
+       if (transaction != 0) AttachTransactionImpl(transaction);\r
+       if (! sql.empty()) Prepare(sql);\r
+}\r
+\r
+StatementImpl::~StatementImpl()\r
+{\r
+       try { Close(); }\r
+               catch (...) { }\r
+       try { if (mTransaction != 0) mTransaction->DetachStatementImpl(this); }\r
+               catch (...) { }\r
+       try { if (mDatabase != 0) mDatabase->DetachStatementImpl(this); }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/time.cpp b/stglibs/ibpp.lib/time.cpp
new file mode 100644 (file)
index 0000000..ffdd5f6
--- /dev/null
@@ -0,0 +1,208 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: time.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $\r
+//     Subject : IBPP, Time class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <time.h>              // Can't use <ctime> thanks to MSVC6 buggy library\r
+\r
+using namespace ibpp_internals;\r
+\r
+void IBPP::Time::Now()\r
+{\r
+       time_t systime = time(0);\r
+       tm* loctime = localtime(&systime);\r
+       IBPP::itot(&mTime, loctime->tm_hour, loctime->tm_min, loctime->tm_sec, 0);\r
+}\r
+\r
+void IBPP::Time::SetTime(int tm)\r
+{\r
+       if (tm < 0 || tm > 863999999)\r
+               throw LogicExceptionImpl("Time::SetTime", _("Invalid time value"));\r
+       mTime = tm;\r
+}\r
+\r
+void IBPP::Time::SetTime(int hour, int minute, int second, int tenthousandths)\r
+{\r
+       if (hour < 0 || hour > 23 ||\r
+               minute < 0 || minute > 59 ||\r
+                       second < 0 || second > 59 ||\r
+                               tenthousandths < 0 || tenthousandths > 9999)\r
+                                       throw LogicExceptionImpl("Time::SetTime",\r
+                                               _("Invalid hour, minute, second values"));\r
+       IBPP::itot(&mTime, hour, minute, second, tenthousandths);\r
+}\r
+\r
+void IBPP::Time::GetTime(int& hour, int& minute, int& second) const\r
+{\r
+       IBPP::ttoi(mTime, &hour, &minute, &second, 0);\r
+}\r
+\r
+void IBPP::Time::GetTime(int& hour, int& minute, int& second, int& tenthousandths) const\r
+{\r
+       IBPP::ttoi(mTime, &hour, &minute, &second, &tenthousandths);\r
+}\r
+\r
+int IBPP::Time::Hours() const\r
+{\r
+       int hours;\r
+       IBPP::ttoi(mTime, &hours, 0, 0, 0);\r
+       return hours;\r
+}\r
+\r
+int IBPP::Time::Minutes() const\r
+{\r
+       int minutes;\r
+       IBPP::ttoi(mTime, 0, &minutes, 0, 0);\r
+       return minutes;\r
+}\r
+\r
+int IBPP::Time::Seconds() const\r
+{\r
+       int seconds;\r
+       IBPP::ttoi(mTime, 0, 0, &seconds, 0);\r
+       return seconds;\r
+}\r
+\r
+int IBPP::Time::SubSeconds() const     // Actually tenthousandths of seconds\r
+{\r
+       int tenthousandths;\r
+       IBPP::ttoi(mTime, 0, 0, 0, &tenthousandths);\r
+       return tenthousandths;\r
+}\r
+\r
+IBPP::Time::Time(int hour, int minute, int second, int tenthousandths)\r
+{\r
+       SetTime(hour, minute, second, tenthousandths);\r
+}\r
+\r
+IBPP::Time::Time(const IBPP::Time& copied)\r
+{\r
+       mTime = copied.mTime;\r
+}\r
+\r
+IBPP::Time& IBPP::Time::operator=(const IBPP::Timestamp& assigned)\r
+{\r
+       mTime = assigned.GetTime();\r
+       return *this;\r
+}\r
+\r
+IBPP::Time& IBPP::Time::operator=(const IBPP::Time& assigned)\r
+{\r
+       mTime = assigned.mTime;\r
+       return *this;\r
+}\r
+\r
+//     Time calculations. Internal format is the number of seconds elapsed since\r
+//     midnight. Splits such a time in its hours, minutes, seconds components.\r
+\r
+void IBPP::ttoi(int itime, int *h, int *m, int *s, int* t)\r
+{\r
+       int hh, mm, ss, tt;\r
+\r
+       hh = (int) (itime / 36000000);  itime = itime - hh * 36000000;\r
+       mm = (int) (itime / 600000);    itime = itime - mm * 600000;\r
+       ss = (int) (itime / 10000);\r
+       tt = (int) (itime - ss * 10000);\r
+\r
+       if (h != 0) *h = hh;\r
+       if (m != 0) *m = mm;\r
+       if (s != 0) *s = ss;\r
+       if (t != 0) *t = tt;\r
+\r
+       return;\r
+}\r
+\r
+//     Get the internal time format, given hour, minute, second.\r
+\r
+void IBPP::itot (int *ptime, int hour, int minute, int second, int tenthousandths)\r
+{\r
+       *ptime = hour * 36000000 + minute * 600000 + second * 10000 + tenthousandths;\r
+       return;\r
+}\r
+\r
+namespace ibpp_internals\r
+{\r
+\r
+//\r
+//     The following functions are helper conversions functions between IBPP\r
+//     Date, Time, Timestamp and ISC_DATE, ISC_TIME and ISC_TIMESTAMP.\r
+//     (They must be maintained if the encoding used by Firebird evolve.)\r
+//     These helper functions are used from row.cpp and from array.cpp.\r
+//\r
+\r
+void encodeDate(ISC_DATE& isc_dt, const IBPP::Date& dt)\r
+{\r
+       // There simply has a shift of 15019 between the native Firebird\r
+       // date model and the IBPP model.\r
+       isc_dt = (ISC_DATE)(dt.GetDate() + 15019);\r
+}\r
+\r
+void decodeDate(IBPP::Date& dt, const ISC_DATE& isc_dt)\r
+{\r
+       // There simply has a shift of 15019 between the native Firebird\r
+       // date model and the IBPP model.\r
+       dt.SetDate((int)isc_dt - 15019);\r
+}\r
+\r
+void encodeTime(ISC_TIME& isc_tm, const IBPP::Time& tm)\r
+{\r
+       isc_tm = (ISC_TIME)tm.GetTime();\r
+}\r
+\r
+void decodeTime(IBPP::Time& tm, const ISC_TIME& isc_tm)\r
+{\r
+       tm.SetTime((int)isc_tm);\r
+}\r
+\r
+void encodeTimestamp(ISC_TIMESTAMP& isc_ts, const IBPP::Timestamp& ts)\r
+{\r
+       encodeDate(isc_ts.timestamp_date, ts);\r
+       encodeTime(isc_ts.timestamp_time, ts);\r
+}\r
+\r
+void decodeTimestamp(IBPP::Timestamp& ts, const ISC_TIMESTAMP& isc_ts)\r
+{\r
+       decodeDate(ts, isc_ts.timestamp_date);\r
+       decodeTime(ts, isc_ts.timestamp_time);\r
+}\r
+\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
+\r
diff --git a/stglibs/ibpp.lib/transaction.cpp b/stglibs/ibpp.lib/transaction.cpp
new file mode 100644 (file)
index 0000000..c9a3877
--- /dev/null
@@ -0,0 +1,409 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: transaction.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $\r
+//     Subject : IBPP, Database class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <algorithm>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void TransactionImpl::AttachDatabase(IBPP::Database db,\r
+       IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)\r
+{\r
+       if (db.intf() == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachDatabase",\r
+                               _("Can't attach an unbound Database."));\r
+\r
+       AttachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()), am, il, lr, flags);\r
+}\r
+\r
+void TransactionImpl::DetachDatabase(IBPP::Database db)\r
+{\r
+       if (db.intf() == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachDatabase",\r
+                               _("Can't detach an unbound Database."));\r
+\r
+       DetachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()));\r
+}\r
+\r
+void TransactionImpl::AddReservation(IBPP::Database db,\r
+       const std::string& table, IBPP::TTR tr)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Transaction::AddReservation",\r
+                               _("Can't add table reservation if Transaction started."));\r
+       if (db.intf() == 0)\r
+               throw LogicExceptionImpl("Transaction::AddReservation",\r
+                               _("Can't add table reservation on an unbound Database."));\r
+\r
+       // Find the TPB associated with this database\r
+       std::vector<DatabaseImpl*>::iterator pos =\r
+               std::find(mDatabases.begin(), mDatabases.end(), dynamic_cast<DatabaseImpl*>(db.intf()));\r
+       if (pos != mDatabases.end())\r
+       {\r
+               size_t index = pos - mDatabases.begin();\r
+               TPB* tpb = mTPBs[index];\r
+               \r
+               // Now add the reservations to the TPB\r
+               switch (tr)\r
+               {\r
+                       case IBPP::trSharedWrite :\r
+                                       tpb->Insert(isc_tpb_lock_write);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_shared);\r
+                                       break;\r
+                       case IBPP::trSharedRead :\r
+                                       tpb->Insert(isc_tpb_lock_read);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_shared);\r
+                                       break;\r
+                       case IBPP::trProtectedWrite :\r
+                                       tpb->Insert(isc_tpb_lock_write);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_protected);\r
+                                       break;\r
+                       case IBPP::trProtectedRead :\r
+                                       tpb->Insert(isc_tpb_lock_read);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_protected);\r
+                                       break;\r
+                       default :\r
+                                       throw LogicExceptionImpl("Transaction::AddReservation",\r
+                                               _("Illegal TTR value detected."));\r
+               }\r
+       }\r
+       else throw LogicExceptionImpl("Transaction::AddReservation",\r
+                       _("The database connection you specified is not attached to this transaction."));\r
+}\r
+\r
+void TransactionImpl::Start()\r
+{\r
+       if (mHandle != 0) return;       // Already started anyway\r
+\r
+       if (mDatabases.empty())\r
+               throw LogicExceptionImpl("Transaction::Start", _("No Database is attached."));\r
+\r
+       struct ISC_TEB\r
+       {\r
+               ISC_LONG* db_ptr;\r
+               ISC_LONG tpb_len;\r
+               char* tpb_ptr;\r
+       } * teb = new ISC_TEB[mDatabases.size()];\r
+\r
+       unsigned i;\r
+       for (i = 0; i < mDatabases.size(); i++)\r
+       {\r
+               if (mDatabases[i]->GetHandle() == 0)\r
+               {\r
+                       // All Databases must be connected to Start the transaction !\r
+                       delete [] teb;\r
+                       throw LogicExceptionImpl("Transaction::Start",\r
+                                       _("All attached Database should have been connected."));\r
+               }\r
+               teb[i].db_ptr = (ISC_LONG*) mDatabases[i]->GetHandlePtr();\r
+               teb[i].tpb_len = mTPBs[i]->Size();\r
+               teb[i].tpb_ptr = mTPBs[i]->Self();\r
+       }\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_start_multiple)(status.Self(), &mHandle, (short)mDatabases.size(), teb);\r
+       delete [] teb;\r
+       if (status.Errors())\r
+       {\r
+               mHandle = 0;    // Should be, but better be sure...\r
+               throw SQLExceptionImpl(status, "Transaction::Start");\r
+       }\r
+}\r
+\r
+void TransactionImpl::Commit()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Transaction::Commit", _("Transaction is not started."));\r
+               \r
+       IBS status;\r
+\r
+       (*gds.Call()->m_commit_transaction)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::Commit");\r
+       mHandle = 0;    // Should be, better be sure\r
+}\r
+\r
+void TransactionImpl::CommitRetain()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Transaction::CommitRetain", _("Transaction is not started."));\r
+\r
+       IBS status;\r
+\r
+       (*gds.Call()->m_commit_retaining)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::CommitRetain");\r
+}\r
+\r
+void TransactionImpl::Rollback()\r
+{\r
+       if (mHandle == 0) return;       // Transaction not started anyway\r
+\r
+       IBS status;\r
+\r
+       (*gds.Call()->m_rollback_transaction)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::Rollback");\r
+       mHandle = 0;    // Should be, better be sure\r
+}\r
+\r
+void TransactionImpl::RollbackRetain()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Transaction::RollbackRetain", _("Transaction is not started."));\r
+\r
+       IBS status;\r
+\r
+       (*gds.Call()->m_rollback_retaining)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::RollbackRetain");\r
+}\r
+\r
+IBPP::ITransaction* TransactionImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void TransactionImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void TransactionImpl::Init()\r
+{\r
+       mHandle = 0;\r
+       mDatabases.clear();\r
+       mTPBs.clear();\r
+       mStatements.clear();\r
+       mBlobs.clear();\r
+       mArrays.clear();\r
+}\r
+\r
+void TransactionImpl::AttachStatementImpl(StatementImpl* st)\r
+{\r
+       if (st == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachStatement",\r
+                                       _("Can't attach a 0 Statement object."));\r
+\r
+       mStatements.push_back(st);\r
+}\r
+\r
+void TransactionImpl::DetachStatementImpl(StatementImpl* st)\r
+{\r
+       if (st == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachStatement",\r
+                               _("Can't detach a 0 Statement object."));\r
+\r
+       mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));\r
+}\r
+\r
+void TransactionImpl::AttachBlobImpl(BlobImpl* bb)\r
+{\r
+       if (bb == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachBlob",\r
+                                       _("Can't attach a 0 BlobImpl object."));\r
+\r
+       mBlobs.push_back(bb);\r
+}\r
+\r
+void TransactionImpl::DetachBlobImpl(BlobImpl* bb)\r
+{\r
+       if (bb == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachBlob",\r
+                               _("Can't detach a 0 BlobImpl object."));\r
+\r
+       mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));\r
+}\r
+\r
+void TransactionImpl::AttachArrayImpl(ArrayImpl* ar)\r
+{\r
+       if (ar == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachArray",\r
+                                       _("Can't attach a 0 ArrayImpl object."));\r
+\r
+       mArrays.push_back(ar);\r
+}\r
+\r
+void TransactionImpl::DetachArrayImpl(ArrayImpl* ar)\r
+{\r
+       if (ar == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachArray",\r
+                               _("Can't detach a 0 ArrayImpl object."));\r
+\r
+       mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));\r
+}\r
+\r
+void TransactionImpl::AttachDatabaseImpl(DatabaseImpl* dbi,\r
+       IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Transaction::AttachDatabase",\r
+                               _("Can't attach a Database if Transaction started."));\r
+       if (dbi == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachDatabase",\r
+                               _("Can't attach a null Database."));\r
+\r
+       mDatabases.push_back(dbi);\r
+\r
+       // Prepare a new TPB\r
+       TPB* tpb = new TPB;\r
+    if (am == IBPP::amRead) tpb->Insert(isc_tpb_read);\r
+    else tpb->Insert(isc_tpb_write);\r
+\r
+       switch (il)\r
+       {\r
+               case IBPP::ilConsistency :              tpb->Insert(isc_tpb_consistency); break;\r
+               case IBPP::ilReadDirty :                tpb->Insert(isc_tpb_read_committed);\r
+                                                               tpb->Insert(isc_tpb_rec_version); break;\r
+               case IBPP::ilReadCommitted :    tpb->Insert(isc_tpb_read_committed);\r
+                                                                               tpb->Insert(isc_tpb_no_rec_version); break;\r
+               default :                                               tpb->Insert(isc_tpb_concurrency); break;\r
+       }\r
+\r
+    if (lr == IBPP::lrNoWait) tpb->Insert(isc_tpb_nowait);\r
+    else tpb->Insert(isc_tpb_wait);\r
+\r
+       if (flags & IBPP::tfIgnoreLimbo)        tpb->Insert(isc_tpb_ignore_limbo);\r
+       if (flags & IBPP::tfAutoCommit)         tpb->Insert(isc_tpb_autocommit);\r
+       if (flags & IBPP::tfNoAutoUndo)         tpb->Insert(isc_tpb_no_auto_undo);\r
+\r
+       mTPBs.push_back(tpb);\r
+\r
+       // Signals the Database object that it has been attached to the Transaction\r
+       dbi->AttachTransactionImpl(this);\r
+}\r
+\r
+void TransactionImpl::DetachDatabaseImpl(DatabaseImpl* dbi)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Transaction::DetachDatabase",\r
+                               _("Can't detach a Database if Transaction started."));\r
+       if (dbi == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachDatabase",\r
+                               _("Can't detach a null Database."));\r
+\r
+       std::vector<DatabaseImpl*>::iterator pos =\r
+               std::find(mDatabases.begin(), mDatabases.end(), dbi);\r
+       if (pos != mDatabases.end())\r
+       {\r
+               size_t index = pos - mDatabases.begin();\r
+               TPB* tpb = mTPBs[index];\r
+               mDatabases.erase(pos);\r
+               mTPBs.erase(mTPBs.begin()+index);\r
+               delete tpb;\r
+       }\r
+\r
+       // Signals the Database object that it has been detached from the Transaction\r
+       dbi->DetachTransactionImpl(this);\r
+}\r
+\r
+TransactionImpl::TransactionImpl(DatabaseImpl* db,\r
+       IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)\r
+       : mRefCount(0)\r
+{\r
+       Init();\r
+       AttachDatabaseImpl(db, am, il, lr, flags);\r
+}\r
+\r
+TransactionImpl::~TransactionImpl()\r
+{\r
+       // Rollback the transaction if it was Started\r
+       try { if (Started()) Rollback(); }\r
+               catch (...) { }\r
+\r
+       // Let's detach cleanly all Blobs from this Transaction.\r
+       // No Blob object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       //\r
+       // We use a reverse traversal of the array to avoid loops.\r
+       // The array shrinks on each loop (mBbCount decreases).\r
+       // And during the deletion, there is a packing of the array through a\r
+       // copy of elements from the end to the beginning of the array.\r
+       try {\r
+               while (mBlobs.size() > 0)\r
+                       mBlobs.back()->DetachTransactionImpl();\r
+       } catch (...) { }\r
+\r
+       // Let's detach cleanly all Arrays from this Transaction.\r
+       // No Array object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       try {\r
+               while (mArrays.size() > 0)\r
+                       mArrays.back()->DetachTransactionImpl();\r
+       } catch (...) { }\r
+\r
+       // Let's detach cleanly all Statements from this Transaction.\r
+       // No Statement object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       try {\r
+               while (mStatements.size() > 0)\r
+                       mStatements.back()->DetachTransactionImpl();\r
+       } catch (...) { }\r
+\r
+       // Very important : let's detach cleanly all Databases from this\r
+       // Transaction. No Database object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       try {\r
+               while (mDatabases.size() > 0)\r
+               {\r
+                       size_t i = mDatabases.size()-1;\r
+                       DetachDatabaseImpl(mDatabases[i]);      // <-- remove link to database from mTPBs\r
+                                                                                       // array and destroy TPB object\r
+                                                                                       // Fixed : Maxim Abrashkin on 12 Jun 2002\r
+                       //mDatabases.back()->DetachTransaction(this);\r
+               }\r
+       } catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/ibpp.lib/user.cpp b/stglibs/ibpp.lib/user.cpp
new file mode 100644 (file)
index 0000000..e9cc1b4
--- /dev/null
@@ -0,0 +1,70 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: user.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $\r
+//     Subject : IBPP, User class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <iostream>\r
+#include <sstream>\r
+#include <iomanip>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     Private implementation\r
+\r
+void IBPP::User::copyfrom(const IBPP::User& r)\r
+{\r
+       username = r.username;\r
+       password = r.password;\r
+       firstname = r.firstname;\r
+       middlename = r.middlename;\r
+       lastname = r.lastname;\r
+       userid = r.userid;\r
+       groupid = r.groupid;\r
+}\r
+\r
+//     Public implementation\r
+\r
+void IBPP::User::clear()\r
+{\r
+       username.erase(); password.erase();\r
+       firstname.erase(); middlename.erase(); lastname.erase();\r
+       userid = groupid = 0;\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r
diff --git a/stglibs/pinger.lib/Makefile b/stglibs/pinger.lib/Makefile
new file mode 100644 (file)
index 0000000..5f368b6
--- /dev/null
@@ -0,0 +1,18 @@
+###############################################################################
+# $Id: Makefile,v 1.5 2008/12/04 17:13:14 faust Exp $
+###############################################################################
+
+LIB_NAME = stg_pinger
+PROG = lib$(LIB_NAME)
+
+SRCS = pinger.cpp
+
+INCS = pinger.h
+
+LIBS = $(LIB_THREAD)
+
+include ../Makefile.in
+
+test: all
+       g++ -c test.cpp
+       g++ -o test test.o ./libstg_pinger.a -lpthread
diff --git a/stglibs/pinger.lib/pinger.cpp b/stglibs/pinger.lib/pinger.cpp
new file mode 100644 (file)
index 0000000..9169b4e
--- /dev/null
@@ -0,0 +1,388 @@
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "pinger.h"
+#include "common.h"
+#include "stg_locker.h"
+
+#ifdef STG_TIME
+extern volatile time_t stgTime;
+#endif
+
+//-----------------------------------------------------------------------------
+STG_PINGER::STG_PINGER(time_t d)
+{
+    delay = d;
+    pthread_mutex_init(&mutex, NULL);
+    pid = 0;
+}
+//-----------------------------------------------------------------------------
+STG_PINGER::~STG_PINGER()
+{
+    pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+int STG_PINGER::Start()
+{
+    struct protoent *proto = NULL;
+    proto = getprotobyname("ICMP");
+    sendSocket = socket(PF_INET, SOCK_RAW, proto->p_proto);
+    recvSocket = socket(PF_INET, SOCK_RAW, proto->p_proto);
+    nonstop = true;
+    pid = (int) getpid() % 65535;
+    if (sendSocket < 0 || recvSocket < 0)
+        {
+        errorStr = "Cannot create socket.";
+        return -1;
+        }
+
+    if (pthread_create(&sendThread, NULL, RunSendPing, this))
+        {
+        errorStr = "Cannot create send thread.";
+        return -1;
+        }
+
+    if (pthread_create(&recvThread, NULL, RunRecvPing, this))
+        {
+        errorStr = "Cannot create recv thread.";
+        return -1;
+        }
+
+    return 0;
+}
+//-----------------------------------------------------------------------------
+int STG_PINGER::Stop()
+{
+    close(recvSocket);
+    nonstop = false;
+    if (isRunningRecver)
+        {
+        //5 seconds to thread stops itself
+        int i;
+        for (i = 0; i < 25; i++)
+            {
+            if (i % 5 == 0)
+                SendPing(0x0100007f);//127.0.0.1
+
+            if (!isRunningRecver)
+                break;
+
+            usleep(200000);
+            }
+
+        //after 5 seconds waiting thread still running. now killing it
+        if (isRunningRecver)
+            {
+            //if (pthread_kill(recvThread, SIGINT))
+            //    {
+                errorStr = "Cannot kill thread.";
+                return -1;
+            //    }
+            //printf("recvThread killed\n");
+            }
+        }
+
+    if (isRunningSender)
+        {
+        //5 seconds to thread stops itself
+        int i;
+        for (i = 0; i < 25; i++)
+            {
+            if (!isRunningSender)
+                break;
+
+            usleep(200000);
+            }
+
+        //after 5 seconds waiting thread still running. now killing it
+        if (isRunningSender)
+            {
+            //if (pthread_kill(sendThread, SIGINT))
+            //    {
+                errorStr = "Cannot kill thread.";
+                return -1;
+            //    }
+            //printf("sendThread killed\n");
+            }
+        }
+
+    close(sendSocket);
+    return 0;
+}
+//-----------------------------------------------------------------------------
+void STG_PINGER::AddIP(uint32_t ip)
+{
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    //printf("AddIP\n");
+    ipToAdd.push_back(ip);
+}
+//-----------------------------------------------------------------------------
+void STG_PINGER::DelIP(uint32_t ip)
+{
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    //printf("DelIP\n");
+    ipToDel.push_back(ip);
+}
+//-----------------------------------------------------------------------------
+void STG_PINGER::RealAddIP()
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+    list<uint32_t>::iterator iter;
+    iter = ipToAdd.begin();
+    while (iter != ipToAdd.end())
+        {
+        /*packets.insert(pair<RAW_PACKET, PACKET_EXTRA_DATA>(rawPacket, ed));*/
+        //pingIP[*iter] = 0;
+        pingIP.insert(pair<uint32_t, time_t>(*iter, 0));
+        iter++;
+        }
+    ipToAdd.erase(ipToAdd.begin(), ipToAdd.end());
+    }
+//-----------------------------------------------------------------------------
+void STG_PINGER::RealDelIP()
+{
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+
+    list<uint32_t>::iterator iter;
+    multimap<uint32_t, time_t>::iterator treeIter;
+    iter = ipToDel.begin();
+    while (iter != ipToDel.end())
+        {
+        treeIter = pingIP.find(*iter);
+        //printf("Found %X\n", *iter);
+        if (treeIter != pingIP.end())
+            pingIP.erase(treeIter);
+
+        iter++;
+        }
+    ipToDel.erase(ipToDel.begin(), ipToDel.end());
+}
+//-----------------------------------------------------------------------------
+int STG_PINGER::GetPingIPNum()
+{
+    return pingIP.size();
+}
+//-----------------------------------------------------------------------------
+void STG_PINGER::GetAllIP(vector<PING_IP_TIME> *)
+{
+    //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+}
+//-----------------------------------------------------------------------------
+void STG_PINGER::PrintAllIP()
+{
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    multimap<uint32_t, time_t>::iterator iter;
+    iter = pingIP.begin();
+    while (iter != pingIP.end())
+        {
+        uint32_t ip = iter->first;
+        time_t t = iter->second;
+        string s;
+        x2str(t, s);
+        printf("ip = %s, time = %9s\n", inet_ntostring(ip).c_str(), s.c_str());
+        iter++;
+        }
+
+}
+//-----------------------------------------------------------------------------
+int STG_PINGER::GetIPTime(uint32_t ip, time_t * t)
+{
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    multimap<uint32_t, time_t>::iterator treeIter;
+
+    treeIter = pingIP.find(ip);
+    if (treeIter == pingIP.end())
+        return -1;
+
+    *t = treeIter->second;
+    return 0;
+}
+//-----------------------------------------------------------------------------
+void STG_PINGER::SetDelayTime(time_t d)
+{
+    delay = d;
+}
+//-----------------------------------------------------------------------------
+time_t STG_PINGER::GetDelayTime()
+{
+    return delay;
+}
+//-----------------------------------------------------------------------------
+string STG_PINGER::GetStrError()
+{
+    return errorStr;
+}
+//-----------------------------------------------------------------------------
+uint16_t STG_PINGER::PingCheckSum(void * data, int len)
+{
+    unsigned short * buf = (unsigned short *)data;
+    unsigned int sum = 0;
+    unsigned short result;
+
+    for ( sum = 0; len > 1; len -= 2 )
+        sum += *buf++;
+
+    if ( len == 1 )
+        sum += *(unsigned char*)buf;
+
+    sum = (sum >> 16) + (sum & 0xFFFF);
+    sum += (sum >> 16);
+    result = ~sum;
+    return result;
+}
+//-----------------------------------------------------------------------------
+int STG_PINGER::SendPing(uint32_t ip)
+{
+    struct sockaddr_in addr;
+    //printf("SendPing %X \n", ip);
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = 0;
+    addr.sin_addr.s_addr = ip;
+
+    memset(&pmSend, 0, sizeof(pmSend));
+    pmSend.hdr.type = ICMP_ECHO;
+    pmSend.hdr.un.echo.id = pid;
+    memcpy(pmSend.msg, &ip, sizeof(ip));
+
+    pmSend.hdr.checksum = PingCheckSum(&pmSend, sizeof(pmSend));
+
+    if (sendto(sendSocket, &pmSend, sizeof(pmSend), 0, (sockaddr *)&addr, sizeof(addr)) <= 0 )
+        {
+        errorStr = "Send ping error: " + string(strerror(errno));
+        return -1;
+        }
+
+
+    return 0;
+}
+//-----------------------------------------------------------------------------
+uint32_t STG_PINGER::RecvPing()
+{
+    struct sockaddr_in addr;
+    uint32_t ipAddr = 0;
+
+    char buf[128];
+    memset(buf, 0, sizeof(buf));
+    int bytes;
+    socklen_t len = sizeof(addr);
+
+    bytes = recvfrom(recvSocket, &buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len);
+    //printf("recvfrom\n");
+    if (bytes > 0)
+        {
+        struct IP_HDR * ip = (struct IP_HDR *)buf;
+        struct ICMP_HDR *icmp = (struct ICMP_HDR *)(buf + ip->ihl * 4);
+
+        //printf("icmp->un.echo.id=%d,  pid=%d, tid: %d\n", icmp->un.echo.id, pid);
+        if (icmp->un.echo.id != pid)
+            return 0;
+
+        ipAddr = *(uint32_t*)(buf + sizeof(ICMP_HDR) + ip->ihl * 4);
+        }
+
+    return ipAddr;
+}
+//-----------------------------------------------------------------------------
+void * STG_PINGER::RunSendPing(void * d)
+{
+    STG_PINGER * pinger = (STG_PINGER*)d;
+
+    pinger->isRunningSender = true;
+    time_t lastPing = 0;
+    while (pinger->nonstop)
+        {
+        pinger->RealAddIP();
+        pinger->RealDelIP();
+
+        multimap<uint32_t, time_t>::iterator iter;
+        iter = pinger->pingIP.begin();
+        while (iter != pinger->pingIP.end())
+            {
+            uint32_t ip = iter->first;
+            pinger->SendPing(ip);
+            iter++;
+            }
+
+        time_t currTime;
+
+        #ifdef STG_TIME
+        lastPing = stgTime;
+        currTime = stgTime;
+        #else
+        currTime = lastPing = time(NULL);
+        #endif
+
+        while (currTime - lastPing < pinger->delay && pinger->nonstop)
+            {
+            #ifdef STG_TIME
+            currTime = stgTime;
+            #else
+            currTime = time(NULL);
+            #endif
+            usleep(20000);
+            }
+        //printf("new ping cycle\n");
+        }
+
+    pinger->isRunningSender = false;
+
+    return NULL;
+}
+//-----------------------------------------------------------------------------
+void * STG_PINGER::RunRecvPing(void * d)
+{
+    STG_PINGER * pinger = (STG_PINGER*)d;
+
+    pinger->isRunningRecver = true;
+
+    uint32_t ip;
+    multimap<uint32_t, time_t>::iterator treeIterLower;
+    multimap<uint32_t, time_t>::iterator treeIterUpper;
+
+    while (pinger->nonstop)
+        {
+        ip = pinger->RecvPing();
+
+        if (ip)
+            {
+            //printf("RecvPing %X\n", ip);
+            treeIterUpper = pinger->pingIP.upper_bound(ip);
+            treeIterLower = pinger->pingIP.lower_bound(ip);
+            int i = 0;
+            while (treeIterUpper != treeIterLower)
+            //treeIterUpper = pinger->pingIP.find(ip);
+            //if (treeIterUpper != pinger->pingIP.end())
+                {
+                //printf("+++! time=%d %X i=%d !+++\n", time(NULL), ip, i);
+                //printf("--- time=%d ---\n", time(NULL));
+                #ifdef STG_TIME
+                treeIterLower->second = stgTime;
+                #else
+                treeIterLower->second = time(NULL);
+                #endif
+                ++treeIterLower;
+                i++;
+                }
+            }
+
+        }
+    pinger->isRunningRecver = false;
+    return NULL;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/pinger.lib/pinger.h b/stglibs/pinger.lib/pinger.h
new file mode 100644 (file)
index 0000000..4349eb0
--- /dev/null
@@ -0,0 +1,139 @@
+ /*
+ $Revision: 1.8 $
+ $Date: 2008/05/10 11:59:53 $
+ $Author: nobunaga $
+ */
+
+#ifndef PINGER_H
+#define PINGER_H
+
+#include <time.h>
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+
+#ifdef LINUX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/ip_icmp.h>
+#endif
+
+#if defined (FREE_BSD) || defined (FREE_BSD5)
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+#endif
+
+#include "os_int.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+struct ICMP_HDR
+{
+uint8_t       type;
+uint8_t       code;
+uint16_t      checksum;
+union
+    {
+    struct
+        {
+        uint16_t    id;
+        uint16_t    sequence;
+        } echo;
+    uint32_t  gateway;
+    struct
+        {
+        uint16_t    unused;
+        uint16_t    mtu;
+        } frag;
+    } un;
+};
+//-----------------------------------------------------------------------------
+struct IP_HDR
+{
+    uint8_t     ihl:4,
+                version:4;
+    uint8_t     tos;
+    uint16_t    tot_len;
+    uint16_t    id;
+    uint16_t    frag_off;
+    uint8_t     ttl;
+    uint8_t     protocol;
+    uint16_t    check;
+    uint32_t    saddr;
+    uint32_t    daddr;
+};
+//-----------------------------------------------------------------------------
+struct PING_IP_TIME
+{
+uint32_t    ip;
+time_t      pingTime;
+};
+//-----------------------------------------------------------------------------
+
+#define PING_DATA_LEN   (64)
+//-----------------------------------------------------------------------------
+struct PING_MESSAGE
+{
+    ICMP_HDR    hdr;
+    char        msg[PING_DATA_LEN];
+};
+//-----------------------------------------------------------------------------
+class STG_PINGER
+{
+public:
+            STG_PINGER(time_t delay = 15);
+            ~STG_PINGER();
+
+    int     Start();
+    int     Stop();
+    void    AddIP(uint32_t ip);
+    void    DelIP(uint32_t ip);
+    int     GetPingIPNum();
+    void    GetAllIP(vector<PING_IP_TIME> * ipTime);
+    void    PrintAllIP();
+    int     GetIPTime(uint32_t ip, time_t * t);
+    void    SetDelayTime(time_t delay);
+    time_t  GetDelayTime();
+    string  GetStrError();
+
+private:
+
+    int         delay;
+    bool        nonstop;
+    bool        isRunningRecver;
+    bool        isRunningSender;
+    int         sendSocket;
+    int         recvSocket;
+    pthread_t   sendThread;
+    pthread_t   recvThread;
+
+    PING_MESSAGE pmSend;
+    uint32_t    pid;
+
+    uint16_t    PingCheckSum(void * data, int len);
+    int         SendPing(uint32_t ip);
+    uint32_t    RecvPing();
+    void        RealAddIP();
+    void        RealDelIP();
+
+    static void * RunSendPing(void * d);
+    static void * RunRecvPing(void * d);
+
+    string      errorStr;
+
+    multimap<uint32_t, time_t>   pingIP;
+    list<uint32_t>          ipToAdd;
+    list<uint32_t>          ipToDel;
+
+    pthread_mutex_t mutex;
+};
+//-----------------------------------------------------------------------------
+#endif
+
+
diff --git a/stglibs/pinger.lib/test.cpp b/stglibs/pinger.lib/test.cpp
new file mode 100644 (file)
index 0000000..af82eb4
--- /dev/null
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <vector>
+#include <string>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pinger.h"
+
+using namespace std;
+
+in_addr_t addr;
+
+//-----------------------------------------------------------------------------
+void AddRemoveTest(STG_PINGER & pinger)
+{
+addr = inet_addr("192.168.1.2");
+pinger.AddIP(*(uint32_t*)&addr);
+
+addr = inet_addr("192.168.1.2");
+pinger.AddIP(*(uint32_t*)&addr);
+
+sleep(2);
+pinger.PrintAllIP();
+printf("tree size=%d\n", pinger.GetPingIPNum());
+sleep(5);
+pinger.PrintAllIP();
+
+addr = inet_addr("192.168.1.2");
+pinger.DelIP(*(uint32_t*)&addr);
+printf("DelIP\n");
+sleep(10);
+//pinger.PrintAllIP();
+printf("tree size=%d\n", pinger.GetPingIPNum());
+sleep(3);
+pinger.PrintAllIP();
+printf("tree size=%d\n", pinger.GetPingIPNum());
+/*addr = inet_addr("192.168.1.2");
+pinger.DelIP(*(uint32_t*)&addr);
+
+addr = inet_addr("192.168.1.1");
+pinger.DelIP(*(uint32_t*)&addr);
+
+sleep(2);
+
+pinger.PrintAllIP();
+
+printf("tree size=%d\n", pinger.GetPingIPNum());
+sleep(5);
+
+addr = inet_addr("192.168.1.4");
+time_t t;
+if (pinger.GetIPTime(*(uint32_t*)&addr, &t) == 0)
+    {
+    printf("192.168.1.4 t=%lu\n", t);
+    }
+else
+    {
+    printf("192.168.1.4 not found\n");
+    }
+
+
+addr = inet_addr("192.168.1.5");
+if (pinger.GetIPTime(*(uint32_t*)&addr, &t) == 0)
+    {
+    printf("192.168.1.5 t=%lu\n", t);
+    }
+else
+    {
+    printf("192.168.1.5 not found\n");
+    }
+
+
+pinger.PrintAllIP();
+addr = inet_addr("192.168.1.3");
+if (pinger.GetIPTime(*(uint32_t*)&addr, &t))
+    {
+    printf("IP not present\n");
+    }
+else
+    {
+    printf("Ping time:\n");
+    }*/
+
+}
+//-----------------------------------------------------------------------------
+void StressTest(STG_PINGER & pinger)
+{
+
+for (int i = 1; i <= 200; i++)
+    {
+    char s[15];
+    sprintf(s, "192.168.1.%d", i);
+    addr = inet_addr(s);
+    pinger.AddIP(*(uint32_t*)&addr);
+    }
+
+sleep(5);
+pinger.PrintAllIP();
+printf("tree size=%d\n", pinger.GetPingIPNum());
+
+for (int i = 1; i <= 200; i++)
+    {
+    char s[15];
+    sprintf(s, "192.168.1.%d", i);
+    addr = inet_addr(s);
+    pinger.DelIP(*(uint32_t*)&addr);
+    }
+
+/*addr = inet_addr("192.168.1.2");
+pinger.AddIP(*(uint32_t*)&addr);
+
+addr = inet_addr("192.168.1.3");
+pinger.AddIP(*(uint32_t*)&addr);*/
+
+sleep(3);
+pinger.PrintAllIP();
+printf("tree size=%d\n", pinger.GetPingIPNum());
+sleep(1);
+}
+//-----------------------------------------------------------------------------
+int main()
+{
+vector<PING_IP_TIME> pingIP;
+
+STG_PINGER pinger(2);
+
+if (pinger.Start())
+    {
+    printf("%s\n", pinger.GetStrError().c_str());
+    }
+
+
+//AddRemoveTest(pinger);
+StressTest(pinger);
+
+pinger.Stop();
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/stglibs/script_executer.lib/Makefile b/stglibs/script_executer.lib/Makefile
new file mode 100644 (file)
index 0000000..90691ab
--- /dev/null
@@ -0,0 +1,12 @@
+###############################################################################
+# $Id: Makefile,v 1.6 2010/01/21 13:02:12 faust Exp $
+###############################################################################
+
+LIB_NAME = script_executer
+PROG = lib$(LIB_NAME)
+
+SRCS = script_executer.cpp
+
+INCS = script_executer.h
+
+include ../Makefile.in
diff --git a/stglibs/script_executer.lib/script_executer.cpp b/stglibs/script_executer.lib/script_executer.cpp
new file mode 100644 (file)
index 0000000..00ff094
--- /dev/null
@@ -0,0 +1,120 @@
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <cerrno>
+#include <csignal>
+
+#include "script_executer.h"
+
+using namespace std;
+
+#define MAX_SCRIPT_LEN  (1100)
+
+static int msgid;
+static bool nonstop;
+
+//-----------------------------------------------------------------------------
+struct SCRIPT_DATA
+{
+    long    mtype;
+    char    script[MAX_SCRIPT_LEN];
+} sd;
+//-----------------------------------------------------------------------------
+static void CatchUSR1Executer(int)
+{
+nonstop = false;
+}
+//-----------------------------------------------------------------------------
+int ScriptExec(const string & str)
+{
+if (str.length() >= MAX_SCRIPT_LEN)
+    return -1;
+
+int ret;
+strncpy(sd.script, str.c_str(), MAX_SCRIPT_LEN);
+sd.mtype = 1;
+ret = msgsnd(msgid, (void *)&sd, MAX_SCRIPT_LEN, 0);
+if (ret < 0)
+    {
+    return -1;
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+#ifdef LINUX
+void Executer(int, int msgID, pid_t pid, char * procName)
+#else
+void Executer(int, int msgID, pid_t pid, char *)
+#endif
+{
+msgid = msgID;
+if (pid)
+    return;
+nonstop = true;
+
+#ifdef LINUX
+memset(procName, 0, strlen(procName));
+strcpy(procName, "stg-exec");
+#else
+setproctitle("stg-exec");
+#endif
+
+struct sigaction newsa, oldsa;
+sigset_t sigmask;
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGTERM);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGTERM, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGINT);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGINT, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGHUP);
+newsa.sa_handler = SIG_IGN;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGHUP, &newsa, &oldsa);
+
+sigemptyset(&sigmask);
+sigaddset(&sigmask, SIGUSR1);
+newsa.sa_handler = CatchUSR1Executer;
+newsa.sa_mask = sigmask;
+newsa.sa_flags = 0;
+sigaction(SIGUSR1, &newsa, &oldsa);
+
+int ret;
+
+SCRIPT_DATA sd;
+
+while (nonstop)
+    {
+    sd.mtype = 1;
+    ret = msgrcv(msgid, &sd, MAX_SCRIPT_LEN, 0, 0);
+
+    if (ret < 0)
+        {
+        usleep(20000);
+        continue;
+        }
+    int ret = system(sd.script);
+    if (ret == -1)
+        {
+        // Fork failed
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/stglibs/script_executer.lib/script_executer.h b/stglibs/script_executer.lib/script_executer.h
new file mode 100644 (file)
index 0000000..19d458e
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SCRIPT_EXECUTER_H
+#define SCRIPT_EXECUTER_H
+
+#include <string>
+#include <sys/types.h>
+
+int ScriptExec(const std::string & str);
+void Executer(int msgKey, int msgID, pid_t pid, char * procName);
+
+#endif //SCRIPT_EXECUTER_H
+
+
diff --git a/stglibs/srvconf.lib/Makefile b/stglibs/srvconf.lib/Makefile
new file mode 100644 (file)
index 0000000..96ad48c
--- /dev/null
@@ -0,0 +1,19 @@
+###############################################################################
+# $Id: Makefile,v 1.9 2010/08/18 07:47:03 faust Exp $
+###############################################################################
+
+LIB_NAME = srvconf
+PROG = lib$(LIB_NAME)
+
+STGLIBS = -lstg_common \
+          -lstg_crypto
+LIBS = -lexpat
+
+SRCS =         netunit.cpp \
+        parser.cpp \
+        servconf.cpp
+
+INCS = servconf.h \
+       netunit.h
+
+include ../Makefile.in
diff --git a/stglibs/srvconf.lib/netunit.cpp b/stglibs/srvconf.lib/netunit.cpp
new file mode 100644 (file)
index 0000000..417db9d
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.6 $
+ $Date: 2009/02/06 10:25:54 $
+ $Author: faust $
+ */
+
+//---------------------------------------------------------------------------
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "netunit.h"
+#include "common.h"
+
+//---------------------------------------------------------------------------
+
+#define SEND_DATA_ERROR             "Send data error!"
+#define RECV_DATA_ANSWER_ERROR      "Recv data answer error!"
+#define UNKNOWN_ERROR               "Unknown error!"
+#define CONNECT_FAILED              "Connect failed!"
+#define INCORRECT_LOGIN             "Incorrect login!"
+#define INCORRECT_HEADER            "Incorrect header!"
+#define SEND_LOGIN_ERROR            "Send login error!"
+#define RECV_LOGIN_ANSWER_ERROR     "Recv login answer error!"
+#define CREATE_SOCKET_ERROR         "Create socket failed!"
+#define WSASTARTUP_FAILED           "WSAStartup failed!"
+#define SEND_HEADER_ERROR           "Send header error!"
+#define RECV_HEADER_ANSWER_ERROR    "Recv header answer error!"
+
+//---------------------------------------------------------------------------
+NETTRANSACT::NETTRANSACT()
+{
+RxCallBack = NULL;
+}
+//-----------------------------------------------------------------------------
+void NETTRANSACT::EnDecryptInit(const char * passwd, int passwdLen, BLOWFISH_CTX *ctx)
+{
+unsigned char * keyL = NULL;//[PASSWD_LEN];  // ��� ������
+
+keyL = new unsigned char[PASSWD_LEN];
+
+memset(keyL, 0, PASSWD_LEN);
+
+strncpy((char *)keyL, passwd, PASSWD_LEN);
+
+Blowfish_Init(ctx, keyL, PASSWD_LEN);
+
+delete[] keyL;
+}
+//-----------------------------------------------------------------------------
+void NETTRANSACT::Encrypt(char * d, const char * s, BLOWFISH_CTX *ctx)
+{
+/*unsigned char ss[8];
+
+memcpy(ss, s, 8);
+
+Blowfish_Encrypt(ctx, (uint32_t *)ss, (uint32_t *)(ss + 4));
+
+memcpy(d, ss, 8);*/
+EncodeString(d, s, ctx);
+
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::Decrypt(char * d, const char * s, BLOWFISH_CTX *ctx)
+{
+/*unsigned char ss[8];
+
+memcpy(ss, s, 8);
+
+Blowfish_Decrypt(ctx, (uint32_t *)ss, (uint32_t *)(ss + 4));
+
+memcpy(d, ss, 8);*/
+DecodeString(d, s, ctx);
+
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::Connect()
+{
+int ret;
+
+outerSocket = socket(PF_INET, SOCK_STREAM, 0);
+if (outerSocket < 0)
+    {
+    strcpy(errorMsg, CREATE_SOCKET_ERROR);
+    return st_conn_fail;
+    }
+
+memset(&outerAddr, 0, sizeof(outerAddr));
+memset(&localAddr, 0, sizeof(localAddr));
+
+struct hostent he;
+struct hostent * phe;
+
+unsigned long ip;
+ip = inet_addr(server);
+
+if (ip == INADDR_NONE)
+    {
+    phe = gethostbyname(server);
+    if (phe == NULL)
+        {
+        sprintf(errorMsg, "DNS error.\nCan not reslove %s", server);
+        return st_dns_err;
+        }
+
+    memcpy(&he, phe, sizeof(he));
+    ip = *((long*)he.h_addr_list[0]);
+    }
+outerAddr.sin_family = AF_INET;
+outerAddr.sin_port = htons(port);
+outerAddr.sin_addr.s_addr = ip;
+
+ret = connect(outerSocket, (struct sockaddr*)&outerAddr, sizeof(outerAddr));
+
+if (ret < 0)
+    {
+    strcpy(errorMsg, CONNECT_FAILED);
+    close(outerSocket);
+    return st_conn_fail;
+    }
+return st_ok;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::Disconnect()
+{
+close(outerSocket);
+return 0;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::Transact(const char * data)
+{
+int ret;
+if ((ret = TxHeader()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = RxHeaderAnswer()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = TxLogin()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = RxLoginAnswer()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = TxLoginS()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = RxLoginSAnswer()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = TxData(data)) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+if ((ret = RxDataAnswer()) != st_ok)
+    {
+    Disconnect();
+    return ret;
+    }
+
+return st_ok;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::TxHeader()
+{
+int ret;
+ret = send(outerSocket, STG_HEADER, strlen(STG_HEADER), 0);
+if (ret <= 0)
+    {
+    strcpy(errorMsg, SEND_HEADER_ERROR);
+    return st_send_fail;
+    }
+
+return st_ok;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::RxHeaderAnswer()
+{
+char buffer[sizeof(STG_HEADER)+1];
+int ret;//, we;
+
+ret = recv(outerSocket, buffer, strlen(OK_HEADER), 0);
+if (ret <= 0)
+    {
+    //we = WSAGetLastError();
+    strcpy(errorMsg, RECV_HEADER_ANSWER_ERROR);
+    return st_recv_fail;
+    }
+
+if (strncmp(OK_HEADER, buffer, strlen(OK_HEADER)) == 0)
+    {
+    return st_ok;
+    }
+else
+    {
+    if (strncmp(ERR_HEADER, buffer, strlen(ERR_HEADER)) == 0)
+        {
+        strcpy(errorMsg, INCORRECT_HEADER);
+        return st_header_err;
+        }
+    else
+        {
+        strcpy(errorMsg, UNKNOWN_ERROR);
+        return st_unknown_err;
+        }
+    }
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::TxLogin()
+{
+char loginZ[ADM_LOGIN_LEN];
+int ret;
+
+memset(loginZ, 0, ADM_LOGIN_LEN);
+strncpy(loginZ, login, ADM_LOGIN_LEN);
+ret = send(outerSocket, loginZ, ADM_LOGIN_LEN, 0);
+
+if (ret <= 0)
+    {
+    strcpy(errorMsg, SEND_LOGIN_ERROR);
+    return st_send_fail;
+    }
+
+return st_ok;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::RxLoginAnswer()
+{
+char buffer[sizeof(OK_LOGIN)+1];
+int ret;//, we;
+
+ret = recv(outerSocket, buffer, strlen(OK_LOGIN), 0);
+if (ret <= 0)
+    {
+    strcpy(errorMsg, RECV_LOGIN_ANSWER_ERROR);
+    return st_recv_fail;
+    }
+
+if (strncmp(OK_LOGIN, buffer, strlen(OK_LOGIN)) == 0)
+    {
+    return st_ok;
+    }
+else
+    {
+    if (strncmp(ERR_LOGIN, buffer, strlen(ERR_LOGIN)) == 0)
+        {
+        strcpy(errorMsg, INCORRECT_LOGIN);
+        return st_login_err;
+        }
+    else
+        {
+        strcpy(errorMsg, UNKNOWN_ERROR);
+        return st_unknown_err;
+        }
+    }
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::TxLoginS()
+{
+char loginZ[ADM_LOGIN_LEN];
+char ct[ENC_MSG_LEN];
+int ret;
+
+memset(loginZ, 0, ADM_LOGIN_LEN);
+strncpy(loginZ, login, ADM_LOGIN_LEN);
+
+BLOWFISH_CTX ctx;
+EnDecryptInit(password, PASSWD_LEN, &ctx);
+
+for (int j = 0; j < ADM_LOGIN_LEN / ENC_MSG_LEN; j++)
+    {
+    Encrypt(ct, loginZ + j*ENC_MSG_LEN, &ctx);
+    ret = send(outerSocket, ct, ENC_MSG_LEN, 0);
+    if (ret <= 0)
+        {
+        strcpy(errorMsg, SEND_LOGIN_ERROR);
+        return st_send_fail;
+        }
+    }
+
+return st_ok;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::RxLoginSAnswer()
+{
+char buffer[sizeof(OK_LOGINS)+1];
+int ret;
+
+ret = recv(outerSocket, buffer, strlen(OK_LOGINS), 0);
+if (ret <= 0)
+    {
+    strcpy(errorMsg, RECV_LOGIN_ANSWER_ERROR);
+    return st_recv_fail;
+    }
+
+if (strncmp(OK_LOGINS, buffer, strlen(OK_LOGINS)) == 0)
+    {
+    return st_ok;
+    }
+else
+    {
+    if (strncmp(ERR_LOGINS, buffer, strlen(ERR_LOGINS)) == 0)
+        {
+        strcpy(errorMsg, INCORRECT_LOGIN);
+        return st_logins_err;
+        }
+    else
+        {
+        strcpy(errorMsg, UNKNOWN_ERROR);
+        return st_unknown_err;
+        }
+    }
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::TxData(const char * text)
+{
+char textZ[ENC_MSG_LEN];
+char ct[ENC_MSG_LEN];
+int ret;
+int j;
+
+int n = strlen(text) / ENC_MSG_LEN;
+int r = strlen(text) % ENC_MSG_LEN;
+
+BLOWFISH_CTX ctx;
+EnDecryptInit(password, PASSWD_LEN, &ctx);
+
+for (j = 0; j < n; j++)
+    {
+    strncpy(textZ, text + j*ENC_MSG_LEN, ENC_MSG_LEN);
+    Encrypt(ct, textZ, &ctx);
+    ret = send(outerSocket, ct, ENC_MSG_LEN, 0);
+    if (ret <= 0)
+        {
+        strcpy(errorMsg, SEND_DATA_ERROR);
+        return st_send_fail;
+        }
+    }
+
+memset(textZ, 0, ENC_MSG_LEN);
+if (r)
+    strncpy(textZ, text + j*ENC_MSG_LEN, ENC_MSG_LEN);
+
+EnDecryptInit(password, PASSWD_LEN, &ctx);
+
+Encrypt(ct, textZ, &ctx);
+ret = send(outerSocket, ct, ENC_MSG_LEN, 0);
+if (ret <= 0)
+    {
+    strcpy(errorMsg, SEND_DATA_ERROR);
+    return st_send_fail;
+    }
+
+return st_ok;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::TxData(char * data)
+{
+char buff[ENC_MSG_LEN];
+char buffS[ENC_MSG_LEN];
+char passwd[ADM_PASSWD_LEN];
+
+strncpy(passwd, password, ADM_PASSWD_LEN);
+memset(buff, 0, ENC_MSG_LEN);
+
+int l = strlen(data)/ENC_MSG_LEN;
+if (strlen(data)%ENC_MSG_LEN)
+    l++;
+
+BLOWFISH_CTX ctx;
+EnDecryptInit(passwd, PASSWD_LEN, &ctx);
+
+for (int j = 0; j < l; j++)
+    {
+    strncpy(buff, &data[j*ENC_MSG_LEN], ENC_MSG_LEN);
+    Encrypt(buffS, buff, &ctx);
+    send(outerSocket, buffS, ENC_MSG_LEN, 0);
+    }
+
+return 0;
+}
+//---------------------------------------------------------------------------
+int NETTRANSACT::RxDataAnswer()
+{
+int n = 0;
+int ret;
+char bufferS[ENC_MSG_LEN];
+char buffer[ENC_MSG_LEN + 1];
+
+BLOWFISH_CTX ctx;
+EnDecryptInit(password, PASSWD_LEN, &ctx);
+
+while (1)
+    {
+    ret = recv(outerSocket, &bufferS[n++], 1, 0);
+    if (ret <= 0)
+        {
+        close(outerSocket);
+        strcpy(errorMsg, RECV_DATA_ANSWER_ERROR);
+        return st_recv_fail;
+        }
+
+    if (n == ENC_MSG_LEN)
+        {
+
+        n = 0;
+        Decrypt(buffer, bufferS, &ctx);
+        buffer[ENC_MSG_LEN] = 0;
+
+        answerList.push_back(buffer);
+
+        for (int j = 0; j < ENC_MSG_LEN; j++)
+            {
+            if (buffer[j] == 0)
+                {
+                if (RxCallBack)
+                    if (st_ok != RxCallBack(dataRxCallBack, &answerList))
+                        {
+                        return st_xml_parse_error;
+                        }
+                return st_ok;
+                }
+            }
+        }
+    }
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::SetLogin(const char * l)
+{
+strncpy(login, l, ADM_LOGIN_LEN);
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::SetPassword(const char * p)
+{
+strncpy(password, p, ADM_PASSWD_LEN);
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::SetServer(const char * serverName)
+{
+strncpy(server, serverName, SERVER_NAME_LEN);
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::SetServerPort(short unsigned p)
+{
+port = p;
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::SetRxCallback(void * data, RxCallback_t cb)
+{
+RxCallBack = cb;
+dataRxCallBack = data;
+}
+//---------------------------------------------------------------------------
+char * NETTRANSACT::GetError()
+{
+return errorMsg;
+}
+//---------------------------------------------------------------------------
+void NETTRANSACT::Reset()
+{
+answerList.clear();
+}
+//---------------------------------------------------------------------------
+
diff --git a/stglibs/srvconf.lib/netunit.h b/stglibs/srvconf.lib/netunit.h
new file mode 100644 (file)
index 0000000..72d3b72
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.6 $
+ $Date: 2010/02/11 12:32:53 $
+ $Author: faust $
+ */
+
+#ifndef NetUnitH
+#define NetUnitH
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <list>
+#include <string>
+
+#include "common.h"
+#include "blowfish.h"
+
+#define  STG_HEADER     "SG04"
+#define  OK_HEADER      "OKHD"
+#define  ERR_HEADER     "ERHD"
+#define  OK_LOGIN       "OKLG"
+#define  ERR_LOGIN      "ERLG"
+#define  OK_LOGINS      "OKLS"
+#define  ERR_LOGINS     "ERLS"
+
+// äÌÉÎÎÁ ÛÉÆÒÕÅÍÏÇÏ É ÐÅÒÅÄÁ×ÁÅÍÏÇ ÚÁ ÏÄÉΠÒÁÚ ÂÌÏËÁ ÉÎÆÏÒÍÁÃÉÉ
+#define  ENC_MSG_LEN    (8)
+
+#define MAX_ERR_STR_LEN (64)
+
+typedef int(*RxCallback_t)(void *, std::list<std::string> *);
+
+enum status
+{
+st_ok = 0,
+st_conn_fail,
+st_send_fail,
+st_recv_fail,
+st_header_err,
+st_login_err,
+st_logins_err,
+st_data_err,
+st_unknown_err,
+st_dns_err,
+st_xml_parse_error,
+st_data_error
+};
+
+enum CONF_STATE
+{
+confHdr = 0,
+confLogin,
+confLoginCipher,
+confData
+};
+//---------------------------------------------------------------------------
+class NETTRANSACT
+{
+public:
+    NETTRANSACT();
+    int     Transact(const char * data);
+    char   *GetError();
+
+    void    SetRxCallback(void * data, RxCallback_t);
+
+    void    SetServer(const char * serverName);
+    void    SetServerPort(short unsigned p);
+
+    void    SetLogin(const char * l);
+    void    SetPassword(const char * p);
+    ////////////////////////////////////////////
+    int     Connect();
+    int     Disconnect();
+    void    Reset();
+private:
+    int     TxHeader();
+    int     RxHeaderAnswer();
+
+    int     TxLogin();
+    int     RxLoginAnswer();
+
+    int     TxLoginS();
+    int     RxLoginSAnswer();
+
+    int     TxData(const char * text);
+    int     TxData(char * data);
+    int     RxDataAnswer();
+
+    void Encrypt(char * d, const char * s, BLOWFISH_CTX *ctx);
+    void EnDecryptInit(const char * passwd, int passwdLen, BLOWFISH_CTX *ctx);
+    void Decrypt(char * d, const char * s, BLOWFISH_CTX *ctx);
+
+    //unsigned ip;
+    char    server[SERVER_NAME_LEN];
+    short unsigned  port;
+    char    login[ADM_LOGIN_LEN];
+    char    password[ADM_PASSWD_LEN];
+    int     outerSocket;
+    int     localSocket;
+    struct  sockaddr_in outerAddr;
+    struct  sockaddr_in localAddr;
+    int     error;
+    std::list<std::string>   answerList;
+    RxCallback_t RxCallBack;
+    void *  dataRxCallBack;
+    char    errorMsg[MAX_ERR_STR_LEN];
+};
+//---------------------------------------------------------------------------
+#endif
diff --git a/stglibs/srvconf.lib/parser.cpp b/stglibs/srvconf.lib/parser.cpp
new file mode 100644 (file)
index 0000000..7c96b2e
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.18 $
+ $Date: 2010/08/04 00:40:00 $
+ $Author: faust $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string>
+
+#include "common.h"
+//#include "srvconf_common.h"
+#include "stg_const.h"
+#include "servconf.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+PARSER::PARSER()
+{
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PARSER_GET_USERS::PARSER_GET_USERS()
+{
+depth = 0;
+error = false;
+RecvUserDataCb = NULL;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::Reset()
+{
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USERS::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    ParseUsers(el, attr);
+    }
+
+if (depth == 2)
+    {
+    ParseUser(el, attr);
+    }
+
+if (depth == 3)
+    {
+    ParseUserParams(el, attr);
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::ParseEnd(const char *)
+{
+depth--;
+if (depth == 1)
+    {
+    if (RecvUserDataCb)
+        {
+        RecvUserDataCb(&user, userDataCb);
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::ParseUsers(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "users") == 0)
+    {
+    if (*attr != NULL)
+        return;
+    return;
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::ParseUser(const char * el, const char ** attr)
+{
+if (el && attr[0])
+    {
+    if (strcasecmp(el, "user") != 0)
+        {
+        return;
+        }
+
+    if (strcasecmp(attr[0], "login") != 0)
+        {
+        return;
+        }
+    user.login = attr[1];
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::ParseUserParams(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "cash") == 0)
+    {
+    if (strtodouble2(attr[1], user.cash) < 0)
+        {
+        return;
+        }
+    }
+
+/*if (strcasecmp(el, "LastCash") == 0)
+    {
+    if (strtodouble2(attr[1], user.lastCash) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }*/
+
+/*if (strcasecmp(el, "LastActivityTime") == 0)
+    {
+    if (strtol(attr[1], user.lastActivityTime) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }*/
+
+
+/*if (strcasecmp(el, "LastTimeCash") == 0)
+    {
+    if (strtol(attr[1], user.lastTimeCash) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }*/
+
+/*if (strcasecmp(el, "CashExpire") == 0)
+    {
+    if (strtol(attr[1], user.cashExpire) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }*/
+
+if (strcasecmp(el, "credit") == 0)
+    {
+    if (strtodouble2(attr[1], user.credit) < 0)
+        {
+        return;
+        }
+    }
+
+/*if (strcasecmp(el, "freemb") == 0)
+    {
+    if (strtodouble2(attr[1], user.freeMb) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }*/
+
+if (strcasecmp(el, "down") == 0)
+    {
+    if (str2x(attr[1], user.down) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "passive") == 0)
+    {
+    if (str2x(attr[1], user.passive) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "disableDetailStat") == 0)
+    {
+    if (str2x(attr[1], user.disableDetailStat) < 0)
+        {
+        return;
+        }
+    }
+
+
+if (strcasecmp(el, "status") == 0)
+    {
+    if (str2x(attr[1], user.connected) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "aonline") == 0)
+    {
+    if (str2x(attr[1], user.alwaysOnline) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "currip") == 0)
+    {
+    user.ip = inet_addr(attr[1]);
+    }
+
+if (strcasecmp(el, "ip") == 0)
+    {
+    user.ips = attr[1];
+    }
+
+
+if (strcasecmp(el, "tariff") == 0)
+    {
+    //KOIToWin(user.tariff, *(attr+1), TARIFF_LEN);
+    user.tariff = attr[1];
+    return;
+    }
+
+if (strcasecmp(el, "password") == 0)
+    {
+    user.password = *(attr+1);
+    return;
+    }
+
+if (strcasecmp(el, "iface") == 0)
+    {
+    user.iface = attr[1];
+    return;
+    }
+
+/*if (strcasecmp(el, "name") == 0)
+    {
+    / *char nameEnc[REALNM_LEN * 2 + 1];
+    char name[REALNM_LEN];
+    strncpy(nameEnc, attr[1], REALNM_LEN * 2 + 1);
+    Decode21(name, nameEnc);
+    KOIToWin(user.realName, name, REALNM_LEN);* /
+    Decode21str(user.realName, attr[1]);
+    return;
+    }*/
+
+if (strcasecmp(el, "address") == 0)
+    {
+    /*char addressEnc[ADDR_LEN * 2 + 1];
+    char address[ADDR_LEN];
+    strncpy(addressEnc, attr[1], ADDR_LEN * 2 + 1);
+    Decode21(address, addressEnc);
+    KOIToWin(user.address, address, ADDR_LEN);*/
+    Decode21str(user.address, attr[1]);
+    return;
+    }
+
+if (strcasecmp(el, "phone") == 0)
+    {
+    /*char phoneEnc[PHONE_LEN * 2 + 1];
+    char phone[PHONE_LEN];
+    strncpy(phoneEnc, attr[1], PHONE_LEN * 2 + 1);
+    Decode21(phone, phoneEnc);
+    KOIToWin(user.phone, phone, PHONE_LEN);*/
+    Decode21str(user.phone, attr[1]);
+    return;
+    }
+
+if (strcasecmp(el, "note") == 0)
+    {
+    /*char noteEnc[NOTE_LEN * 2 + 1];
+    char note[NOTE_LEN];
+    strncpy(noteEnc, attr[1], NOTE_LEN * 2 + 1);*/
+    //KOIToWin(user.note, note, NOTE_LEN);
+    //user.note = note;
+    Decode21str(user.note, attr[1]);
+    return;
+    }
+
+if (strcasecmp(el, "email") == 0)
+    {
+    /*char emailEnc[EMAIL_LEN * 2 + 1];
+    char email[EMAIL_LEN];
+    strncpy(emailEnc, attr[1], EMAIL_LEN * 2 + 1);
+    Decode21(email, emailEnc);
+    //KOIToWin(user.email, email, EMAIL_LEN);
+    user.email = email;*/
+    Decode21str(user.email, attr[1]);
+    return;
+    }
+
+if (strcasecmp(el, "group") == 0)
+    {
+    /*char groupEnc[GROUP_LEN * 2 + 1];
+    char group[GROUP_LEN];
+    strncpy(groupEnc, attr[1], GROUP_LEN * 2 + 1);
+    Decode21(group, groupEnc);
+    //KOIToWin(user.group, group, GROUP_LEN);
+    user.group = group;*/
+    Decode21str(user.group, attr[1]);
+    return;
+    }
+
+if (strcasecmp(el, "traff") == 0)
+    {
+    ParseUserLoadStat(el, attr);
+    return;
+    }
+
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::ParseUserLoadStat(const char *, const char ** attr)
+{
+int i = 0;
+char dir[6];
+while (attr[i])
+    {
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "MU%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.mu[j]);
+            break;
+            }
+        }
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "MD%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.md[j]);
+            break;
+            }
+        }
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "SU%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.su[j]);
+            break;
+            }
+        }
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "SD%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.sd[j]);
+            break;
+            }
+        }
+    i+=2;
+    }
+return;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USERS::SetUserDataRecvCb(RecvUserDataCb_t f, void * data)
+{
+RecvUserDataCb = f;
+userDataCb = data;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PARSER_GET_USER::PARSER_GET_USER()
+{
+depth = 0;
+error = false;
+RecvUserDataCb = NULL;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::Reset()
+{
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_USER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    ParseUser(el, attr);
+    }
+
+if (depth == 2)
+    {
+    ParseUserParams(el, attr);
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::ParseEnd(const char *)
+{
+depth--;
+if (depth == 0)
+    {
+    if (RecvUserDataCb)
+        {
+        RecvUserDataCb(&user, userDataCb);
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::ParseUser(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "user") == 0)
+    {
+    if (strcasecmp(attr[1], "error") == 0)
+        user.login = "";
+    return;
+    }
+}
+//-----------------------------------------------------------------------------
+struct ParsedStringParams
+{
+string    * param;
+string      paramName;
+};
+//-----------------------------------------------------------------------------
+struct ParsedDoubleParams
+{
+double    * param;
+string      paramName;
+};
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::ParseUserParams(const char * el, const char ** attr)
+{
+//printf("PARSER_GET_USER::ParseUserParams el=%s attr[1]=%s\n", el, attr[1]);
+
+if (strcasecmp(el, "login") == 0)
+    {
+    user.login = attr[1];
+    }
+
+
+/*if (strcasecmp(el, "LastActivityTime") == 0)
+    {
+    if (strtol(attr[1], user.lastActivityTime) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }
+
+
+if (strcasecmp(el, "LastTimeCash") == 0)
+    {
+    if (strtol(attr[1], user.lastTimeCash) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }
+
+if (strcasecmp(el, "CashExpire") == 0)
+    {
+    if (strtol(attr[1], user.cashExpire) < 0)
+        {
+        MessageDlg("Error in answer", mtError, TMsgDlgButtons() << mbOK, 0);
+        return 0;
+        }
+    }
+*/
+
+if (strcasecmp(el, "down") == 0)
+    {
+    if (str2x(attr[1], user.down) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "passive") == 0)
+    {
+    if (str2x(attr[1], user.passive) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "disableDetailStat") == 0)
+    {
+    if (str2x(attr[1], user.disableDetailStat) < 0)
+        {
+        return;
+        }
+    }
+
+
+if (strcasecmp(el, "status") == 0)
+    {
+    if (str2x(attr[1], user.connected) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "aonline") == 0)
+    {
+    if (str2x(attr[1], user.alwaysOnline) < 0)
+        {
+        return;
+        }
+    }
+
+if (strcasecmp(el, "currip") == 0)
+    {
+    user.ip = inet_addr(attr[1]);
+    }
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    {
+    string num;
+    x2str(i, num);
+    string udName = "UserData" + num;
+    if (strcasecmp(el, udName.c_str()) == 0)
+        {
+        Decode21str(user.userData[i], attr[1]);
+        return;
+        }
+    }
+
+ParsedStringParams psp[] =
+{
+    {&user.ips,         "ip"},
+    {&user.tariff,      "tariff"},
+    {&user.password,    "password"},
+    {&user.iface,       "iface"},
+};
+
+for (unsigned i = 0; i < sizeof(psp)/sizeof(ParsedStringParams); i++)
+    {
+    if (strcasecmp(el, psp[i].paramName.c_str()) == 0)
+        {
+        *psp[i].param = attr[1];
+        return;
+        }
+    }
+
+ParsedStringParams pspEnc[] =
+{
+    {&user.note,    "note"},
+    {&user.email,   "email"},
+    {&user.group,   "group"},
+    {&user.name,    "name"},
+    {&user.address, "address"},
+    {&user.phone,   "phone"}
+};
+
+for (unsigned i = 0; i < sizeof(pspEnc)/sizeof(ParsedStringParams); i++)
+    {
+    if (strcasecmp(el, pspEnc[i].paramName.c_str()) == 0)
+        {
+        Decode21str(*pspEnc[i].param, attr[1]);
+        return;
+        }
+    }
+
+ParsedDoubleParams pdp[] =
+{
+    {&user.cash,            "cash"},
+    {&user.credit,          "credit"},
+    {&user.lastCash,        "lastCash"},
+    {&user.prepaidTraff,    "freemb"},
+};
+
+for (unsigned i = 0; i < sizeof(pdp)/sizeof(ParsedDoubleParams); i++)
+    {
+    if (strcasecmp(el, pdp[i].paramName.c_str()) == 0)
+        {
+        strtodouble2(attr[1], *pdp[i].param);
+        return;
+        }
+    }
+
+if (strcasecmp(el, "traff") == 0)
+    {
+    ParseUserLoadStat(el, attr);
+    return;
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::ParseUserLoadStat(const char *, const char ** attr)
+{
+int i = 0;
+char dir[6];
+while (attr[i])
+    {
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "MU%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.mu[j]);
+            break;
+            }
+        }
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "MD%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.md[j]);
+            break;
+            }
+        }
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "SU%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.su[j]);
+            break;
+            }
+        }
+    for (int j = 0; j < DIR_NUM; j++)
+        {
+        sprintf(dir, "SD%d", j);
+        if (strcasecmp(dir, attr[i]) == 0)
+            {
+            str2x(attr[i+1], user.stat.sd[j]);
+            break;
+            }
+        }
+    i+=2;
+    }
+return;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_USER::SetUserDataRecvCb(RecvUserDataCb_t f, void * data)
+{
+RecvUserDataCb = f;
+userDataCb = data;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PARSER_GET_SERVER_INFO::PARSER_GET_SERVER_INFO()
+{
+depth = 0;
+error = false;
+RecvServerInfoDataCb = NULL;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::Reset()
+{
+
+}
+//-----------------------------------------------------------------------------
+int PARSER_GET_SERVER_INFO::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "ServerInfo") != 0)
+        {
+        //printf("%s\n", el);
+        }
+    }
+else
+    {
+    if (depth == 2)
+        {
+        if (strcasecmp(el, "uname") == 0)
+            {
+            ParseUname(attr);
+            return 0;
+            }
+        if (strcasecmp(el, "version") == 0)
+            {
+            ParseServerVersion(attr);
+            return 0;
+            }
+        if (strcasecmp(el, "tariff") == 0)
+            {
+            ParseTariffType(attr);
+            return 0;
+            }
+        if (strcasecmp(el, "dir_num") == 0)
+            {
+            ParseDirNum(attr);
+            return 0;
+            }
+        if (strcasecmp(el, "users_num") == 0)
+            {
+            ParseUsersNum(attr);
+            return 0;
+            }
+        if (strcasecmp(el, "tariff_num") == 0)
+            {
+            ParseTariffsNum(attr);
+            return 0;
+            }
+
+        for (int j = 0; j < DIR_NUM; j++)
+            {
+            char str[16];
+            sprintf(str, "dir_name_%d", j);
+            if (strcasecmp(el, str) == 0)
+                {
+                ParseDirName(attr, j);
+                }
+            }
+
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseEnd(const char *)
+{
+depth--;
+if (depth == 0)
+    {
+    RecvServerInfoDataCb(&serverInfo, serverInfoDataCb);
+    }
+}
+//-----------------------------------------------------------------------------
+/*void PARSER_GET_SERVER_INFO::ParseServerInfo(const char * el, const char ** attr)
+    {
+    }*/
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::SetServerInfoRecvCb(RecvServerInfoDataCb_t f, void * data)
+{
+RecvServerInfoDataCb = f;
+serverInfoDataCb = data;
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseUname(const char ** attr)
+{
+if (strcmp(*attr, "value") == 0)
+    serverInfo.uname = attr[1];
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseServerVersion(const char ** attr)
+{
+if (strcmp(*attr, "value") == 0)
+    serverInfo.version = attr[1];
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseUsersNum(const char ** attr)
+{
+if (strcmp(*attr, "value") == 0)
+    {
+    if (str2x(attr[1], serverInfo.usersNum) < 0)
+        {
+        serverInfo.usersNum = -1;
+        return;
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseTariffsNum(const char ** attr)
+{
+if (strcmp(*attr, "value") == 0)
+    {
+    if (str2x(attr[1], serverInfo.tariffNum) < 0)
+        {
+        serverInfo.tariffNum = -1;
+        return;
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseTariffType(const char ** attr)
+{
+if (strcmp(*attr, "value") == 0)
+    {
+    if (str2x(attr[1], serverInfo.tariffType) < 0)
+        {
+        serverInfo.tariffType = -1;
+        return;
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseDirNum(const char **attr)
+{
+if (strcasecmp(*attr, "value") == 0)
+    {
+    if (str2x(attr[1], serverInfo.dirNum) < 0)
+        {
+        serverInfo.dirNum = -1;
+        return;
+        }
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_GET_SERVER_INFO::ParseDirName(const char **attr, int d)
+{
+if (strcmp(attr[0], "value") == 0)
+    {
+    char str[2*DIRNAME_LEN + 1];
+    Decode21(str, attr[1]);
+    serverInfo.dirName[d] = str;
+    }
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PARSER_CHG_USER::PARSER_CHG_USER()
+{
+depth = 0;
+error = false;
+RecvChgUserCb = NULL;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHG_USER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SetUser") == 0)
+        {
+        ParseAnswer(el, attr);
+        }
+    else if (strcasecmp(el, "DelUser") == 0)
+        {
+        ParseAnswer(el, attr);
+        }
+    else if (strcasecmp(el, "AddUser") == 0)
+        {
+        ParseAnswer(el, attr);
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::ParseEnd(const char *)
+{
+depth--;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::Reset()
+{
+
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::ParseAnswer(const char *, const char **attr)
+{
+if (RecvChgUserCb)
+    {
+    RecvChgUserCb(attr[1], chgUserCbData);
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHG_USER::SetChgUserRecvCb(RecvChgUserCb_t f, void * data)
+{
+RecvChgUserCb = f;
+chgUserCbData = data;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PARSER_CHECK_USER::PARSER_CHECK_USER()
+{
+depth = 0;
+error = false;
+RecvCheckUserCb = NULL;
+}
+//-----------------------------------------------------------------------------
+int PARSER_CHECK_USER::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "CheckUser") == 0)
+        {
+        //printf("el=%s attr[0]=%s attr[1]=%s\n", el, attr[0], attr[1]);
+        ParseAnswer(el, attr);
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHECK_USER::ParseEnd(const char *)
+{
+depth--;
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHECK_USER::ParseAnswer(const char *, const char **attr)
+{
+if (RecvCheckUserCb)
+    {
+    RecvCheckUserCb(attr[1], checkUserCbData);
+    }
+}
+//-----------------------------------------------------------------------------
+void PARSER_CHECK_USER::SetCheckUserRecvCb(RecvCheckUserCb_t f, void * data)
+{
+RecvCheckUserCb = f;
+checkUserCbData = data;
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+PARSER_SEND_MESSAGE::PARSER_SEND_MESSAGE()
+{
+depth = 0;
+error = false;
+RecvSendMessageCb = NULL;
+}
+//-----------------------------------------------------------------------------
+int  PARSER_SEND_MESSAGE::ParseStart(const char *el, const char **attr)
+{
+depth++;
+if (depth == 1)
+    {
+    if (strcasecmp(el, "SendMessageResult") == 0)
+        {
+        ParseAnswer(el, attr);
+        }
+    }
+return 0;
+}
+//-----------------------------------------------------------------------------
+void PARSER_SEND_MESSAGE::ParseEnd(const char *)
+{
+depth--;
+}
+//-----------------------------------------------------------------------------
+void PARSER_SEND_MESSAGE::Reset()
+{
+
+}
+//-----------------------------------------------------------------------------
+void PARSER_SEND_MESSAGE::ParseAnswer(const char *, const char **attr)
+{
+if (RecvSendMessageCb)
+    RecvSendMessageCb(attr[1], sendMessageCbData);
+}
+//-----------------------------------------------------------------------------
+void PARSER_SEND_MESSAGE::SetSendMessageRecvCb(RecvSendMessageCb_t f, void * data)
+{
+RecvSendMessageCb = f;
+sendMessageCbData = data;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/srvconf.lib/servconf.cpp b/stglibs/srvconf.lib/servconf.cpp
new file mode 100644 (file)
index 0000000..be6fa27
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.8 $
+ $Date: 2010/08/04 00:40:38 $
+ $Author: faust $
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "servconf.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+int AnsRecv(void * data, list<string> * list1)
+{
+//NODE * node;
+SERVCONF * sc;
+char ans[ENC_MSG_LEN + 1];
+int len, done = 0;
+
+sc = (SERVCONF*)data;
+
+XML_ParserReset(sc->parser, NULL);
+XML_SetElementHandler(sc->parser, Start, End);
+XML_SetUserData(sc->parser, data);
+
+//loop parsing
+list<string>::iterator node;
+node = list1->begin();
+
+if (node == list1->end())
+    {
+    return st_ok;
+    }
+
+while (node != list1->end())
+    {
+    strncpy(ans, node->c_str(), ENC_MSG_LEN);
+    ans[ENC_MSG_LEN] = 0;
+       //printf("---> %s\n", ans);
+    len = strlen(ans);
+
+    if (XML_Parse(sc->parser, ans, len, done) == XML_STATUS_ERROR)
+        {
+        snprintf(sc->errorMsg, MAX_ERR_STR_LEN, "XML parse error at line %d: %s",
+                 static_cast<int>(XML_GetCurrentLineNumber(sc->parser)),
+                 XML_ErrorString(XML_GetErrorCode(sc->parser)));
+        printf(sc->errorMsg, "XML parse error at line %d: %s",
+               XML_GetCurrentLineNumber(sc->parser),
+               XML_ErrorString(XML_GetErrorCode(sc->parser)));
+        return st_xml_parse_error;
+        }
+    ++node;
+
+    }
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+void Start(void *data, const char *el, const char **attr)
+{
+SERVCONF * sc;
+sc = (SERVCONF*)data;
+sc->Start(el, attr);
+}
+//-----------------------------------------------------------------------------
+void End(void *data, const char *el)
+{
+SERVCONF * sc;
+sc = (SERVCONF*)data;
+sc->End(el);
+}
+//-----------------------------------------------------------------------------
+SERVCONF::SERVCONF()
+{
+parser = XML_ParserCreate(NULL);
+parseDepth = 0;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetServer(const char * server)
+{
+nt.SetServer(server);
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetPort(uint16_t port)
+{
+nt.SetServerPort(port);
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetAdmLogin(const char * login)
+{
+nt.SetLogin(login);
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetAdmPassword(const char * password)
+{
+nt.SetPassword(password);
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::GetUser(const char * l)
+{
+char request[255];
+snprintf(request, 255, "<GetUser login=\"%s\"/>", l);
+int ret;
+
+currParser = &parserGetUser;
+((PARSER_GET_USER*)currParser)->SetUserDataRecvCb(RecvGetUserDataCb, getUserDataDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::GetUsers()
+{
+char request[] = "<GetUsers/>";
+int ret;
+
+currParser = &parserGetUsers;
+((PARSER_GET_USERS*)currParser)->SetUserDataRecvCb(RecvUserDataCb, getUsersDataDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::SendMessage(const char * login, const char * message, int prio)
+{
+char request[1000];
+char msg[500];
+Encode12(msg, message, strlen(message));
+snprintf(request, 1000, "<Message login=\"%s\" priority=\"%d\" text=\"%s\"/>", login, prio, msg);
+int ret;
+
+currParser = &parserSendMessage;
+parserSendMessage.SetSendMessageRecvCb(RecvSendMessageCb, sendMessageDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::GetServerInfo()
+{
+char request[] = "<GetServerInfo/>";
+int ret;
+
+currParser = &parserServerInfo;
+((PARSER_GET_SERVER_INFO*)currParser)->SetServerInfoRecvCb(RecvServerInfoDataCb, getServerInfoDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::ChgUser(const char * request)
+{
+int ret;
+
+currParser = &parserChgUser;
+((PARSER_CHG_USER*)currParser)->SetChgUserRecvCb(RecvChgUserCb, chgUserDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    printfd(__FILE__, "Error on connect: '%s'\n", errorMsg);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    printfd(__FILE__, "Error on transact: '%s'\n", errorMsg);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    printfd(__FILE__, "Error on disconnect: '%s'\n", errorMsg);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+//  TODO: remove this shit!
+//-----------------------------------------------------------------------------
+int SERVCONF::MsgUser(const char * request)
+{
+int ret;
+
+currParser = &parserSendMessage;
+parserSendMessage.SetSendMessageRecvCb(RecvSendMessageCb, sendMessageDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::CheckUser(const char * login, const char * password)
+{
+char request[255];
+snprintf(request, 255, "<CheckUser login=\"%s\" password=\"%s\"/>", login, password);
+int ret;
+
+currParser = &parserCheckUser;
+((PARSER_CHECK_USER*)currParser)->SetCheckUserRecvCb(RecvCheckUserCb, checkUserDataCb);
+
+nt.Reset();
+nt.SetRxCallback(this, AnsRecv);
+
+if ((ret = nt.Connect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Transact(request)) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+if ((ret = nt.Disconnect()) != st_ok)
+    {
+    strncpy(errorMsg, nt.GetError(), MAX_ERR_STR_LEN);
+    return ret;
+    }
+
+return st_ok;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::Start(const char *el, const char **attr)
+{
+currParser->ParseStart(el, attr);
+return 0;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::End(const char *el)
+{
+currParser->ParseEnd(el);
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetUserDataRecvCb(RecvUserDataCb_t f, void * data)
+{
+RecvUserDataCb = f;
+getUsersDataDataCb = data;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetGetUserDataRecvCb(RecvUserDataCb_t f, void * data)
+{
+RecvGetUserDataCb = f;            //GET_USER
+getUserDataDataCb = data;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetServerInfoRecvCb(RecvServerInfoDataCb_t f, void * data)
+{
+RecvServerInfoDataCb = f;
+getServerInfoDataCb = data;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetChgUserCb(RecvChgUserCb_t f, void * data)
+{
+RecvChgUserCb = f;
+chgUserDataCb = data;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetCheckUserCb(RecvCheckUserCb_t f, void * data)
+{
+RecvCheckUserCb = f;
+checkUserDataCb = data;
+}
+//-----------------------------------------------------------------------------
+void SERVCONF::SetSendMessageCb(RecvSendMessageCb_t f, void * data)
+{
+RecvSendMessageCb = f;
+sendMessageDataCb = data;
+}
+//-----------------------------------------------------------------------------
+char * SERVCONF::GetStrError()
+{
+return errorMsg;
+}
+//-----------------------------------------------------------------------------
+int SERVCONF::GetError()
+{
+int e = error;
+error = 0;
+return e;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/srvconf.lib/servconf.h b/stglibs/srvconf.lib/servconf.h
new file mode 100644 (file)
index 0000000..f3beaec
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.10 $
+ $Date: 2009/03/17 09:52:35 $
+ $Author: faust $
+ */
+
+#ifndef SERVCONF_H
+#define SERVCONF_H
+
+#include "os_int.h"
+
+#include <expat.h>
+#include <list>
+#include <string>
+#include "netunit.h"
+#include "stg_const.h"
+
+void Start(void *data, const char *el, const char **attr);
+void End(void *data, const char *el);
+
+#define MAX_ERR_STR_LEN (64)
+#define IP_STRING_LEN   (255)
+#define UNAME_LEN       (256)
+#define SERV_VER_LEN    (64)
+#define DIRNAME_LEN     (16)
+
+//-----------------------------------------------------------------------------
+struct STAT
+{
+    long long   su[DIR_NUM];
+    long long   sd[DIR_NUM];
+    long long   mu[DIR_NUM];
+    long long   md[DIR_NUM];
+    double      freeMb;
+};
+//-----------------------------------------------------------------------------
+struct SERVERINFO
+{
+    std::string version;
+    int         tariffNum;
+    int         tariffType;
+    int         usersNum;
+    std::string uname;
+    int         dirNum;
+    std::string dirName[DIR_NUM];
+};
+//-----------------------------------------------------------------------------
+struct USERDATA
+{
+    std::string     login;
+    std::string     password;
+    double          cash;
+    double          credit;
+    double          lastCash;
+    double          prepaidTraff;
+    int             down;
+    int             passive;
+    int             disableDetailStat;
+    int             connected;
+    int             alwaysOnline;
+    uint32_t        ip;
+    std::string     ips;
+    std::string     tariff;
+    std::string     iface;
+    std::string     group;
+    std::string     note;
+    std::string     email;
+    std::string     name;
+    std::string     address;
+    std::string     phone;
+    STAT            stat;
+    std::string     userData[USERDATA_NUM];
+
+    struct USERDATA * next;
+};
+//-----------------------------------------------------------------------------
+typedef void(*RecvUserDataCb_t)(USERDATA * ud, void * data);
+typedef void(*RecvServerInfoDataCb_t)(SERVERINFO * si, void * data);
+typedef int(*RecvChgUserCb_t)(const char * asnwer, void * data);
+typedef int(*RecvCheckUserCb_t)(const char * answer, void * data);
+typedef int(*RecvSendMessageCb_t)(const char * answer, void * data);
+//-----------------------------------------------------------------------------
+struct ADMINDATA
+{
+    char login[ADM_LOGIN_LEN];
+};
+//-----------------------------------------------------------------------------
+class PARSER
+{
+public:
+    PARSER();
+    virtual ~PARSER(){};
+    virtual int ParseStart(const char *el, const char **attr) = 0;
+    virtual void ParseEnd(const char *el) = 0;
+    void    Reset();
+    //virtual bool    GetError() = 0;
+    //virtual void    SetUserDataRecvCb(RecvUserDataCb_t) = 0;
+protected:
+    //RecvUserDataCb_t RecvUserDataCb;
+private:
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHG_USER: public PARSER
+{
+public:
+    PARSER_CHG_USER();
+    int  ParseStart(const char *el, const char **attr);
+    void ParseEnd(const char *el);
+    void Reset();
+    void ParseAnswer(const char *el, const char **attr);
+    void SetChgUserRecvCb(RecvChgUserCb_t, void * data);
+private:
+    RecvChgUserCb_t RecvChgUserCb;
+    void * chgUserCbData;
+    int depth;
+    bool error;
+};
+//-----------------------------------------------------------------------------
+class PARSER_CHECK_USER: public PARSER
+{
+public:
+    PARSER_CHECK_USER();
+    int  ParseStart(const char *el, const char **attr);
+    void ParseEnd(const char *el);
+    void Reset();
+    void ParseAnswer(const char *el, const char **attr);
+    void SetCheckUserRecvCb(RecvCheckUserCb_t, void * data);
+private:
+    RecvCheckUserCb_t RecvCheckUserCb;
+    void * checkUserCbData;
+    int depth;
+    bool error;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_USERS: public PARSER
+{
+public:
+    PARSER_GET_USERS();
+    int  ParseStart(const char *el, const char **attr);
+    void ParseEnd(const char *el);
+    void Reset();
+    void ParseUsers(const char *el, const char **attr);
+    void ParseUser(const char *el, const char **attr);
+    void ParseUserParams(const char *el, const char **attr);
+    void ParseUserLoadStat(const char * el, const char ** attr);
+    //bool GetError();
+    void SetUserDataRecvCb(RecvUserDataCb_t, void * data);
+private:
+    RecvUserDataCb_t RecvUserDataCb;
+    void * userDataCb;
+    USERDATA user;
+    int depth;
+    bool error;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_USER: public PARSER
+{
+public:
+    PARSER_GET_USER();
+    int  ParseStart(const char *el, const char **attr);
+    void ParseEnd(const char *el);
+    void Reset();
+    void ParseUsers(const char *el, const char **attr);
+    void ParseUser(const char *el, const char **attr);
+    void ParseUserParams(const char *el, const char **attr);
+    void ParseUserLoadStat(const char * el, const char ** attr);
+    void SetUserDataRecvCb(RecvUserDataCb_t, void * data);
+private:
+    RecvUserDataCb_t RecvUserDataCb;
+    void * userDataCb;
+    USERDATA user;
+    int depth;
+    bool error;
+};
+//-----------------------------------------------------------------------------
+class PARSER_GET_SERVER_INFO: public PARSER
+{
+public:
+    PARSER_GET_SERVER_INFO();
+    int  ParseStart(const char *el, const char **attr);
+    void ParseEnd(const char *el);
+    void Reset();
+    void ParseServerInfo(const char *el, const char **attr);
+    bool GetError();
+    void SetServerInfoRecvCb(RecvServerInfoDataCb_t, void * data);
+private:
+    void ParseUname(const char ** attr);
+    void ParseServerVersion(const char ** attr);
+    void ParseUsersNum(const char ** attr);
+    void ParseTariffsNum(const char ** attr);
+    void ParseTariffType(const char ** attr);
+    void ParseDirNum(const char **attr);
+    void ParseDirName(const char **attr, int d);
+
+    RecvServerInfoDataCb_t RecvServerInfoDataCb;
+    void * serverInfoDataCb;
+    USERDATA user;
+    int depth;
+    bool error;
+    SERVERINFO serverInfo;
+};
+//-----------------------------------------------------------------------------
+class PARSER_SEND_MESSAGE: public PARSER
+{
+public:
+    PARSER_SEND_MESSAGE();
+    int  ParseStart(const char *el, const char **attr);
+    void ParseEnd(const char *el);
+    void Reset();
+    void ParseAnswer(const char *el, const char **attr);
+    void SetSendMessageRecvCb(RecvSendMessageCb_t, void * data);
+private:
+    RecvSendMessageCb_t RecvSendMessageCb;
+    void * sendMessageCbData;
+    int depth;
+    bool error;
+};
+//-----------------------------------------------------------------------------
+class SERVCONF
+{
+public:
+    SERVCONF();
+    void SetServer(const char * server);
+    void SetPort(uint16_t port);
+
+    void SetAdmLogin(const char * login);
+    void SetAdmPassword(const char * password);
+
+    void SetUserDataRecvCb(RecvUserDataCb_t, void * data);
+    void SetServerInfoRecvCb(RecvServerInfoDataCb_t, void * data);
+    void SetChgUserCb(RecvChgUserCb_t, void * data);
+    void SetCheckUserCb(RecvCheckUserCb_t, void * data);
+    void SetGetUserDataRecvCb(RecvUserDataCb_t, void * data);
+    void SetSendMessageCb(RecvSendMessageCb_t, void * data);
+
+    int GetUsers();
+    int GetUser(const char * login);
+    int ChgUser(const char * request);
+    // TODO: Remove this shit!
+    int MsgUser(const char * request);
+    int SendMessage(const char * login, const char * message, int prio);
+    int GetServerInfo();
+    int CheckUser(const char * login, const char * password);
+
+    char * GetStrError();
+    int  GetError();
+    int Start(const char *el, const char **attr);
+    void End(const char *el);
+
+private:
+    PARSER * currParser;
+
+    PARSER_GET_USERS parserGetUsers;
+    PARSER_GET_USER parserGetUser;
+    PARSER_GET_SERVER_INFO  parserServerInfo;
+    PARSER_CHG_USER parserChgUser;
+    PARSER_CHECK_USER parserCheckUser;
+    PARSER_SEND_MESSAGE parserSendMessage;
+
+    NETTRANSACT nt;
+    int parseDepth;
+    USERDATA ud;
+
+    char    errorMsg[MAX_ERR_STR_LEN];
+    int     error;
+    XML_Parser      parser;
+
+    RecvUserDataCb_t RecvUserDataCb;
+    RecvUserDataCb_t RecvGetUserDataCb;
+    RecvServerInfoDataCb_t RecvServerInfoDataCb;
+    RecvChgUserCb_t RecvChgUserCb;
+    RecvCheckUserCb_t RecvCheckUserCb;
+    RecvSendMessageCb_t RecvSendMessageCb;
+
+    void * getUserDataDataCb;
+    void * getUsersDataDataCb;
+    void * getServerInfoDataCb;
+    void * chgUserDataCb;
+    void * checkUserDataCb;
+    void * sendMessageDataCb;
+
+    friend int AnsRecv(void * data, std::list<std::string> * list);
+};
+//-----------------------------------------------------------------------------
+
+#endif  /* _SERVCONF_H_ */
+
+/* EOF */
+
diff --git a/stglibs/srvconf.lib/servconf.vpj b/stglibs/srvconf.lib/servconf.vpj
new file mode 100644 (file)
index 0000000..c5f9b3c
--- /dev/null
@@ -0,0 +1,191 @@
+<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
+<Project
+       Version="10.0"
+       VendorName="SlickEdit"
+       WorkingDir="."
+       BuildSystem="automakefile"
+       BuildMakeFile="makefile">
+       <Config
+               Name="Debug"
+               Type="gnuc"
+               DebugCallbackName="gdb"
+               OutputFile="%bdservconf.a">
+               <Menu>
+                       <Target
+                               Name="Compile"
+                               MenuCaption="&amp;Compile"
+                               OutputExts="*.o"
+                               Dialog="_gnuc_options_form Compile"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ -c %xup -pipe -g -Wall -ggdb -o "%bd%n%oe" %i "%f"'/>
+                       </Target>
+                       <Target
+                               Name="Link"
+                               MenuCaption="&amp;Link"
+                               ShowOnMenu="Never"
+                               Dialog="_gnuc_options_form Link"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ %xup -pipe -g -Wall -o "%o" %f %libs'/>
+                       </Target>
+                       <Target
+                               Name="Build"
+                               MenuCaption="&amp;Build"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveWorkspaceFiles"
+                               Deletable="0">
+                               <Exec CmdLine="gmake -fMakefile"/>
+                       </Target>
+                       <Target
+                               Name="Rebuild"
+                               MenuCaption="&amp;Rebuild"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="Debug"
+                               MenuCaption="&amp;Debug"
+                               RunFromDir="%rw"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="Execute"
+                               MenuCaption="E&amp;xecute"
+                               RunFromDir="%rw"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="dash"
+                               MenuCaption="-"
+                               RunFromDir="%rw">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="GNU C Options"
+                               MenuCaption="GNU C &amp;Options..."
+                               ShowOnMenu="HideIfNoCmdLine"
+                               Deletable="0">
+                               <Exec
+                                       CmdLine="gnucoptions"
+                                       Type="Slick-C"/>
+                       </Target>
+               </Menu>
+               <Libs>
+                       <Lib File="/usr/lib/libexpat.a"/>
+               </Libs>
+       </Config>
+       <Config
+               Name="Release"
+               Type="gnuc"
+               DebugCallbackName="gdb"
+               OutputFile="%bdservconf.a">
+               <Menu>
+                       <Target
+                               Name="Compile"
+                               MenuCaption="&amp;Compile"
+                               OutputExts="*.o"
+                               Dialog="_gnuc_options_form Compile"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ -c %xup -pipe -Wall -o "%bd%n%oe" %i "%f"'/>
+                       </Target>
+                       <Target
+                               Name="Link"
+                               MenuCaption="&amp;Link"
+                               ShowOnMenu="Never"
+                               Dialog="_gnuc_options_form Link"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveCurrent"
+                               Deletable="0">
+                               <Exec CmdLine='g++ %xup -pipe -Wall -o "%o" %f %libs'/>
+                       </Target>
+                       <Target
+                               Name="Build"
+                               MenuCaption="&amp;Build"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               SaveOption="SaveWorkspaceFiles"
+                               Deletable="0">
+                               <Exec CmdLine="gmake -fMakefile"/>
+                       </Target>
+                       <Target
+                               Name="Rebuild"
+                               MenuCaption="&amp;Rebuild"
+                               RunFromDir="%rw"
+                               CaptureOutputWith="ProcessBuffer"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="Debug"
+                               MenuCaption="&amp;Debug"
+                               RunFromDir="%rw"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="Execute"
+                               MenuCaption="E&amp;xecute"
+                               RunFromDir="%rw"
+                               Deletable="0">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="dash"
+                               MenuCaption="-"
+                               RunFromDir="%rw">
+                               <Exec/>
+                       </Target>
+                       <Target
+                               Name="GNU C Options"
+                               MenuCaption="GNU C &amp;Options..."
+                               ShowOnMenu="HideIfNoCmdLine"
+                               Deletable="0">
+                               <Exec
+                                       CmdLine="gnucoptions"
+                                       Type="Slick-C"/>
+                       </Target>
+               </Menu>
+               <Libs>
+                       <Lib File="/usr/lib/libexpat.a"/>
+               </Libs>
+       </Config>
+       <Files>
+               <Folder
+                       Name="Source Files"
+                       Filters="*.c;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl">
+                       <F N="netunit.cpp"/>
+                       <F N="parser.cpp"/>
+                       <F N="servconf.cpp"/>
+                       <F N="test.cpp"/>
+               </Folder>
+               <Folder
+                       Name="Header Files"
+                       Filters="*.h;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
+                       <F N="netunit.h"/>
+                       <F N="servconf.h"/>
+               </Folder>
+               <Folder
+                       Name="Resource Files"
+                       Filters="*.ico;*.cur;*.dlg"/>
+               <Folder
+                       Name="Bitmaps"
+                       Filters="*.bmp;*.xpm;*.xbm"/>
+               <Folder
+                       Name="Other Files"
+                       Filters=""/>
+       </Files>
+</Project>
diff --git a/stglibs/srvconf.lib/servconf.vpw b/stglibs/srvconf.lib/servconf.vpw
new file mode 100644 (file)
index 0000000..96ebe79
--- /dev/null
@@ -0,0 +1,4 @@
+[Global]
+Version=8
+[ProjectFiles]
+servconf.vpj
diff --git a/stglibs/srvconf.lib/test.cpp b/stglibs/srvconf.lib/test.cpp
new file mode 100644 (file)
index 0000000..092ffce
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+ /*
+ $Revision: 1.6 $
+ $Date: 2008/02/09 16:22:18 $
+ $Author: nobunaga $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "servconf.h"
+
+//-----------------------------------------------------------------------------
+void RecvUserData(USERDATA * ud, void * d)
+{
+// ôÕÔ ×Ù×ÏÄÉÔÓÑ ÞÁÓÔØ ÉÎÆÙ Ï ÐÏÌØÚÏ×ÁÔÅÌÅ, ÎÏ × ud ÐÅÒÅÄÁÅÔÓÑ ×ÓÑ ÉÎÆÁ
+printf("login: %s password :%s cash:%8.2f   ip:%16s\n", ud->login, ud->password, ud->cash, ud->ips);
+}
+//-----------------------------------------------------------------------------
+void RecvServerInfoData(SERVERINFO * si, void * d)
+{
+// ôÕÔ ÔÏÖÅ ÔÏÌØËÏ ÞÁÓÔØ ÉÎÆÙ ×Ù×ÏÄÉÔÓÑ ÎÁ ÜËÒÁÎ
+printf("uname:   %20s\n", si->uname);
+printf("version: %20s\n", si->version);
+printf("users:   %20d\n", si->usersNum);
+for (int i = 0; i < DIR_NUM; i++)
+    {
+    printf("dir name 1:   >%16s<\n", si->dirName[i]);
+    }
+}
+//-----------------------------------------------------------------------------
+int RecvSetUserAnswer(const char * ans, void * d)
+{
+printf("ans=%s\n", ans);
+if (strcasecmp("Ok", ans) == 0)
+    *((bool*)d) = true;
+else
+    *((bool*)d) = false;
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RecvCheckUserAnswer(const char * ans, void * d)
+{
+if (strcmp("Ok", ans) == 0)
+    *((bool*)d) = true;
+else
+    *((bool*)d) = false;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int RecvSendMessageAnswer(const char * ans, void * d)
+{
+if (strcasecmp("Ok", ans) == 0)
+    *((bool*)d) = true;
+else
+    *((bool*)d) = false;
+return 0;
+}
+//-----------------------------------------------------------------------------
+int main()
+{
+SERVCONF sc;
+int ret;
+bool userExist = false;
+bool result = false;
+
+sc.SetServer("127.0.0.1");  // õÓÔÁÎÁ×ÌÉ×ÁÅÍ ÉÍÑ ÓÅÒ×ÅÒÁ Ó ËÏÔÏÒÇÏ ÚÁÂÉÒÁÔØ ÉÎÆÕ
+sc.SetPort(5555);           // ÁÄÍÉÎÓËÉÊ ÐÏÒÔ ÓÅÒ×ÅÒÁÐÏÒÔ
+sc.SetAdmLogin("admin");    // ÷ÙÓÔÁ×ÌÑÅÍ ÌÏÇÉΠɠÐÁÒÏÌØ ÁÄÍÉÎÁ
+sc.SetAdmPassword("123456");
+
+sc.SetUserDataRecvCb(RecvUserData, NULL);          // óÔÁ×ÉÍ ËÏÌÂÜË-ÆÕÎËÃÉÉ, ËÏÔÏÒÙÅ
+sc.SetGetUserDataRecvCb(RecvUserData, NULL);          // GET USER
+sc.SetServerInfoRecvCb(RecvServerInfoData, NULL);  // ÂÕÄÕÔ ×ÙÚ×ÁÎÙ ÐÒÉ ÐÏÌÕÞÅÎÉÉ ÉÎÆÏÒÍÁÃÉÉ Ó ÓÅÒ×ÅÒÁ
+sc.SetChgUserCb(RecvSetUserAnswer, &userExist);
+sc.SetCheckUserCb(RecvCheckUserAnswer, &userExist);
+sc.SetSendMessageCb(RecvSendMessageAnswer, &result);
+printf("--------------- GetServerInfo ---------------\n");
+ret = sc.GetServerInfo();       // úÁÐÒÁÛÉ×ÁÅÍ ÉÎÆÕ Ï ÓÅÒ×ÅÒÅ. üÔÏ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ
+if (ret != st_ok)               // ÄÌÑ ÐÒÏ×ÅÒËÉ ÌÏÇÉÎÁ É ÐÁÒÏÌÑ ÁÄÍÉÎÁ
+    {
+    printf("error %d %s\n", ret, sc.GetStrError());
+    return 0;
+    }
+
+/*printf("--------------- GetUsers ---------------\n");
+ret = sc.GetUsers();            // úÁÐÒÁÛÉ×ÁÅÍ ÉÎÆÕ Ï ÐÏÌØÚÏ×ÁÔÅÌÅ
+if (ret != st_ok)
+    {
+    printf("error %d %s\n", ret, sc.GetStrError());
+    return 0;
+    }*/
+
+printf("--------------- SendMessage ---------------\n");
+ret = sc.SendMessage("zubr11", "test", 0);            //
+if (ret != st_ok)
+    {
+    printf("error %d %s\n", ret, sc.GetStrError());
+    return 0;
+    }
+if (result)
+    printf("SendMessage ok\n");
+else
+    printf("SendMessage failed\n");
+
+return 0;
+
+printf("--------------- GetUser ---------------\n");
+ret = sc.GetUser("test");            // úÁÐÒÁÛÉ×ÁÅÍ ÉÎÆÕ Ï ÐÏÌØÚÏ×ÁÔÅÌÅ
+if (ret != st_ok)
+    {
+    printf("error %d %s\n", ret, sc.GetStrError());
+    return 0;
+    }
+
+return 0;
+
+printf("--------------- CheckUser ---------------\n");
+sc.CheckUser("test", "123456");
+if (userExist)
+    printf("login - ok\n");
+else
+    printf("login failed\n");
+
+printf("--------------- ChgUser ON ---------------\n");
+char req[1024];
+sprintf(req, "<SetUser> "
+        "<login value=\"test\"/> "
+        "<ips value=\"192.168.111.100\"/> "
+        "<aonline value=\"1\"/> "
+        "<iface value=\"ppp0\"/></SetUser>");
+sc.ChgUser(req);
+if (userExist)
+    printf("chg user ok\n");
+else
+    printf("chg user error\n");
+
+printf("--------------- ChgUser OFF ---------------\n");
+sprintf(req, "<SetUser> "
+        "<login value=\"test\"/> "
+        "<aonline value=\"0\"/> </SetUser>");
+
+sc.ChgUser(req);
+if (userExist)
+    printf("chg user ok\n");
+else
+    printf("chg user error\n");
+
+return 0;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/stglibs/srvconf.lib/test.sh b/stglibs/srvconf.lib/test.sh
new file mode 100755 (executable)
index 0000000..95b9913
--- /dev/null
@@ -0,0 +1 @@
+gcc -g3 test.cpp -L../../lib ./libsrvconf.a -lexpat ../../lib/libstg_common.so ../../lib/libstg_crypto.so -I../../include
diff --git a/stglibs/stg_locker.lib/Makefile b/stglibs/stg_locker.lib/Makefile
new file mode 100644 (file)
index 0000000..5f99d5c
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# $Id: Makefile,v 1.2 2008/12/04 17:11:55 faust Exp $
+###############################################################################
+
+LIB_NAME = stg_locker
+PROG = lib$(LIB_NAME)
+
+SRCS = stg_locker.cpp
+
+INCS = stg_locker.h
+
+LIBS=$(LIB_THREAD)
+
+include ../Makefile.in
diff --git a/stglibs/stg_locker.lib/stg_locker.cpp b/stglibs/stg_locker.lib/stg_locker.cpp
new file mode 100644 (file)
index 0000000..be0aa00
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.2 $
+ $Date: 2007/11/30 08:57:49 $
+ $Author: nobunaga $
+*/
+
+
+
+#include <pthread.h>
+#include "stg_locker.h"
+
+#ifdef DEBUG_LOCKER
+
+long long STG_LOCKER::id = 0;
+pthread_mutex_t STG_LOCKER::lockerMutex = PTHREAD_MUTEX_INITIALIZER;
+
+#endif
+
diff --git a/stglibs/stg_locker.lib/stg_locker.h b/stglibs/stg_locker.lib/stg_locker.h
new file mode 100644 (file)
index 0000000..6583368
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
+ */
+
+/*
+ $Revision: 1.5 $
+ $Date: 2010/03/04 11:57:11 $
+ $Author: faust $
+*/
+
+
+#ifndef STG_LOCKER_H
+#define STG_LOCKER_H
+
+#include <pthread.h>
+#include "noncopyable.h"
+
+#ifdef DEBUG_LOCKER
+
+#include <iostream>
+#include <string>
+#include <pthread.h>
+
+#endif
+//-----------------------------------------------------------------------------
+class STG_LOCKER : private NONCOPYABLE
+{
+public:
+    #ifdef DEBUG_LOCKER
+    STG_LOCKER(pthread_mutex_t * m, const char * __file__, int __line__)
+        : mutex(m),
+          file(__file__),
+          line(__line__),
+          lockID(0)
+    #else
+    STG_LOCKER(pthread_mutex_t * m, const char *, int)
+        : mutex(m)
+    #endif
+        {
+        mutex = m;
+        #ifdef DEBUG_LOCKER
+        pthread_mutex_lock(&lockerMutex);
+        file = __file__;
+        line = __line__;
+        if (id == 0)
+            pthread_mutex_init(&lockerMutex, NULL);
+
+        lockID = ++id;
+        std::cout << "Lock: " << lockID << " " << file << ":" << line << " " << mutex << " " << pthread_self() << std::endl;
+        pthread_mutex_unlock(&lockerMutex);
+        #endif
+        pthread_mutex_lock(mutex);
+        };
+
+    ~STG_LOCKER()
+        {
+        pthread_mutex_unlock(mutex);
+        #ifdef DEBUG_LOCKER
+        pthread_mutex_lock(&lockerMutex);
+        std::cout << "Unlock: " << lockID << " " << file << ":" << line << " " << mutex << " " << pthread_self() << std::endl;
+        pthread_mutex_unlock(&lockerMutex);
+        #endif
+        };
+private:
+    pthread_mutex_t * mutex;
+    #ifdef DEBUG_LOCKER
+    std::string file;
+    int line;
+    static pthread_mutex_t lockerMutex;
+    static long long id;
+    long long lockID;
+    #endif
+};
+//-----------------------------------------------------------------------------
+
+#endif //STG_LOCKER_H
diff --git a/stglibs/stg_logger.lib/Makefile b/stglibs/stg_logger.lib/Makefile
new file mode 100644 (file)
index 0000000..e19b892
--- /dev/null
@@ -0,0 +1,12 @@
+###############################################################################
+# $Id: Makefile,v 1.3 2007/05/08 14:29:21 faust Exp $
+###############################################################################
+
+LIB_NAME = stg_logger
+PROG = lib$(LIB_NAME)
+
+SRCS = stg_logger.cpp
+
+INCS = stg_logger.h
+
+include ../Makefile.in
diff --git a/stglibs/stg_logger.lib/stg_logger.cpp b/stglibs/stg_logger.lib/stg_logger.cpp
new file mode 100644 (file)
index 0000000..cb96e50
--- /dev/null
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include "stg_logger.h"
+
+#ifdef STG_TIME
+extern const volatile time_t stgTime;
+#endif
+//-----------------------------------------------------------------------------
+STG_LOGGER & GetStgLogger()
+{
+static STG_LOGGER logger;
+return logger;
+}
+//-----------------------------------------------------------------------------
+STG_LOGGER::STG_LOGGER()
+    : fileName()
+{
+pthread_mutex_init(&mutex, NULL);
+}
+//-----------------------------------------------------------------------------
+STG_LOGGER::~STG_LOGGER()
+{
+pthread_mutex_destroy(&mutex);
+}
+//-----------------------------------------------------------------------------
+void STG_LOGGER::SetLogFileName(const std::string & fn)
+{
+STG_LOGGER_LOCKER lock(&mutex);
+fileName = fn;
+}
+//-----------------------------------------------------------------------------
+void STG_LOGGER::operator()(const char * fmt, ...)
+{
+STG_LOGGER_LOCKER lock(&mutex);
+
+char buff[2048];
+
+va_list vl;
+va_start(vl, fmt);
+vsnprintf(buff, sizeof(buff), fmt, vl);
+va_end(vl);
+
+FILE * f;
+if (!fileName.empty())
+    {
+    f = fopen(fileName.c_str(), "at");
+    if (f)
+        {
+        #ifdef STG_TIME
+        fprintf(f, "%s", LogDate(stgTime));
+        #else
+        fprintf(f, "%s", LogDate(time(NULL)));
+        #endif
+        fprintf(f, " -- ");
+        fprintf(f, "%s", buff);
+        fprintf(f, "\n");
+        fclose(f);
+        }
+    else
+        {
+        openlog("stg", LOG_NDELAY, LOG_USER);
+        syslog(LOG_CRIT, "%s", buff);
+        closelog();
+        }
+    }
+else
+    {
+    openlog("stg", LOG_NDELAY, LOG_USER);
+    syslog(LOG_CRIT, "%s", buff);
+    closelog();
+    }
+}
+//-----------------------------------------------------------------------------
+const char * STG_LOGGER::LogDate(time_t t)
+{
+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;
+}
+//-----------------------------------------------------------------------------
diff --git a/stglibs/stg_logger.lib/stg_logger.h b/stglibs/stg_logger.lib/stg_logger.h
new file mode 100644 (file)
index 0000000..3f9eed0
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef STG_LOGGER_H
+#define STG_LOGGER_H
+
+#include <pthread.h>
+#include <string>
+#include "noncopyable.h"
+
+const char * LogDate(time_t t);
+//-----------------------------------------------------------------------------
+class STG_LOGGER;
+STG_LOGGER & GetStgLogger();
+//-----------------------------------------------------------------------------
+class STG_LOGGER_LOCKER : private NONCOPYABLE
+{
+public:
+    STG_LOGGER_LOCKER(pthread_mutex_t * m) : mutex(m) { pthread_mutex_lock(mutex); };
+    ~STG_LOGGER_LOCKER() { pthread_mutex_unlock(mutex); };
+private:
+    pthread_mutex_t * mutex;
+};
+//-----------------------------------------------------------------------------
+class STG_LOGGER
+{
+friend STG_LOGGER & GetStgLogger();
+
+public:
+    ~STG_LOGGER();
+    void SetLogFileName(const std::string & fn);
+    void operator()(const char * fmt, ...);
+
+private:
+    STG_LOGGER();
+    const char * LogDate(time_t t);
+
+    std::string fileName;
+    pthread_mutex_t mutex;
+};
+//-----------------------------------------------------------------------------
+
+#endif //STG_LOGGER_H