]> git.stg.codes - stg.git/commitdiff
Merge remote-tracking branch 'origin/master' into ticket37
authorElena Mamontova <helenh463@gmail.com>
Thu, 27 Oct 2016 15:55:36 +0000 (18:55 +0300)
committerElena Mamontova <helenh463@gmail.com>
Thu, 27 Oct 2016 15:55:36 +0000 (18:55 +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 51c3707910c34bbd3bf087c638c341f5060fd5f0,96add48fe14a4b2de738ea617add82770e7fe265..f63d96869552c48b8cdcdaa85502c00445bf3b43
@@@ -67,6 -67,16 +67,16 @@@ const int pt_mega = 1024 * 1024
  namespace
  {
  PLUGIN_CREATOR<FILES_STORE> fsc;
+ bool CheckAndCreate(const std::string & dir, mode_t mode)
+ {
+ if (access(dir.c_str(), F_OK) == 0)
+     return true;
+ if (mkdir(dir.c_str(), mode) == 0)
+     return true;
+ return false;
+ }
  }
  
  extern "C" STORE * GetStore();
@@@ -244,8 -254,33 +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;
  }
@@@ -410,6 -445,24 +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;
  }
  //-----------------------------------------------------------------------------
@@@ -1465,19 -1518,6 +1518,19 @@@ if (conf.ReadString("Period", &str, "mo
      td->tariffConf.period = TARIFF::MONTH;
  else
      td->tariffConf.period = TARIFF::StringToPeriod(str);
 +
 +if (conf.ReadString("ChangePolicy", &str, "allow") < 0)
 +    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;
  }
  //-----------------------------------------------------------------------------
@@@ -1539,10 -1579,118 +1592,120 @@@ std::string fileName = storeSettings.Ge
      cf.WriteDouble("Free", td.tariffConf.free);
      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 4e666794c90e62f97a07fd8482b3dc00e45dd38f,138a9ed92a8a72a2c13086b168e0ccf286165b0e..6f8177cab11bc04445b85d1503b090a0bdfd4124
@@@ -150,44 -150,36 +150,44 @@@ tr
      int32_t id;
      st->Get(1, id);
      st->Close();
 +
 +    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 = ? \
 -                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();
  
@@@ -290,15 -282,9 +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 519074b131707887647048d61e5b96fac8b8a657,db2717acb0496e8da8f7b8b8f2a9bd62e7b01c5b..1ab5d0e8c2c806e28974c30065975727efc9bfa4
@@@ -33,7 -33,6 +33,7 @@@
  
  #include <libpq-fe.h>
  
 +#include "stg/common.h"
  #include "stg/const.h"
  #include "stg/locker.h"
  #include "../../../stg_timer.h"
@@@ -271,9 -270,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 << "'";
  
@@@ -528,7 -527,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 << "', "
@@@ -565,7 -564,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())
@@@ -682,9 -681,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());
      }
@@@ -833,7 -832,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
@@@ -884,7 -883,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);
@@@ -1079,7 -1078,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 << "')";
@@@ -1150,7 -1149,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)";
      }
@@@ -1158,7 -1157,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, '')";
      }
@@@ -1250,7 -1249,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 << "')";
          }
@@@ -1398,8 -1397,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 9845242991ab5e1f91f1706dffd6ab490adb5db9,ef70505389fc372eb2425398903256a805e4882f..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
@@@ -93,10 -94,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)
      {
@@@ -112,6 -113,35 +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;
@@@ -131,8 -161,6 +132,6 @@@ if (year
  else
      {
      time_t curTime = stgTime;
-     /*time(&curTime);*/
      localtime_r(&curTime, &brokenTime);
      }
  
@@@ -144,4 -172,3 +143,3 @@@ strftime(buf, 32, "%Y-%m-%d", &brokenTi
  
  date = buf;
  }
index aea25c781b43577c3bfd4b7fb50ea652f8b45210,c160db75cb8a39ec8fd402a076fefe41d504780c..f3410368a179e097477f5e1303a3b6d7dafc416e
@@@ -1178,24 -1178,10 +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();
      }
@@@ -1342,6 -1328,75 +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 fc7c35ce86c5b19eebc1a569c3120ae2e1fc2ce2,76a1b42144b38aaec9382d516c73b8d991e6a61d..a4722a00f3e301b9bc84dc6a500552d802dfefbb
@@@ -514,6 -514,22 +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];
@@@ -733,38 -749,6 +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));
@@@ -784,11 -768,6 +800,6 @@@ if (errno == ERANGE
  
  return 0;
  }
- //---------------------------------------------------------------------------
- int str2x(const std::string & str, double & x)
- {
- return strtodouble2(str.c_str(), x);
- }
  #ifndef WIN32
  //---------------------------------------------------------------------------
  int str2x(const std::string & str, int64_t & x)
@@@ -859,6 -838,12 +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 6734a435351c4a2aa2039adeab06986c1d882c73,623d82d073aed1552bf531df2e40e4d86080f560..6201233d2b94941bad3fe04575925e3412800169
@@@ -57,9 -57,8 +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);
@@@ -77,9 -76,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);
@@@ -98,11 -97,13 +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;
@@@ -119,6 -120,7 +120,7 @@@ return res
  }
  
  template <typename T>
+ inline
  T FromString(const std::string & value)
  {
  T res;
@@@ -127,10 -129,18 +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);
@@@ -149,12 -159,11 +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);
@@@ -211,7 -220,7 +222,7 @@@ int str2x(const std::string & str, var
          x += str[i] - '0';
      }
  
-     x*= minus;
+     x *= minus;
  
      return 0;
  }