]> git.stg.codes - stg.git/commitdiff
Merge remote-tracking branch 'other/ticket37' into ticket
authorElena Mamontova <helenh463@gmail.com>
Tue, 25 Oct 2016 15:34:40 +0000 (18:34 +0300)
committerElena Mamontova <helenh463@gmail.com>
Tue, 25 Oct 2016 15:34:40 +0000 (18:34 +0300)
1  2 
projects/stargazer/plugins/store/files/file_store.cpp
projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp
projects/stargazer/user_impl.cpp
stglibs/common.lib/common.cpp
stglibs/common.lib/include/stg/common.h

index d4b29ad9c488b939dd00526b71aa86784494f437,51c3707910c34bbd3bf087c638c341f5060fd5f0..f63d96869552c48b8cdcdaa85502c00445bf3b43
@@@ -67,16 -67,6 +67,16 @@@ const int pt_mega = 1024 * 1024
  namespace
  {
  PLUGIN_CREATOR<FILES_STORE> fsc;
 +
 +bool CheckAndCreate(const std::string & dir, mode_t mode)
 +{
 +if (access(dir.c_str(), F_OK) == 0)
 +    return true;
 +if (mkdir(dir.c_str(), mode) == 0)
 +    return true;
 +return false;
 +}
 +
  }
  
  extern "C" STORE * GetStore();
@@@ -254,33 -244,8 +254,33 @@@ if (workDir.size() && workDir[workDir.s
      workDir.resize(workDir.size() - 1);
      }
  usersDir = workDir + "/users/";
 +if (!CheckAndCreate(usersDir, GetConfModeDir()))
 +    {
 +    errorStr = usersDir + " doesn't exist. Failed to create.";
 +    printfd(__FILE__, "%s\n", errorStr.c_str());
 +    return -1;
 +    }
  tariffsDir = workDir + "/tariffs/";
 +if (!CheckAndCreate(tariffsDir, GetConfModeDir()))
 +    {
 +    errorStr = tariffsDir + " doesn't exist. Failed to create.";
 +    printfd(__FILE__, "%s\n", errorStr.c_str());
 +    return -1;
 +    }
  adminsDir = workDir + "/admins/";
 +if (!CheckAndCreate(adminsDir, GetConfModeDir()))
 +    {
 +    errorStr = adminsDir + " doesn't exist. Failed to create.";
 +    printfd(__FILE__, "%s\n", errorStr.c_str());
 +    return -1;
 +    }
 +servicesDir = workDir + "/services/";
 +if (!CheckAndCreate(servicesDir, GetConfModeDir()))
 +    {
 +    errorStr = servicesDir + " doesn't exist. Failed to create.";
 +    printfd(__FILE__, "%s\n", errorStr.c_str());
 +    return -1;
 +    }
  
  return 0;
  }
@@@ -445,24 -410,6 +445,24 @@@ STG_LOCKER lock(&mutex)
  
  tariffList->swap(files);
  
 +return 0;
 +}
 +//-----------------------------------------------------------------------------
 +int FILES_STORE::GetServicesList(std::vector<std::string> * list) const
 +{
 +std::vector<std::string> files;
 +
 +if (GetFileList(&files, storeSettings.GetServicesDir(), S_IFREG, ".serv"))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Failed to open '" + storeSettings.GetServicesDir() + "': " + std::string(strerror(errno));
 +    return -1;
 +    }
 +
 +STG_LOCKER lock(&mutex);
 +
 +list->swap(files);
 +
  return 0;
  }
  //-----------------------------------------------------------------------------
@@@ -1523,6 -1470,14 +1523,14 @@@ if (conf.ReadString("ChangePolicy", &st
      td->tariffConf.changePolicy = TARIFF::ALLOW;
  else
      td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(str);
+ if (conf.ReadTime("ChangePolicyTimeout", &td->tariffConf.changePolicyTimeout, 0) < 0)
+     {
+     STG_LOCKER lock(&mutex);
+     errorStr = "Cannot read tariff " + tariffName + ". Parameter ChangePolicyTimeout";
+     printfd(__FILE__, "FILES_STORE::RestoreTariff - changepolicytimeout read failed for tariff '%s'\n", tariffName.c_str());
+     return -1;
+     }
  return 0;
  }
  //-----------------------------------------------------------------------------
@@@ -1585,118 -1540,9 +1593,119 @@@ std::string fileName = storeSettings.Ge
      cf.WriteString("TraffType", TARIFF::TraffTypeToString(td.tariffConf.traffType));
      cf.WriteString("Period", TARIFF::PeriodToString(td.tariffConf.period));
      cf.WriteString("ChangePolicy", TARIFF::ChangePolicyToString(td.tariffConf.changePolicy));
+     cf.WriteTime("ChangePolicyTimeout", td.tariffConf.changePolicyTimeout);
      }
  
 +return 0;
 +}
 +//-----------------------------------------------------------------------------*/
 +int FILES_STORE::AddService(const std::string & name) const
 +{
 +std::string fileName;
 +strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
 +
 +if (Touch(fileName))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Cannot create file " + fileName;
 +    printfd(__FILE__, "FILES_STORE::AddService - failed to add service '%s'\n", name.c_str());
 +    return -1;
 +    }
 +
 +return 0;
 +}
 +//-----------------------------------------------------------------------------*/
 +int FILES_STORE::DelService(const std::string & name) const
 +{
 +std::string fileName;
 +strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
 +if (unlink(fileName.c_str()))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "unlink failed. Message: '";
 +    errorStr += strerror(errno);
 +    errorStr += "'";
 +    printfd(__FILE__, "FILES_STORE::DelAdmin - unlink failed. Message: '%s'\n", strerror(errno));
 +    }
 +return 0;
 +}
 +//-----------------------------------------------------------------------------*/
 +int FILES_STORE::SaveService(const SERVICE_CONF & conf) const
 +{
 +std::string fileName;
 +
 +strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), conf.name.c_str());
 +
 +    {
 +    CONFIGFILE cf(fileName, true);
 +
 +    int e = cf.Error();
 +
 +    if (e)
 +        {
 +        STG_LOCKER lock(&mutex);
 +        errorStr = "Cannot write service " + conf.name + ". " + fileName;
 +        printfd(__FILE__, "FILES_STORE::SaveService - failed to save service '%s'\n", conf.name.c_str());
 +        return -1;
 +        }
 +
 +    cf.WriteString("name", conf.name);
 +    cf.WriteString("comment", conf.comment);
 +    cf.WriteDouble("cost", conf.cost);
 +    cf.WriteInt("pay_day", conf.payDay);
 +    }
 +
 +return 0;
 +}
 +//-----------------------------------------------------------------------------
 +int FILES_STORE::RestoreService(SERVICE_CONF * conf, const std::string & name) const
 +{
 +std::string fileName;
 +strprintf(&fileName, "%s/%s.serv", storeSettings.GetServicesDir().c_str(), name.c_str());
 +CONFIGFILE cf(fileName);
 +
 +if (cf.Error())
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Cannot open " + fileName;
 +    printfd(__FILE__, "FILES_STORE::RestoreService - failed to restore service '%s'\n", name.c_str());
 +    return -1;
 +    }
 +
 +if (cf.ReadString("name", &conf->name, name))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Error in parameter 'name'";
 +    printfd(__FILE__, "FILES_STORE::RestoreService - name read failed for service '%s'\n", name.c_str());
 +    return -1;
 +    }
 +
 +if (cf.ReadString("comment", &conf->comment, ""))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Error in parameter 'comment'";
 +    printfd(__FILE__, "FILES_STORE::RestoreService - comment read failed for service '%s'\n", name.c_str());
 +    return -1;
 +    }
 +
 +if (cf.ReadDouble("cost", &conf->cost, 0.0))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Error in parameter 'cost'";
 +    printfd(__FILE__, "FILES_STORE::RestoreService - cost read failed for service '%s'\n", name.c_str());
 +    return -1;
 +    }
 +
 +unsigned short value = 0;
 +if (cf.ReadUShortInt("pay_day", &value, 0))
 +    {
 +    STG_LOCKER lock(&mutex);
 +    errorStr = "Error in parameter 'pay_day'";
 +    printfd(__FILE__, "FILES_STORE::RestoreService - pay day read failed for service '%s'\n", name.c_str());
 +    return -1;
 +    }
 +conf->payDay = value;
 +
  return 0;
  }
  //-----------------------------------------------------------------------------
index cdee539855eec910fbfd8defd3b111929e38baed,4e666794c90e62f97a07fd8482b3dc00e45dd38f..6f8177cab11bc04445b85d1503b090a0bdfd4124
@@@ -150,54 -150,44 +150,44 @@@ tr
      int32_t id;
      st->Get(1, id);
      st->Close();
-     if (schemaVersion == 1)
+     std::string query = "update tb_tariffs set \
+                             fee = ?, \
+                             free = ?, \
+                             passive_cost = ?, \
+                             traff_type = ?";
+     if (schemaVersion > 0)
+         query += ", period = ?";
+     if (schemaVersion > 1)
+         query += ", change_policy = ?, \
+                     change_policy_timeout = ?";
+     query += " where pk_tariff = ?";
+     unsigned num = 5;
+     st->Prepare(query);
+     st->Set(1, td.tariffConf.fee);
+     st->Set(2, td.tariffConf.free);
+     st->Set(3, td.tariffConf.passiveCost);
+     st->Set(4, td.tariffConf.traffType);
+     if (schemaVersion > 0)
          {
-         st->Prepare("update tb_tariffs set \
-                 fee = ?, \
-                 free = ?, \
-                 passive_cost = ?, \
-                 traff_type = ?, \
-                 period = ? \
-                 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, TARIFF::PeriodToString(td.tariffConf.period));
-         st->Set(6, id);
+         ++num;
          }
-     else if (schemaVersion > 1)
-             {
-             st->Prepare("update tb_tariffs set \
-                     fee = ?, \
-                     free = ?, \
-                     passive_cost = ?, \
-                     traff_type = ?, \
-                     period = ?, \
-                     change_policy = ? \
-                     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, TARIFF::PeriodToString(td.tariffConf.period));
-             st->Set(6, TARIFF::ChangePolicyToString(td.tariffConf.changePolicy));
-             st->Set(7, id);
-             }
-     else
+     if (schemaVersion > 1)
          {
-         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->Set(6, TARIFF::ChangePolicyToString(td.tariffConf.changePolicy));
+         IBPP::Timestamp policyTimeout;
+         time_t2ts(td.tariffConf.changePolicyTimeout, &policyTimeout);
+         st->Set(7, policyTimeout);
+         num += 2;
          }
+     st->Set(num, id);
      st->Execute();
      st->Close();
  
@@@ -300,11 -290,15 +290,14 @@@ tr
      st->Get(3, td->tariffConf.fee);
      st->Get(4, td->tariffConf.free);
      st->Get(5, td->tariffConf.passiveCost);
 -    //st->Get(6, td->tariffConf.traffType);
      td->tariffConf.traffType = TARIFF::IntToTraffType(Get<int>(st, 6));
      if (schemaVersion > 0)
          td->tariffConf.period = TARIFF::StringToPeriod(Get<std::string>(st, 7));
      if (schemaVersion > 1)
+         {
          td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(Get<std::string>(st, 8));
+         td->tariffConf.changePolicyTimeout = ts2time_t(Get<IBPP::Timestamp>(st, 9));
+         }
      st->Close();
      st->Prepare("select * from tb_tariffs_params where fk_tariff = ?");
      st->Set(1, id);
index db2717acb0496e8da8f7b8b8f2a9bd62e7b01c5b,519074b131707887647048d61e5b96fac8b8a657..1ab5d0e8c2c806e28974c30065975727efc9bfa4
@@@ -33,6 -33,7 +33,7 @@@
  
  #include <libpq-fe.h>
  
+ #include "stg/common.h"
  #include "stg/const.h"
  #include "stg/locker.h"
  #include "../../../stg_timer.h"
@@@ -270,9 -271,9 +271,9 @@@ std::ostringstream query
  query << "UPDATE tb_users SET "
              "cash = " << stat.cash << ", "
              "free_mb = " << stat.freeMb << ", "
-             "last_activity_time = CAST('" << Int2TS(stat.lastActivityTime) << "' AS TIMESTAMP), "
+             "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), "
              "last_cash_add = " << stat.lastCashAdd << ", "
-             "last_cash_add_time = CAST('" << Int2TS(stat.lastCashAddTime) << "' AS TIMESTAMP), "
+             "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), "
              "passive_time = " << stat.passiveTime << " "
           "WHERE name = '" << elogin << "'";
  
@@@ -527,7 -528,7 +528,7 @@@ query << "UPDATE tb_users SET 
               "address = '" << eaddress << "', "
               "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
               "credit = " << conf.credit << ", "
-              "credit_expire = CAST('" << Int2TS(conf.creditExpire) << "' AS TIMESTAMP), "
+              "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), "
               "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
               "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
               "email = '" << eemail << "', "
@@@ -564,7 -565,7 +565,7 @@@ if (PQresultStatus(result) != PGRES_COM
  
  PQclear(result);
  
 -if (SaveUserServices(uid, conf.service))
 +if (SaveUserServices(uid, conf.services))
      {
      printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
      if (RollbackTransaction())
@@@ -681,9 -682,9 +682,9 @@@ if (tuples != 1
      std::stringstream tuple;
      tuple << PQgetvalue(result, 0, 0) << " ";
      tuple << PQgetvalue(result, 0, 1) << " ";
-     stat->lastActivityTime = TS2Int(PQgetvalue(result, 0, 2));
+     stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2));
      tuple << PQgetvalue(result, 0, 3) << " ";
-     stat->lastCashAddTime = TS2Int(PQgetvalue(result, 0, 4));
+     stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4));
      tuple << PQgetvalue(result, 0, 5) << " ";
  
      PQclear(result);
      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))";
+                    "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))";
  
      result = PQexec(connection, query.str().c_str());
      }
@@@ -832,7 -833,7 +833,7 @@@ uint32_t 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->creditExpire = readTime(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
@@@ -883,7 -884,7 +884,7 @@@ tuples = PQntuples(result)
  
  for (int i = 0; i < tuples; ++i)
      {
 -    conf->service.push_back(PQgetvalue(result, i, 0));
 +    conf->services.push_back(PQgetvalue(result, i, 0));
      }
  
  PQclear(result);
@@@ -1078,7 -1079,7 +1079,7 @@@ query << "SELECT sp_add_param_log_entry
              "'" << eadminLogin << "', CAST('"
              << inet_ntostring(admIP) << "/32' AS INET), "
              "'" << eparam << "', "
-             "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+             "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
              "'" << eold << "', "
              "'" << enew << "', "
              "'" << emessage << "')";
@@@ -1149,7 -1150,7 +1150,7 @@@ if (version < 6
      {
      query << "SELECT sp_add_session_log_entry("
                   "'" << elogin << "', "
-                  "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                   "'c', CAST('"
                   << inet_ntostring(ip) << "/32' AS INET), 0)";
      }
@@@ -1157,7 -1158,7 +1158,7 @@@ els
      {
      query << "SELECT sp_add_session_log_entry("
                   "'" << elogin << "', "
-                  "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                   "'c', CAST('"
                   << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
      }
@@@ -1249,7 -1250,7 +1250,7 @@@ if (EscapeString(ereason)
          // Old database version - no freeMb logging support
          query << "SELECT sp_add_session_log_entry("
                      "'" << elogin << "', "
-                     "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                      "'d', CAST('0.0.0.0/0' AS INET), "
                      << cash << ")";
          }
          {
          query << "SELECT sp_add_session_log_entry("
                      "'" << elogin << "', "
-                     "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), "
+                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
                      "'d', CAST('0.0.0.0/0' AS INET), "
                      << cash << ", " << freeMb << ", '" << ereason << "')";
          }
@@@ -1397,8 -1398,8 +1398,8 @@@ for (it = statTree.begin(); it != statT
                  "(till_time, from_time, fk_user, "
                   "dir_num, ip, download, upload, cost) "
               "VALUES ("
-                 "CAST('" << Int2TS(currTime) << "' AS TIMESTAMP), "
-                 "CAST('" << Int2TS(lastStat) << "' AS TIMESTAMP), "
+                 "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
+                 "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
                  "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
                  << it->first.dir << ", "
                  << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
index ef70505389fc372eb2425398903256a805e4882f,9845242991ab5e1f91f1706dffd6ab490adb5db9..9a5101e121c04a605e1698f08305445e31687818
   *
   */
  
 +#include "postgresql_store.h"
 +
 +#include "stg/common.h"
 +
  #include <string>
  #include <ctime>
  
  #include <libpq-fe.h>
  
 -#include "stg/common.h"
 -#include "postgresql_store.h"
 -
  extern volatile time_t stgTime;
  
  int POSTGRESQL_STORE::StartTransaction() const
@@@ -94,10 -93,10 +94,10 @@@ int error = 0
  char * buf = new char[(value.length() << 1) + 1];
  
  PQescapeStringConn(connection,
 -                 buf,
 -                 value.c_str(),
 -                 value.length(),
 -                 &error);
 +                   buf,
 +                   value.c_str(),
 +                   value.length(),
 +                   &error);
  
  if (error)
      {
@@@ -113,35 -112,6 +113,6 @@@ delete[] buf
  return 0;
  }
  
- std::string POSTGRESQL_STORE::Int2TS(time_t ts) const
- {
- struct tm brokenTime;
- brokenTime.tm_wday = 0;
- brokenTime.tm_yday = 0;
- brokenTime.tm_isdst = 0;
- gmtime_r(&ts, &brokenTime);
- char buf[32];
- strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
- return buf;
- }
- time_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;
@@@ -161,6 -131,8 +132,6 @@@ if (year
  else
      {
      time_t curTime = stgTime;
 -    /*time(&curTime);*/
 -
      localtime_r(&curTime, &brokenTime);
      }
  
@@@ -172,3 -144,4 +143,3 @@@ strftime(buf, 32, "%Y-%m-%d", &brokenTi
  
  date = buf;
  }
 -
index c160db75cb8a39ec8fd402a076fefe41d504780c,aea25c781b43577c3bfd4b7fb50ea652f8b45210..f3410368a179e097477f5e1303a3b6d7dafc416e
@@@ -1178,10 -1178,24 +1178,24 @@@ if (nextTariff.ConstData() != ""
      {
      const TARIFF * 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);
+         {
+         std::string message = tariff->TariffChangeIsAllowed(*nt);
+         if (message.empty())
+             {
+             property.tariffName.Set(nextTariff, sysAdmin, login, store);
+             }
+         else
+             {
+             WriteServLog("Tariff change is prohibited for user %s. %s",
+                          login.c_str(),
+                          message.c_str());
+             }
+         }
      ResetNextTariff();
      WriteConf();
      }
@@@ -1328,75 -1342,6 +1342,75 @@@ switch (settings->GetFeeChargeType()
  ResetPassiveTime();
  }
  //-----------------------------------------------------------------------------
 +void USER_IMPL::ProcessServices()
 +{
 +struct tm tms;
 +time_t t = stgTime;
 +localtime_r(&t, &tms);
 +
 +double passiveTimePart = 1.0;
 +if (!settings->GetFullFee())
 +    {
 +    passiveTimePart = GetPassiveTimePart();
 +    }
 +else
 +    {
 +    if (passive.ConstData())
 +        {
 +        printfd(__FILE__, "Don't charge fee `cause we are passive\n");
 +        return;
 +        }
 +    }
 +
 +for (size_t i = 0; i < property.Conf().services.size(); ++i)
 +    {
 +    SERVICE_CONF conf;
 +    if (m_services.Find(property.Conf().services[i], &conf))
 +        continue;
 +    if (conf.payDay == tms.tm_mday ||
 +        (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
 +        {
 +        double c = cash;
 +        double fee = conf.cost * passiveTimePart;
 +        printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
 +                login.c_str(),
 +                cash.ConstData(),
 +                credit.ConstData(),
 +                tariff->GetFee(),
 +                passiveTimePart,
 +                fee);
 +        switch (settings->GetFeeChargeType())
 +            {
 +            case 0:
 +                property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 +                SetPrepaidTraff();
 +                break;
 +            case 1:
 +                if (c + credit >= 0)
 +                    {
 +                    property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 +                    SetPrepaidTraff();
 +                    }
 +                break;
 +            case 2:
 +                if (c + credit >= fee)
 +                    {
 +                    property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 +                    SetPrepaidTraff();
 +                    }
 +                break;
 +            case 3:
 +                if (c >= 0)
 +                    {
 +                    property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 +                    SetPrepaidTraff();
 +                    }
 +                break;
 +            }
 +        }
 +    }
 +}
 +//-----------------------------------------------------------------------------
  void USER_IMPL::SetPrepaidTraff()
  {
  if (tariff != NULL)
index 76a1b42144b38aaec9382d516c73b8d991e6a61d,fc7c35ce86c5b19eebc1a569c3120ae2e1fc2ce2..a4722a00f3e301b9bc84dc6a500552d802dfefbb
@@@ -514,22 -514,6 +514,22 @@@ uint32_t inet_strington(const std::stri
      return result;
  }
  //-----------------------------------------------------------------------------
 +std::string TimeToString(time_t time)
 +{
 +struct tm brokenTime;
 +
 +brokenTime.tm_wday = 0;
 +brokenTime.tm_yday = 0;
 +brokenTime.tm_isdst = 0;
 +
 +gmtime_r(&time, &brokenTime);
 +
 +char buf[32];
 +strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
 +
 +return buf;
 +}
 +//-----------------------------------------------------------------------------
  int ParseTariffTimeStr(const char * str, int &h1, int &m1, int &h2, int &m2)
  {
  char hs1[10], ms1[10], hs2[10], ms2[10];
@@@ -749,6 -733,38 +749,38 @@@ void SwapBytes(int64_t & value
      value = temp;
  }
  //---------------------------------------------------------------------------
+ std::string formatTime(time_t ts)
+ {
+ char buf[32];
+ struct tm brokenTime;
+ brokenTime.tm_wday = 0;
+ brokenTime.tm_yday = 0;
+ brokenTime.tm_isdst = 0;
+ gmtime_r(&ts, &brokenTime);
+ strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime);
+ return buf;
+ }
+ //---------------------------------------------------------------------------
+ time_t readTime(const std::string & ts)
+ {
+ if (ts == "0000-00-00 00:00:00")
+     return 0;
+ 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);
+ }
+ //---------------------------------------------------------------------------
  int str2x(const std::string & str, int32_t & x)
  {
  x = static_cast<int32_t>(strtol(str.c_str(), NULL, 10));
@@@ -768,6 -784,11 +800,6 @@@ if (errno == ERANGE
  
  return 0;
  }
 -//---------------------------------------------------------------------------
 -int str2x(const std::string & str, double & x)
 -{
 -return strtodouble2(str.c_str(), x);
 -}
  #ifndef WIN32
  //---------------------------------------------------------------------------
  int str2x(const std::string & str, int64_t & x)
@@@ -838,12 -859,6 +870,12 @@@ std::string & Trim(std::string & val
  return TrimR(TrimL(val));
  }
  //---------------------------------------------------------------------------
 +std::string Trim(const std::string & val)
 +{
 +std::string res(val);
 +return TrimR(TrimL(res));
 +}
 +//---------------------------------------------------------------------------
  std::string ToLower(std::string value)
  {
      std::transform(value.begin(), value.end(), value.begin(), ::tolower);
index 623d82d073aed1552bf531df2e40e4d86080f560,6734a435351c4a2aa2039adeab06986c1d882c73..6201233d2b94941bad3fe04575925e3412800169
@@@ -57,8 -57,9 +57,8 @@@ const char    * IntToKMG(int64_t a, in
  const char    * LogDate(time_t t);
  int             ParesTimeStat(const char * str);
  int             IsTimeStat(struct tm * t, int statTime);
 -/*bool            IsDigit(char c);
 -bool            IsAlpha(char c);*/
 -int             strtodouble2(const char * s, double &a);
 +int             strtodouble2(const char * str, double & value);
 +inline int      strtodouble2(const std::string & str, double & value) { return strtodouble2(str.c_str(), value); }
  int             printfd(const char * __file__, const char * fmt, ...);
  void            Encode12(char * dst, const char * src, size_t srcLen);
  void            Decode21(char * dst, const char * src);
@@@ -76,9 -77,9 +76,9 @@@ void            WinToKOI(const std::str
  int             DaysInMonth(unsigned year, unsigned mon);
  int             DaysInCurrentMonth();
  int             Min8(int a);
 -//char          * inet_ntostr(unsigned long);
  std::string     inet_ntostring(uint32_t);
  uint32_t        inet_strington(const std::string & value);
 +std::string     TimeToString(time_t time);
  int             strprintf(std::string * str, const char * fmt, ...);
  int             ParseTariffTimeStr(const char * str, int &h1, int &m1, int &h2, int &m2);
  uint32_t        CalcMask(uint32_t msk);
@@@ -97,13 -98,11 +97,13 @@@ void            SwapBytes(int64_t & val
  std::string &   TrimL(std::string & val);
  std::string &   TrimR(std::string & val);
  std::string &   Trim(std::string & val);
 +std::string     Trim(const std::string & val);
  
 -std::string ToLower(std::string value);
 -std::string ToUpper(std::string value);
 +std::string     ToLower(std::string value);
 +std::string     ToUpper(std::string value);
  
  template <typename C, typename F>
 +inline
  C Split(const std::string & value, char delim, F conv)
  {
  C res;
@@@ -120,7 -119,6 +120,7 @@@ return res
  }
  
  template <typename T>
 +inline
  T FromString(const std::string & value)
  {
  T res;
@@@ -129,18 -127,10 +129,18 @@@ stream >> res
  return res;
  }
  
 +template <>
 +inline
 +std::string FromString<std::string>(const std::string & value)
 +{
 +return value;
 +}
 +
  template <typename C>
 +inline
  C Split(const std::string & value, char delim)
  {
 -    return Split<C>(value, delim, FromString);
 +    return Split<C>(value, delim, FromString<typename C::value_type>);
  }
  
  std::string IconvString(const std::string & source, const std::string & from, const std::string & to);
@@@ -159,11 -149,12 +159,13 @@@ bool WriteAll(int sd, const void * sour
  
  std::string ToPrintable(const std::string & src);
  
+ std::string formatTime(time_t value);
+ time_t readTime(const std::string & value);
  //-----------------------------------------------------------------------------
  int str2x(const std::string & str, int32_t & x);
  int str2x(const std::string & str, uint32_t & x);
 -int str2x(const std::string & str, double & x);
 +inline
 +int str2x(const std::string & str, double & x) { return strtodouble2(str.c_str(), x); }
  #ifndef WIN32
  int str2x(const std::string & str, int64_t & x);
  int str2x(const std::string & str, uint64_t & x);
@@@ -220,7 -211,7 +222,7 @@@ int str2x(const std::string & str, var
          x += str[i] - '0';
      }
  
 -    x*= minus;
 +    x *= minus;
  
      return 0;
  }