]> git.stg.codes - stg.git/blobdiff - projects/stargazer/plugins/store/mysql/mysql_store.cpp
MySQL custom port implemented
[stg.git] / projects / stargazer / plugins / store / mysql / mysql_store.cpp
index b4ac87155a762d5510d4700f624decf959956fd2..48be4aa6b37ad952950c8b6f14d2d022e1d9918e 100644 (file)
@@ -7,11 +7,13 @@
 #include <mysql.h>
 #include <errmsg.h>
 
 #include <mysql.h>
 #include <errmsg.h>
 
+#include "stg/common.h"
 #include "stg/user_ips.h"
 #include "stg/user_conf.h"
 #include "stg/user_stat.h"
 #include "stg/blowfish.h"
 #include "stg/plugin_creator.h"
 #include "stg/user_ips.h"
 #include "stg/user_conf.h"
 #include "stg/user_stat.h"
 #include "stg/blowfish.h"
 #include "stg/plugin_creator.h"
+#include "stg/logger.h"
 #include "mysql_store.h"
 
 #define adm_enc_passwd "cjeifY8m3"
 #include "mysql_store.h"
 
 #define adm_enc_passwd "cjeifY8m3"
@@ -29,10 +31,10 @@ template <typename T>
 int GetInt(const std::string & str, T * val, T defaultVal = T())
 {
     char *res;
 int GetInt(const std::string & str, T * val, T defaultVal = T())
 {
     char *res;
-    
+
     *val = static_cast<T>(strtoll(str.c_str(), &res, 10));
     *val = static_cast<T>(strtoll(str.c_str(), &res, 10));
-    
-    if (*res != 0) 
+
+    if (*res != 0)
     {
         *val = defaultVal; //Error!
         return EINVAL;
     {
         *val = defaultVal; //Error!
         return EINVAL;
@@ -44,10 +46,10 @@ int GetInt(const std::string & str, T * val, T defaultVal = T())
 int GetDouble(const std::string & str, double * val, double defaultVal)
 {
     char *res;
 int GetDouble(const std::string & str, double * val, double defaultVal)
 {
     char *res;
-    
+
     *val = strtod(str.c_str(), &res);
     *val = strtod(str.c_str(), &res);
-    
-    if (*res != 0) 
+
+    if (*res != 0)
     {
         *val = defaultVal; //Error!
         return EINVAL;
     {
         *val = defaultVal; //Error!
         return EINVAL;
@@ -59,10 +61,10 @@ int GetDouble(const std::string & str, double * val, double defaultVal)
 int GetTime(const std::string & str, time_t * val, time_t defaultVal)
 {
     char *res;
 int GetTime(const std::string & str, time_t * val, time_t defaultVal)
 {
     char *res;
-    
+
     *val = strtol(str.c_str(), &res, 10);
     *val = strtol(str.c_str(), &res, 10);
-    
-    if (*res != 0) 
+
+    if (*res != 0)
     {
         *val = defaultVal; //Error!
         return EINVAL;
     {
         *val = defaultVal; //Error!
         return EINVAL;
@@ -72,7 +74,7 @@ int GetTime(const std::string & str, time_t * val, time_t defaultVal)
 }
 
 //-----------------------------------------------------------------------------
 }
 
 //-----------------------------------------------------------------------------
-std::string ReplaceStr(std::string source, const std::string symlist, const char chgsym)
+std::string ReplaceStr(std::string source, const std::string symlist, const char chgsym)
 {
     std::string::size_type pos=0;
 
 {
     std::string::size_type pos=0;
 
@@ -85,17 +87,17 @@ std::string ReplaceStr(std::string source, const std::string symlist, const char
 int GetULongLongInt(const std::string & str, uint64_t * val, uint64_t defaultVal)
 {
     char *res;
 int GetULongLongInt(const std::string & str, uint64_t * val, uint64_t defaultVal)
 {
     char *res;
-    
+
     *val = strtoull(str.c_str(), &res, 10);
     *val = strtoull(str.c_str(), &res, 10);
-    
-    if (*res != 0) 
+
+    if (*res != 0)
     {
         *val = defaultVal; //Error!
         return EINVAL;
     }
 
     return 0;
     {
         *val = defaultVal; //Error!
         return EINVAL;
     }
 
     return 0;
-} 
+}
 
 PLUGIN_CREATOR<MYSQL_STORE> msc;
 }
 
 PLUGIN_CREATOR<MYSQL_STORE> msc;
 }
@@ -110,28 +112,24 @@ return msc.GetPlugin();
 }
 //-----------------------------------------------------------------------------
 MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
 }
 //-----------------------------------------------------------------------------
 MYSQL_STORE_SETTINGS::MYSQL_STORE_SETTINGS()
-    : settings(NULL),
-      errorStr(),
-      dbUser(),
-      dbPass(),
-      dbName(),
-      dbHost()
+    : settings(NULL)
+    , dbPort(0)
 {
 }
 //-----------------------------------------------------------------------------
 {
 }
 //-----------------------------------------------------------------------------
-int MYSQL_STORE_SETTINGS::ParseParam(const std::vector<PARAM_VALUE> & moduleParams, 
-                        const std::string & name, std::string & result)
+int MYSQL_STORE_SETTINGS::ParseParam(const std::vector<PARAM_VALUE> & moduleParams,
+                                     const std::string & name, std::string & result)
 {
 PARAM_VALUE pv;
 pv.param = name;
 std::vector<PARAM_VALUE>::const_iterator pvi;
 pvi = find(moduleParams.begin(), moduleParams.end(), pv);
 {
 PARAM_VALUE pv;
 pv.param = name;
 std::vector<PARAM_VALUE>::const_iterator pvi;
 pvi = find(moduleParams.begin(), moduleParams.end(), pv);
-if (pvi == moduleParams.end())
+if (pvi == moduleParams.end() || pvi->value.empty())
     {
     errorStr = "Parameter \'" + name + "\' not found.";
     return -1;
     }
     {
     errorStr = "Parameter \'" + name + "\' not found.";
     return -1;
     }
-    
+
 result = pvi->value[0];
 
 return 0;
 result = pvi->value[0];
 
 return 0;
@@ -152,16 +150,25 @@ if (ParseParam(s.moduleParams, "server", dbHost) < 0 &&
     ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
     return -1;
 
     ParseParam(s.moduleParams, "dbhost", dbHost) < 0)
     return -1;
 
+std::string dbPortAsString;
+if (ParseParam(s.moduleParams, "port", dbPortAsString) == 0 ||
+    ParseParam(s.moduleParams, "dbport", dbPortAsString) == 0)
+{
+    if (GetInt<unsigned int>(dbPortAsString, &dbPort, 0) != 0)
+    {
+        errorStr = "Can't parse db port from string: \"" + dbPortAsString + "\"\n";
+        return -1;
+    }
+}
+
 return 0;
 }
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 MYSQL_STORE::MYSQL_STORE()
 return 0;
 }
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 MYSQL_STORE::MYSQL_STORE()
-    : errorStr(),
-      version("mysql_store v.0.67"),
-      storeSettings(),
-      settings(),
+    : version("mysql_store v.0.67"),
+      schemaVersion(0),
       logger(GetPluginLogger(GetStgLogger(), "store_mysql"))
 {
 }
       logger(GetPluginLogger(GetStgLogger(), "store_mysql"))
 {
 }
@@ -180,7 +187,7 @@ int    MYSQL_STORE::MysqlQuery(const char* sQuery,MYSQL * sock) const
                 return 0;
         }
     }
                 return 0;
         }
     }
-    
+
     return ret;
 }
 //-----------------------------------------------------------------------------
     return ret;
 }
 //-----------------------------------------------------------------------------
@@ -190,7 +197,6 @@ int MYSQL_STORE::ParseSettings()
 {
 int ret = storeSettings.ParseSettings(settings);
 MYSQL mysql;
 {
 int ret = storeSettings.ParseSettings(settings);
 MYSQL mysql;
-MYSQL * sock;
 mysql_init(&mysql);
 if (ret)
     errorStr = storeSettings.GetStrError();
 mysql_init(&mysql);
 if (ret)
     errorStr = storeSettings.GetStrError();
@@ -201,10 +207,10 @@ else
         errorStr = "Database password must be not empty. Please read Manual.";
         return -1;
     }
         errorStr = "Database password must be not empty. Please read Manual.";
         return -1;
     }
-    
+    MYSQL * sock;
     if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
     if (!(sock = mysql_real_connect(&mysql,storeSettings.GetDBHost().c_str(),
             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
-            0,0,NULL,0)))
+            0,storeSettings.GetDBPort(),NULL,0)))
         {
             errorStr = "Couldn't connect to mysql engine! With error:\n";
             errorStr += mysql_error(&mysql);
         {
             errorStr = "Couldn't connect to mysql engine! With error:\n";
             errorStr += mysql_error(&mysql);
@@ -216,7 +222,7 @@ else
          if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
          {
              std::string res = "CREATE DATABASE " + storeSettings.GetDBName();
          if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
          {
              std::string res = "CREATE DATABASE " + storeSettings.GetDBName();
-            
+
             if(MysqlQuery(res.c_str(),sock))
             {
                 errorStr = "Couldn't create database! With error:\n";
             if(MysqlQuery(res.c_str(),sock))
             {
                 errorStr = "Couldn't create database! With error:\n";
@@ -228,19 +234,26 @@ else
             {
                  if(mysql_select_db(sock, storeSettings.GetDBName().c_str()))
                  {
             {
                  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;
+                     errorStr = "Couldn't select database! With error:\n";
+                     errorStr += mysql_error(sock);
+                     mysql_close(sock);
+                     ret = -1;
                  }
                  }
-                 ret = CheckAllTables(sock);
+                 else
+                     ret = CheckAllTables(sock);
             }
             }
-         }
-         else
-             ret = CheckAllTables(sock);
-         mysql_close(sock);
+        }
+        else
+        {
+            ret = CheckAllTables(sock);
+        }
+        if (!ret)
+        {
+            logger("MYSQL_STORE: Current DB schema version: %d", schemaVersion);
+            MakeUpdates(sock);
+        }
+        mysql_close(sock);
     }
     }
-    
 }
 return ret;
 }
 }
 return ret;
 }
@@ -267,6 +280,43 @@ return num_rows == 1;
 //-----------------------------------------------------------------------------
 int MYSQL_STORE::CheckAllTables(MYSQL * sock)
 {
 //-----------------------------------------------------------------------------
 int MYSQL_STORE::CheckAllTables(MYSQL * sock)
 {
+//info-------------------------------------------------------------------------
+if(!IsTablePresent("info",sock))
+{
+    sprintf(qbuf,"CREATE TABLE info (version INTEGER NOT NULL)");
+
+    if(MysqlQuery(qbuf,sock))
+        {
+        errorStr = "Couldn't create info table With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+
+    sprintf(qbuf,"INSERT INTO info SET version=0");
+
+    if(MysqlQuery(qbuf,sock))
+        {
+        errorStr = "Couldn't write default version. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    schemaVersion = 0;
+}
+else
+{
+    std::vector<std::string> info;
+    if (GetAllParams(&info, "info", "version"))
+        schemaVersion = 0;
+    else
+    {
+        if (info.empty())
+            schemaVersion = 0;
+        else
+            GetInt(info.front(), &schemaVersion, 0);
+    }
+}
 //admins-----------------------------------------------------------------------
 if(!IsTablePresent("admins",sock))
 {
 //admins-----------------------------------------------------------------------
 if(!IsTablePresent("admins",sock))
 {
@@ -275,7 +325,7 @@ if(!IsTablePresent("admins",sock))
         "ChgPassword TINYINT DEFAULT 0,ChgStat TINYINT DEFAULT 0,"\
         "ChgCash TINYINT DEFAULT 0,UsrAddDel TINYINT DEFAULT 0,"\
         "ChgTariff TINYINT DEFAULT 0,ChgAdmin 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";
     if(MysqlQuery(qbuf,sock))
     {
         errorStr = "Couldn't create admin table list With error:\n";
@@ -287,7 +337,7 @@ if(!IsTablePresent("admins",sock))
     sprintf(qbuf,"INSERT INTO admins SET login='admin',"\
         "password='geahonjehjfofnhammefahbbbfbmpkmkmmefahbbbfbmpkmkmmefahbbbfbmpkmkaa',"\
         "ChgConf=1,ChgPassword=1,ChgStat=1,ChgCash=1,UsrAddDel=1,ChgTariff=1,ChgAdmin=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";
     if(MysqlQuery(qbuf,sock))
     {
         errorStr = "Couldn't create default admin. With error:\n";
@@ -302,37 +352,40 @@ std::string param, res;
 if(!IsTablePresent("tariffs",sock))
 {
     res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
 if(!IsTablePresent("tariffs",sock))
 {
     res = "CREATE TABLE tariffs (name VARCHAR(40) DEFAULT '' PRIMARY KEY,";
-        
+
     for (int i = 0; i < DIR_NUM; i++)
         {
     for (int i = 0; i < DIR_NUM; i++)
         {
-        strprintf(&param, " PriceDayA%d DOUBLE DEFAULT 0.0,", i); 
+        strprintf(&param, " PriceDayA%d DOUBLE DEFAULT 0.0,", i);
         res += param;
         res += param;
-    
+
         strprintf(&param, " PriceDayB%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, " PriceNightA%d DOUBLE DEFAULT 0.0,", i);
         res += param;
-    
+
         strprintf(&param, " PriceNightB%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, " Threshold%d INT DEFAULT 0,", i);
         res += param;
-    
+
         strprintf(&param, " Time%d VARCHAR(15) DEFAULT '0:0-0: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, " NoDiscount%d INT DEFAULT 0,", i);
         res += param;
-    
+
         strprintf(&param, " SinglePrice%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 '')";
-    
+
+    res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0,"
+        "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT '',"
+        "period VARCHAR(32) NOT NULL DEFAULT 'month',"
+        "change_policy VARCHAR(32) NOT NULL DEFAULT 'allow',"
+        "change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0)";
+
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create tariffs table list With error:\n";
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create tariffs table list With error:\n";
@@ -342,51 +395,52 @@ if(!IsTablePresent("tariffs",sock))
     }
 
     res = "INSERT INTO tariffs SET name='tariff',";
     }
 
     res = "INSERT INTO tariffs SET name='tariff',";
-        
+
     for (int i = 0; i < DIR_NUM; i++)
         {
         strprintf(&param, " NoDiscount%d=1,", i);
         res += param;
     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, " Threshold%d=0,", i);
         res += param;
-    
+
         strprintf(&param, " Time%d='0:0-0: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);
         if(i != 0 && i != 1)
         {
             strprintf(&param, " SinglePrice%d=0,", i);
-            res += param;        
+            res += param;
         }
         }
-    
+
         if(i != 1)
         {
         if(i != 1)
         {
-            strprintf(&param, " PriceDayA%d=0.0,", i); 
-            res += param;        
+            strprintf(&param, " PriceDayA%d=0.0,", i);
+            res += param;
         }
         if(i != 1)
         {
         }
         if(i != 1)
         {
-            strprintf(&param, " PriceDayB%d=0.0,", i);        
-            res += param;    
+            strprintf(&param, " PriceDayB%d=0.0,", i);
+            res += param;
         }
         }
-    
+
         if(i != 0)
         {
         if(i != 0)
         {
-            strprintf(&param, " PriceNightA%d=0.0,", i); 
-            res += param;        
+            strprintf(&param, " PriceNightA%d=0.0,", i);
+            res += param;
         }
         if(i != 0)
         {
         }
         if(i != 0)
         {
-            strprintf(&param, " PriceNightB%d=0.0,", i);        
-            res += param;    
+            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,"\
     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'";
-    
+        "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month',"\
+        "change_policy='allow', change_policy_timeout=0";
+
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create default tariff. With error:\n";
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create default tariff. With error:\n";
@@ -394,6 +448,17 @@ if(!IsTablePresent("tariffs",sock))
         mysql_close(sock);
         return -1;
     }
         mysql_close(sock);
         return -1;
     }
+
+    sprintf(qbuf,"UPDATE info SET version=1");
+
+    if(MysqlQuery(qbuf,sock))
+    {
+        errorStr = "Couldn't write default version. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+    }
+    schemaVersion = 2;
 }
 
 //users-----------------------------------------------------------------------
 }
 
 //users-----------------------------------------------------------------------
@@ -404,34 +469,34 @@ if(!IsTablePresent("users",sock))
         "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 '',";
         "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;
         }
     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;
     param = " CreditExpire INT(11) DEFAULT 0,";
     res += param;
-    
+
     strprintf(&param, " IP VARCHAR(254) DEFAULT '*',");
     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;
     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, " 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;
     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";
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create users table list With error:\n";
@@ -444,21 +509,26 @@ if(!IsTablePresent("users",sock))
     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',"\
     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='',";
-    
+        "Phone='', RealName='',Tariff='tariff',TariffChange='',NAS='',";
+
+    for (int i = 0; i < USERDATA_NUM; i++)
+        {
+        strprintf(&param, " Userdata%d='',", i);
+        res += param;
+        }
+
     for (int i = 0; i < DIR_NUM; i++)
         {
         strprintf(&param, " D%d=0,", i);
         res += param;
     for (int i = 0; i < DIR_NUM; i++)
         {
         strprintf(&param, " D%d=0,", i);
         res += param;
-    
+
         strprintf(&param, " U%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";
     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";
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create default user. With error:\n";
@@ -472,7 +542,7 @@ if(!IsTablePresent("users",sock))
 if(!IsTablePresent("logs"))
 {
     sprintf(qbuf,"CREATE TABLE logs (unid INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, login VARCHAR(40),text TEXT)");
 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";
     if(MysqlQuery(qbuf))
     {
         errorStr = "Couldn't create admin table list With error:\n";
@@ -487,7 +557,7 @@ 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)");
     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";
     if(MysqlQuery(qbuf,sock))
     {
         errorStr = "Couldn't create messages table. With error:\n";
@@ -501,18 +571,18 @@ if(!IsTablePresent("messages",sock))
 if(!IsTablePresent("stat",sock))
 {
     res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
 if(!IsTablePresent("stat",sock))
 {
     res = "CREATE TABLE stat (login VARCHAR(50), month TINYINT, year SMALLINT,";
-    
+
     for (int i = 0; i < DIR_NUM; i++)
         {
     for (int i = 0; i < DIR_NUM; i++)
         {
-        strprintf(&param, " U%d BIGINT,", i); 
+        strprintf(&param, " U%d BIGINT,", i);
         res += param;
         res += param;
-            
-        strprintf(&param, " D%d BIGINT,", i); 
+
+        strprintf(&param, " D%d BIGINT,", i);
         res += param;
         }
         res += param;
         }
-        
+
     res += " cash DOUBLE, INDEX (login))";
     res += " cash DOUBLE, INDEX (login))";
-    
+
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create stat table. With error:\n";
     if(MysqlQuery(res.c_str(),sock))
     {
         errorStr = "Couldn't create stat table. With error:\n";
@@ -525,20 +595,64 @@ if(!IsTablePresent("stat",sock))
 return 0;
 }
 //-----------------------------------------------------------------------------
 return 0;
 }
 //-----------------------------------------------------------------------------
+int MYSQL_STORE::MakeUpdates(MYSQL * sock)
+{
+if (schemaVersion  < 1)
+    {
+    if (MysqlQuery("ALTER TABLE tariffs ADD period VARCHAR(32) NOT NULL DEFAULT 'month'", sock))
+        {
+        errorStr = "Couldn't update tariffs table to version 1. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    if (MysqlQuery("UPDATE info SET version = 1", sock))
+        {
+        errorStr = "Couldn't update DB schema version to 1. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    schemaVersion = 1;
+    logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
+    }
+
+if (schemaVersion  < 2)
+    {
+    if (MysqlQuery("ALTER TABLE tariffs ADD change_policy VARCHAR(32) NOT NULL DEFAULT 'allow'", sock) ||
+        MysqlQuery("ALTER TABLE tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0", sock))
+        {
+        errorStr = "Couldn't update tariffs table to version 2. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    if (MysqlQuery("UPDATE info SET version = 2", sock))
+        {
+        errorStr = "Couldn't update DB schema version to 2. With error:\n";
+        errorStr += mysql_error(sock);
+        mysql_close(sock);
+        return -1;
+        }
+    schemaVersion = 2;
+    logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion);
+    }
+return 0;
+}
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 
-int MYSQL_STORE::GetAllParams(std::vector<std::string> * ParamList, 
+int MYSQL_STORE::GetAllParams(std::vector<std::string> * ParamList,
                             const std::string & table, const std::string & name) const
 {
 MYSQL_RES *res;
 MYSQL_ROW row;
 MYSQL * sock=NULL;
 my_ulonglong num, i;
                             const std::string & table, const std::string & name) const
 {
 MYSQL_RES *res;
 MYSQL_ROW row;
 MYSQL * sock=NULL;
 my_ulonglong num, i;
-    
+
 ParamList->clear();
 ParamList->clear();
-    
+
 sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
 sprintf(qbuf,"SELECT %s FROM %s", name.c_str(), table.c_str());
-    
+
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't GetAllParams Query for: ";
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't GetAllParams Query for: ";
@@ -560,7 +674,7 @@ num = mysql_num_rows(res);
 
 for(i = 0; i < num; i++)
 {
 
 for(i = 0; i < num; i++)
 {
-    row = mysql_fetch_row(res);    
+    row = mysql_fetch_row(res);
     ParamList->push_back(row[0]);
 }
 
     ParamList->push_back(row[0]);
 }
 
@@ -597,9 +711,12 @@ return 0;
 //-----------------------------------------------------------------------------
 int MYSQL_STORE::AddUser(const std::string & login) const
 {
 //-----------------------------------------------------------------------------
 int MYSQL_STORE::AddUser(const std::string & login) const
 {
-sprintf(qbuf,"INSERT INTO users SET login='%s'", login.c_str());
-    
-if(MysqlSetQuery(qbuf))
+std::string query = "INSERT INTO users SET login='" + login + "',Note='',NAS=''";
+
+for (int i = 0; i < USERDATA_NUM; i++)
+    query += ",Userdata" + x2str(i) + "=''";
+
+if(MysqlSetQuery(query.c_str()))
 {
     errorStr = "Couldn't add user:\n";
     //errorStr += mysql_error(sock);
 {
     errorStr = "Couldn't add user:\n";
     //errorStr += mysql_error(sock);
@@ -612,7 +729,7 @@ return 0;
 int MYSQL_STORE::DelUser(const std::string & login) const
 {
 sprintf(qbuf,"DELETE FROM users WHERE login='%s' LIMIT 1", login.c_str());
 int MYSQL_STORE::DelUser(const std::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";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't delete user:\n";
@@ -644,7 +761,7 @@ query += "CreditExpire, IP FROM users WHERE login='";
 query += login + "' LIMIT 1";
 
 //sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
 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";
 if(MysqlGetQuery(query.c_str(),sock))
 {
     errorStr = "Couldn't restore Tariff(on query):\n";
@@ -670,8 +787,6 @@ if (mysql_num_rows(res) != 1)
 
 row = mysql_fetch_row(res);
 
 
 row = mysql_fetch_row(res);
 
-std::string param;
-
 conf->password = row[1];
 
 if (conf->password.empty())
 conf->password = row[1];
 
 if (conf->password.empty())
@@ -716,7 +831,7 @@ if (GetInt(row[5], &conf->alwaysOnline) != 0)
 
 conf->tariffName = row[6];
 
 
 conf->tariffName = row[6];
 
-if (conf->tariffName.empty()) 
+if (conf->tariffName.empty())
     {
     mysql_free_result(res);
     errorStr = "User \'" + login + "\' tariff is blank.";
     {
     mysql_free_result(res);
     errorStr = "User \'" + login + "\' tariff is blank.";
@@ -747,7 +862,7 @@ for (int i = 0; i < USERDATA_NUM; i++)
     }
 
 GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
     }
 
 GetTime(row[15+USERDATA_NUM], &conf->creditExpire, 0);
-    
+
 std::string ipStr = row[16+USERDATA_NUM];
 USER_IPS i;
 try
 std::string ipStr = row[16+USERDATA_NUM];
 USER_IPS i;
 try
@@ -790,7 +905,7 @@ query += "Cash, FreeMb, LastCashAdd, LastCashAddTime, PassiveTime, LastActivityT
 query += login + "'";
 
 //sprintf(qbuf,"SELECT * FROM users WHERE login='%s' LIMIT 1", login.c_str());
 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";
 if(MysqlGetQuery(query.c_str() ,sock))
 {
     errorStr = "Couldn't restore UserStat(on query):\n";
@@ -824,7 +939,7 @@ for (int i = 0; i < DIR_NUM; i++)
         mysql_close(sock);
         return -1;
         }
         mysql_close(sock);
         return -1;
         }
-    stat->down[i] = traff;
+    stat->monthDown[i] = traff;
 
     sprintf(s, "U%d", i);
     if (GetULongLongInt(row[startPos+i*2+1], &traff, 0) != 0)
 
     sprintf(s, "U%d", i);
     if (GetULongLongInt(row[startPos+i*2+1], &traff, 0) != 0)
@@ -834,7 +949,7 @@ for (int i = 0; i < DIR_NUM; i++)
         mysql_close(sock);
         return -1;
         }
         mysql_close(sock);
         return -1;
         }
-    stat->up[i] = traff;
+    stat->monthUp[i] = traff;
     }//for
 
 startPos += (2*DIR_NUM);
     }//for
 
 startPos += (2*DIR_NUM);
@@ -899,7 +1014,7 @@ std::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', "\
 
 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', ", 
+    "Note='%s', RealName='%s', StgGroup='%s', Credit=%f, TariffChange='%s', ",
     conf.password.c_str(),
     conf.passive,
     conf.disabled,
     conf.password.c_str(),
     conf.passive,
     conf.disabled,
@@ -918,11 +1033,11 @@ strprintf(&res,"UPDATE users SET Password='%s', Passive=%d, Down=%d, DisabledDet
 
 for (int i = 0; i < USERDATA_NUM; i++)
     {
 
 for (int i = 0; i < USERDATA_NUM; i++)
     {
-    strprintf(&param, " Userdata%d='%s',", i, 
+    strprintf(&param, " Userdata%d='%s',", i,
         (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
     res += param;
     }
         (ReplaceStr(conf.userdata[i],badSyms,repSym)).c_str());
     res += param;
     }
-    
+
 strprintf(&param, " CreditExpire=%d,", conf.creditExpire);
 res += param;
 
 strprintf(&param, " CreditExpire=%d,", conf.creditExpire);
 res += param;
 
@@ -954,15 +1069,15 @@ res = "UPDATE users SET";
 
 for (int i = 0; i < DIR_NUM; i++)
     {
 
 for (int i = 0; i < DIR_NUM; i++)
     {
-    strprintf(&param, " D%d=%lld,", i, stat.down[i]);
+    strprintf(&param, " D%d=%lld,", i, stat.monthDown[i]);
     res += param;
 
     res += param;
 
-    strprintf(&param, " U%d=%lld,", i, stat.up[i]);
+    strprintf(&param, " U%d=%lld,", i, stat.monthUp[i]);
     res += param;
     }
 
 strprintf(&param, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
     res += param;
     }
 
 strprintf(&param, " Cash=%f, FreeMb=%f, LastCashAdd=%f, LastCashAddTime=%d,"\
-    " PassiveTime=%d, LastActivityTime=%d", 
+    " PassiveTime=%d, LastActivityTime=%d",
     stat.cash,
     stat.freeMb,
     stat.lastCashAdd,
     stat.cash,
     stat.freeMb,
     stat.lastCashAdd,
@@ -1017,7 +1132,7 @@ 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);
 {
     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";
     if(MysqlQuery(qbuf,sock))
     {
         errorStr = "Couldn't create WriteDetailedStat table:\n";
@@ -1107,24 +1222,24 @@ logStr += "\'";
 return WriteLogString(logStr, login);
 }
 //-----------------------------------------------------------------------------
 return WriteLogString(logStr, login);
 }
 //-----------------------------------------------------------------------------
-int MYSQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year, 
+int MYSQL_STORE::SaveMonthStat(const USER_STAT & stat, int month, int year,
                                 const std::string & login) const
 {
 std::string param, res;
 
                                 const std::string & login) const
 {
 std::string param, res;
 
-strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,", 
+strprintf(&res, "INSERT INTO stat SET login='%s', month=%d, year=%d,",
     login.c_str(), month+1, year+1900);
     login.c_str(), month+1, year+1900);
-    
+
 for (int i = 0; i < DIR_NUM; i++)
     {
 for (int i = 0; i < DIR_NUM; i++)
     {
-    strprintf(&param, " U%d=%lld,", i, stat.up[i]); 
+    strprintf(&param, " U%d=%lld,", i, stat.monthUp[i]);
     res += param;
 
     res += param;
 
-    strprintf(&param, " D%d=%lld,", i, stat.down[i]);        
+    strprintf(&param, " D%d=%lld,", i, stat.monthDown[i]);
     res += param;
     }
     res += param;
     }
-    
-strprintf(&param, " cash=%f", stat.cash);        
+
+strprintf(&param, " cash=%f", stat.cash);
 res += param;
 
 if(MysqlSetQuery(res.c_str()))
 res += param;
 
 if(MysqlSetQuery(res.c_str()))
@@ -1140,7 +1255,7 @@ return 0;
 int MYSQL_STORE::AddAdmin(const std::string & login) const
 {
 sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
 int MYSQL_STORE::AddAdmin(const std::string & login) const
 {
 sprintf(qbuf,"INSERT INTO admins SET login='%s'", login.c_str());
-    
+
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't add admin:\n";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't add admin:\n";
@@ -1154,7 +1269,7 @@ return 0;
 int MYSQL_STORE::DelAdmin(const std::string & login) const
 {
 sprintf(qbuf,"DELETE FROM admins where login='%s' LIMIT 1", login.c_str());
 int MYSQL_STORE::DelAdmin(const std::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";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't delete admin:\n";
@@ -1175,14 +1290,14 @@ memset(pass, 0, sizeof(pass));
 memset(adminPass, 0, sizeof(adminPass));
 
 BLOWFISH_CTX ctx;
 memset(adminPass, 0, sizeof(adminPass));
 
 BLOWFISH_CTX ctx;
-EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+InitContext(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++)
     {
 
 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);
+    EncryptBlock(pass + 8*i, adminPass + 8*i, &ctx);
     }
 
 pass[ADM_PASSWD_LEN - 1] = 0;
     }
 
 pass[ADM_PASSWD_LEN - 1] = 0;
@@ -1190,7 +1305,7 @@ 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 "\
 
 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", 
+    "WHERE login='%s' LIMIT 1",
     passwordE,
     ac.priv.userConf,
     ac.priv.userPasswd,
     passwordE,
     ac.priv.userConf,
     ac.priv.userPasswd,
@@ -1219,16 +1334,14 @@ char password[ADM_PASSWD_LEN + 1];
 char passwordE[2*ADM_PASSWD_LEN + 2];
 BLOWFISH_CTX ctx;
 
 char passwordE[2*ADM_PASSWD_LEN + 2];
 BLOWFISH_CTX ctx;
 
-memset(pass, 0, sizeof(pass));
 memset(password, 0, sizeof(password));
 memset(password, 0, sizeof(password));
-memset(passwordE, 0, sizeof(passwordE));
 
 std::string p;
 MYSQL_RES *res;
 MYSQL_ROW row;
 MYSQL * sock;
 sprintf(qbuf,"SELECT * FROM admins WHERE login='%s' LIMIT 1", login.c_str());
 
 std::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";
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't restore admin:\n";
@@ -1252,7 +1365,7 @@ if ( mysql_num_rows(res) == 0)
     mysql_close(sock);
     return -1;
 }
     mysql_close(sock);
     return -1;
 }
-  
+
 row = mysql_fetch_row(res);
 
 p = row[1];
 row = mysql_fetch_row(res);
 
 p = row[1];
@@ -1273,11 +1386,11 @@ memset(pass, 0, sizeof(pass));
 if (passwordE[0] != 0)
     {
     Decode21(pass, passwordE);
 if (passwordE[0] != 0)
     {
     Decode21(pass, passwordE);
-    EnDecodeInit(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
+    InitContext(adm_enc_passwd, strlen(adm_enc_passwd), &ctx);
 
     for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
         {
 
     for (int i = 0; i < ADM_PASSWD_LEN/8; i++)
         {
-        DecodeString(password + 8*i, pass + 8*i, &ctx);
+        DecryptBlock(password + 8*i, pass + 8*i, &ctx);
         }
     }
 else
         }
     }
 else
@@ -1289,7 +1402,7 @@ ac->password = password;
 
 uint16_t a;
 
 
 uint16_t a;
 
-if (GetInt(row[2], &a) == 0) 
+if (GetInt(row[2], &a) == 0)
     ac->priv.userConf = a;
 else
     {
     ac->priv.userConf = a;
 else
     {
@@ -1299,7 +1412,7 @@ else
     return -1;
     }
 
     return -1;
     }
 
-if (GetInt(row[3], &a) == 0) 
+if (GetInt(row[3], &a) == 0)
     ac->priv.userPasswd = a;
 else
     {
     ac->priv.userPasswd = a;
 else
     {
@@ -1309,7 +1422,7 @@ else
     return -1;
     }
 
     return -1;
     }
 
-if (GetInt(row[4], &a) == 0) 
+if (GetInt(row[4], &a) == 0)
     ac->priv.userStat = a;
 else
     {
     ac->priv.userStat = a;
 else
     {
@@ -1319,7 +1432,7 @@ else
     return -1;
     }
 
     return -1;
     }
 
-if (GetInt(row[5], &a) == 0) 
+if (GetInt(row[5], &a) == 0)
     ac->priv.userCash = a;
 else
     {
     ac->priv.userCash = a;
 else
     {
@@ -1329,7 +1442,7 @@ else
     return -1;
     }
 
     return -1;
     }
 
-if (GetInt(row[6], &a) == 0) 
+if (GetInt(row[6], &a) == 0)
     ac->priv.userAddDel = a;
 else
     {
     ac->priv.userAddDel = a;
 else
     {
@@ -1339,7 +1452,7 @@ else
     return -1;
     }
 
     return -1;
     }
 
-if (GetInt(row[7], &a) == 0) 
+if (GetInt(row[7], &a) == 0)
     ac->priv.tariffChg = a;
 else
     {
     ac->priv.tariffChg = a;
 else
     {
@@ -1349,7 +1462,7 @@ else
     return -1;
     }
 
     return -1;
     }
 
-if (GetInt(row[8], &a) == 0) 
+if (GetInt(row[8], &a) == 0)
     ac->priv.adminChg = a;
 else
     {
     ac->priv.adminChg = a;
 else
     {
@@ -1367,7 +1480,7 @@ return 0;
 int MYSQL_STORE::AddTariff(const std::string & name) const
 {
 sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
 int MYSQL_STORE::AddTariff(const std::string & name) const
 {
 sprintf(qbuf,"INSERT INTO tariffs SET name='%s'", name.c_str());
-    
+
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't add tariff:\n";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't add tariff:\n";
@@ -1381,7 +1494,7 @@ return 0;
 int MYSQL_STORE::DelTariff(const std::string & name) const
 {
 sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
 int MYSQL_STORE::DelTariff(const std::string & name) const
 {
 sprintf(qbuf,"DELETE FROM tariffs WHERE name='%s' LIMIT 1", name.c_str());
-    
+
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't delete tariff: ";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't delete tariff: ";
@@ -1398,7 +1511,7 @@ MYSQL_RES *res;
 MYSQL_ROW row;
 MYSQL * sock;
 sprintf(qbuf,"SELECT * FROM tariffs WHERE name='%s' LIMIT 1", tariffName.c_str());
 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";
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't restore Tariff:\n";
@@ -1433,10 +1546,10 @@ for (int i = 0; i<DIR_NUM; i++)
         return -1;
         }
 
         return -1;
         }
 
-    ParseTariffTimeStr(str.c_str(), 
-                       td->dirPrice[i].hDay, 
-                       td->dirPrice[i].mDay, 
-                       td->dirPrice[i].hNight, 
+    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);
                        td->dirPrice[i].mNight);
 
     strprintf(&param, "PriceDayA%d", i);
@@ -1533,7 +1646,22 @@ if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
 
     str = row[4+8*DIR_NUM];
     param = "TraffType";
 
     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;
+        }
+
+td->tariffConf.traffType = TARIFF::StringToTraffType(str);
+
+if (schemaVersion > 0)
+{
+    str = row[5+8*DIR_NUM];
+    param = "Period";
+
     if (str.length() == 0)
         {
         mysql_free_result(res);
     if (str.length() == 0)
         {
         mysql_free_result(res);
@@ -1542,24 +1670,46 @@ if (GetDouble(row[1+8*DIR_NUM], &td->tariffConf.passiveCost, 0.0) < 0)
         return -1;
         }
 
         return -1;
         }
 
-if (!strcasecmp(str.c_str(), "up"))
-    td->tariffConf.traffType = TRAFF_UP;
+    td->tariffConf.period = TARIFF::StringToPeriod(str);
+    }
 else
 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;
-                }
+    {
+    td->tariffConf.period = TARIFF::MONTH;
+    }
+
+if (schemaVersion > 1)
+    {
+    str = row[6+8*DIR_NUM];
+    param = "ChangePolicy";
+
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(str);
+
+    str = row[7+8*DIR_NUM];
+    param = "ChangePolicyTimeout";
+
+    if (str.length() == 0)
+        {
+        mysql_free_result(res);
+        errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param;
+        mysql_close(sock);
+        return -1;
+        }
+
+    td->tariffConf.changePolicyTimeout = readTime(str);
+    }
+else
+    {
+    td->tariffConf.changePolicy = TARIFF::ALLOW;
+    td->tariffConf.changePolicyTimeout = 0;
+    }
 
 mysql_free_result(res);
 mysql_close(sock);
 
 mysql_free_result(res);
 mysql_close(sock);
@@ -1574,30 +1724,30 @@ std::string res="UPDATE tariffs SET";
 
 for (int i = 0; i < DIR_NUM; i++)
     {
 
 for (int i = 0; i < DIR_NUM; i++)
     {
-    strprintf(&param, " PriceDayA%d=%f,", i, 
+    strprintf(&param, " PriceDayA%d=%f,", i,
         td.dirPrice[i].priceDayA * pt_mega);
     res += param;
 
         td.dirPrice[i].priceDayA * pt_mega);
     res += param;
 
-    strprintf(&param, " PriceDayB%d=%f,", i, 
-        td.dirPrice[i].priceDayB * pt_mega);        
+    strprintf(&param, " PriceDayB%d=%f,", i,
+        td.dirPrice[i].priceDayB * pt_mega);
     res += param;
     res += param;
-        
+
     strprintf(&param, " PriceNightA%d=%f,", i,
         td.dirPrice[i].priceNightA * pt_mega);
     res += param;
 
     strprintf(&param, " PriceNightA%d=%f,", i,
         td.dirPrice[i].priceNightA * pt_mega);
     res += param;
 
-    strprintf(&param, " PriceNightB%d=%f,", i, 
+    strprintf(&param, " PriceNightB%d=%f,", i,
         td.dirPrice[i].priceNightB * pt_mega);
     res += param;
         td.dirPrice[i].priceNightB * pt_mega);
     res += param;
-        
-    strprintf(&param, " Threshold%d=%d,", i, 
+
+    strprintf(&param, " Threshold%d=%d,", i,
         td.dirPrice[i].threshold);
     res += param;
 
     std::string s;
     strprintf(&param, " Time%d", i);
 
         td.dirPrice[i].threshold);
     res += param;
 
     std::string s;
     strprintf(&param, " Time%d", i);
 
-    strprintf(&s, "%0d:%0d-%0d:%0d", 
+    strprintf(&s, "%0d:%0d-%0d:%0d",
             td.dirPrice[i].hDay,
             td.dirPrice[i].mDay,
             td.dirPrice[i].hNight,
             td.dirPrice[i].hDay,
             td.dirPrice[i].mDay,
             td.dirPrice[i].hNight,
@@ -1605,11 +1755,11 @@ for (int i = 0; i < DIR_NUM; i++)
 
     res += (param + "='" + s + "',");
 
 
     res += (param + "='" + s + "',");
 
-    strprintf(&param, " NoDiscount%d=%d,", i, 
+    strprintf(&param, " NoDiscount%d=%d,", i,
         td.dirPrice[i].noDiscount);
     res += param;
 
         td.dirPrice[i].noDiscount);
     res += param;
 
-    strprintf(&param, " SinglePrice%d=%d,", i, 
+    strprintf(&param, " SinglePrice%d=%d,", i,
         td.dirPrice[i].singlePrice);
     res += param;
     }
         td.dirPrice[i].singlePrice);
     res += param;
     }
@@ -1623,27 +1773,21 @@ res += param;
 strprintf(&param, " Free=%f,", td.tariffConf.free);
 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;
-    }
+res += " TraffType='" + TARIFF::TraffTypeToString(td.tariffConf.traffType) + "'";
+
+if (schemaVersion > 0)
+    res += ", Period='" + TARIFF::PeriodToString(td.tariffConf.period) + "'";
+
+if (schemaVersion > 1)
+    res += ", change_policy='" + TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) + "'"\
+           ", change_policy_timeout='" + formatTime(td.tariffConf.changePolicy) + "'";
+
 strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
 res += param;
 
 if(MysqlSetQuery(res.c_str()))
 {
 strprintf(&param, " WHERE name='%s' LIMIT 1", tariffName.c_str());
 res += param;
 
 if(MysqlSetQuery(res.c_str()))
 {
-    errorStr = "Couldn't save admin:\n";
+    errorStr = "Couldn't save tariff:\n";
     //errorStr += mysql_error(sock);
     return -1;
 }
     //errorStr += mysql_error(sock);
     return -1;
 }
@@ -1651,8 +1795,8 @@ if(MysqlSetQuery(res.c_str()))
 return 0;
 }
 //-----------------------------------------------------------------------------
 return 0;
 }
 //-----------------------------------------------------------------------------
-int MYSQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree, 
-                                   time_t lastStat, 
+int MYSQL_STORE::WriteDetailedStat(const std::map<IP_DIR_PAIR, STAT_NODE> & statTree,
+                                   time_t lastStat,
                                    const std::string & login) const
 {
 std::string res, stTime, endTime, tempStr;
                                    const std::string & login) const
 {
 std::string res, stTime, endTime, tempStr;
@@ -1696,7 +1840,7 @@ if (num_rows < 1)
         "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);
         "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";
     if(MysqlQuery(qbuf,sock))
     {
         errorStr = "Couldn't create WriteDetailedStat table:\n";
@@ -1723,12 +1867,12 @@ lt2 = localtime(&t);
 h2 = lt2->tm_hour;
 m2 = lt2->tm_min;
 s2 = lt2->tm_sec;
 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',"\
 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',", 
+    "day=%d,startTime='%s',endTime='%s',",
     lt->tm_mon+1, lt->tm_year+1900,
     login.c_str(),
     lt->tm_mday,
     lt->tm_mon+1, lt->tm_year+1900,
     login.c_str(),
     lt->tm_mday,
@@ -1741,14 +1885,14 @@ stIter = statTree.begin();
 
 while (stIter != statTree.end())
     {
 
 while (stIter != statTree.end())
     {
-        strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f", 
+        strprintf(&tempStr,"IP='%s', dir=%d, down=%lld, up=%lld, cash=%f",
                 inet_ntostring(stIter->first.ip).c_str(),
                 inet_ntostring(stIter->first.ip).c_str(),
-                stIter->first.dir, 
-                stIter->second.down, 
-                stIter->second.up, 
+                stIter->first.dir,
+                stIter->second.down,
+                stIter->second.up,
                 stIter->second.cash
             );
                 stIter->second.cash
             );
-    
+
         if( MysqlQuery((res+tempStr).c_str(),sock) )
         {
             errorStr = "Couldn't insert data in WriteDetailedStat:\n";
         if( MysqlQuery((res+tempStr).c_str(),sock) )
         {
             errorStr = "Couldn't insert data in WriteDetailedStat:\n";
@@ -1775,11 +1919,11 @@ gettimeofday(&tv, NULL);
 
 msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
 
 
 msg->header.id = static_cast<uint64_t>(tv.tv_sec) * 1000000 + static_cast<uint64_t>(tv.tv_usec);
 
-sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld", 
+sprintf(qbuf,"INSERT INTO messages SET login='%s', id=%lld",
     login.c_str(),
     static_cast<long long>(msg->header.id)
     );
     login.c_str(),
     static_cast<long long>(msg->header.id)
     );
-    
+
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't add message:\n";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't add message:\n";
@@ -1796,7 +1940,7 @@ std::string res;
 
 strprintf(&res,"UPDATE messages SET type=%d, lastSendTime=%u, creationTime=%u, "\
     "showTime=%u, stgRepeat=%d, repeatPeriod=%u, text='%s' "\
 
 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", 
+    "WHERE login='%s' AND id=%lld LIMIT 1",
     msg.header.type,
     msg.header.lastSendTime,
     msg.header.creationTime,
     msg.header.type,
     msg.header.lastSendTime,
     msg.header.creationTime,
@@ -1826,7 +1970,7 @@ MYSQL * sock;
 
 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
         login.c_str(), static_cast<unsigned long long>(id));
 
 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s' AND id=%llu LIMIT 1",
         login.c_str(), static_cast<unsigned long long>(id));
-    
+
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't GetMessage:\n";
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't GetMessage:\n";
@@ -1903,9 +2047,9 @@ return 0;
 //-----------------------------------------------------------------------------
 int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
 {
 //-----------------------------------------------------------------------------
 int MYSQL_STORE::DelMessage(uint64_t id, const std::string & login) const
 {
-sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1", 
+sprintf(qbuf,"DELETE FROM messages WHERE login='%s' AND id=%lld LIMIT 1",
         login.c_str(), static_cast<long long>(id));
         login.c_str(), static_cast<long long>(id));
-    
+
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't delete Message:\n";
 if(MysqlSetQuery(qbuf))
 {
     errorStr = "Couldn't delete Message:\n";
@@ -1922,7 +2066,7 @@ MYSQL_RES *res;
 MYSQL_ROW row;
 MYSQL * sock;
 sprintf(qbuf,"SELECT * FROM messages WHERE login='%s'", login.c_str());
 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";
 if(MysqlGetQuery(qbuf,sock))
 {
     errorStr = "Couldn't GetMessageHdrs:\n";
@@ -1948,9 +2092,9 @@ for (i = 0; i < num_rows; i++)
     row = mysql_fetch_row(res);
     if (str2x(row[1], id))
         continue;
     row = mysql_fetch_row(res);
     if (str2x(row[1], id))
         continue;
-    
+
     STG_MSG_HDR hdr;
     STG_MSG_HDR hdr;
-    if (row[2]) 
+    if (row[2])
         if(str2x(row[2], hdr.type))
             continue;
 
         if(str2x(row[2], hdr.type))
             continue;
 
@@ -2007,7 +2151,7 @@ MYSQL *  MYSQL_STORE::MysqlConnect() const {
     }
     if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
     }
     if (!(sock = mysql_real_connect(sock,storeSettings.GetDBHost().c_str(),
             storeSettings.GetDBUser().c_str(),storeSettings.GetDBPassword().c_str(),
-            0,0,NULL,0)))
+            0,storeSettings.GetDBPort(),NULL,0)))
         {
             errorStr = "Couldn't connect to mysql engine! With error:\n";
             errorStr += mysql_error(sock);
         {
             errorStr = "Couldn't connect to mysql engine! With error:\n";
             errorStr += mysql_error(sock);