2  *    This program is free software; you can redistribute it and/or modify
 
   3  *    it under the terms of the GNU General Public License as published by
 
   4  *    the Free Software Foundation; either version 2 of the License, or
 
   5  *    (at your option) any later version.
 
   7  *    This program is distributed in the hope that it will be useful,
 
   8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
   9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  10  *    GNU General Public License for more details.
 
  12  *    You should have received a copy of the GNU General Public License
 
  13  *    along with this program; if not, write to the Free Software
 
  14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
  22  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
 
  27  $Date: 2010/11/03 10:50:03 $
 
  36 #include <unistd.h> // access
 
  41 #include "stg/users.h"
 
  42 #include "stg/common.h"
 
  43 #include "stg/scriptexecuter.h"
 
  44 #include "stg/tariff.h"
 
  45 #include "stg/tariffs.h"
 
  46 #include "stg/admin.h"
 
  47 #include "user_impl.h"
 
  48 #include "settings_impl.h"
 
  49 #include "stg_timer.h"
 
  51 #ifdef USE_ABSTRACT_SETTINGS
 
  52 USER_IMPL::USER_IMPL(const SETTINGS * s,
 
  59       property(s->GetScriptsDir()),
 
  60       WriteServLog(GetStgLogger()),
 
  65       connected(__connected),
 
  70       lastIPForDisconnect(0),
 
  83       lastWriteDetailedStat(0),
 
  87       lastCashAdd(property.lastCashAdd),
 
  88       passiveTime(property.passiveTime),
 
  89       lastCashAddTime(property.lastCashAddTime),
 
  90       freeMb(property.freeMb),
 
  91       lastActivityTime(property.lastActivityTime),
 
  92       password(property.password),
 
  93       passive(property.passive),
 
  94       disabled(property.disabled),
 
  95       disabledDetailStat(property.disabledDetailStat),
 
  96       alwaysOnline(property.alwaysOnline),
 
  97       tariffName(property.tariffName),
 
  98       nextTariff(property.nextTariff),
 
  99       address(property.address),
 
 101       group(property.group),
 
 102       email(property.email),
 
 103       phone(property.phone),
 
 104       realName(property.realName),
 
 105       credit(property.credit),
 
 106       creditExpire(property.creditExpire),
 
 108       userdata0(property.userdata0),
 
 109       userdata1(property.userdata1),
 
 110       userdata2(property.userdata2),
 
 111       userdata3(property.userdata3),
 
 112       userdata4(property.userdata4),
 
 113       userdata5(property.userdata5),
 
 114       userdata6(property.userdata6),
 
 115       userdata7(property.userdata7),
 
 116       userdata8(property.userdata8),
 
 117       userdata9(property.userdata9),
 
 120       passiveNotifier(this),
 
 121       tariffNotifier(this),
 
 127 password = "*_EMPTY_PASSWORD_*";
 
 128 tariffName = NO_TARIFF_NAME;
 
 130 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
 
 131 lastWriteDetailedStat = stgTime;
 
 133 property.tariffName.AddBeforeNotifier(&tariffNotifier);
 
 134 property.passive.AddBeforeNotifier(&passiveNotifier);
 
 135 property.cash.AddBeforeNotifier(&cashNotifier);
 
 136 ips.AddAfterNotifier(&ipNotifier);
 
 138 pthread_mutexattr_t attr;
 
 139 pthread_mutexattr_init(&attr);
 
 140 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 
 141 pthread_mutex_init(&mutex, &attr);
 
 144 USER_IMPL::USER_IMPL(const SETTINGS_IMPL * s,
 
 151       property(s->GetScriptsDir()),
 
 152       WriteServLog(GetStgLogger()),
 
 157       connected(__connected),
 
 162       lastIPForDisconnect(0),
 
 175       lastWriteDetailedStat(0),
 
 179       lastCashAdd(property.lastCashAdd),
 
 180       passiveTime(property.passiveTime),
 
 181       lastCashAddTime(property.lastCashAddTime),
 
 182       freeMb(property.freeMb),
 
 183       lastActivityTime(property.lastActivityTime),
 
 184       password(property.password),
 
 185       passive(property.passive),
 
 186       disabled(property.disabled),
 
 187       disabledDetailStat(property.disabledDetailStat),
 
 188       alwaysOnline(property.alwaysOnline),
 
 189       tariffName(property.tariffName),
 
 190       nextTariff(property.nextTariff),
 
 191       address(property.address),
 
 193       group(property.group),
 
 194       email(property.email),
 
 195       phone(property.phone),
 
 196       realName(property.realName),
 
 197       credit(property.credit),
 
 198       creditExpire(property.creditExpire),
 
 200       userdata0(property.userdata0),
 
 201       userdata1(property.userdata1),
 
 202       userdata2(property.userdata2),
 
 203       userdata3(property.userdata3),
 
 204       userdata4(property.userdata4),
 
 205       userdata5(property.userdata5),
 
 206       userdata6(property.userdata6),
 
 207       userdata7(property.userdata7),
 
 208       userdata8(property.userdata8),
 
 209       userdata9(property.userdata9),
 
 212       passiveNotifier(this),
 
 213       tariffNotifier(this),
 
 219 password = "*_EMPTY_PASSWORD_*";
 
 220 tariffName = NO_TARIFF_NAME;
 
 222 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
 
 223 lastWriteDetailedStat = stgTime;
 
 225 property.tariffName.AddBeforeNotifier(&tariffNotifier);
 
 226 property.passive.AddBeforeNotifier(&passiveNotifier);
 
 227 property.cash.AddBeforeNotifier(&cashNotifier);
 
 228 ips.AddAfterNotifier(&ipNotifier);
 
 230 pthread_mutexattr_t attr;
 
 231 pthread_mutexattr_init(&attr);
 
 232 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 
 233 pthread_mutex_init(&mutex, &attr);
 
 236 //-----------------------------------------------------------------------------
 
 237 USER_IMPL::USER_IMPL(const USER_IMPL & u)
 
 240       property(u.settings->GetScriptsDir()),
 
 241       WriteServLog(GetStgLogger()),
 
 246       connected(__connected),
 
 248       userIDGenerator(u.userIDGenerator),
 
 249       __currIP(u.__currIP),
 
 251       lastIPForDisconnect(0),
 
 252       pingTime(u.pingTime),
 
 253       sysAdmin(u.sysAdmin),
 
 257       traffStat(u.traffStat),
 
 258       traffStatSaved(u.traffStatSaved),
 
 259       settings(u.settings),
 
 261       messages(u.messages),
 
 263       lastWriteStat(u.lastWriteStat),
 
 264       lastWriteDetailedStat(u.lastWriteDetailedStat),
 
 268       lastCashAdd(property.lastCashAdd),
 
 269       passiveTime(property.passiveTime),
 
 270       lastCashAddTime(property.lastCashAddTime),
 
 271       freeMb(property.freeMb),
 
 272       lastActivityTime(property.lastActivityTime),
 
 273       password(property.password),
 
 274       passive(property.passive),
 
 275       disabled(property.disabled),
 
 276       disabledDetailStat(property.disabledDetailStat),
 
 277       alwaysOnline(property.alwaysOnline),
 
 278       tariffName(property.tariffName),
 
 279       nextTariff(property.nextTariff),
 
 280       address(property.address),
 
 282       group(property.group),
 
 283       email(property.email),
 
 284       phone(property.phone),
 
 285       realName(property.realName),
 
 286       credit(property.credit),
 
 287       creditExpire(property.creditExpire),
 
 289       userdata0(property.userdata0),
 
 290       userdata1(property.userdata1),
 
 291       userdata2(property.userdata2),
 
 292       userdata3(property.userdata3),
 
 293       userdata4(property.userdata4),
 
 294       userdata5(property.userdata5),
 
 295       userdata6(property.userdata6),
 
 296       userdata7(property.userdata7),
 
 297       userdata8(property.userdata8),
 
 298       userdata9(property.userdata9),
 
 301       passiveNotifier(this),
 
 302       tariffNotifier(this),
 
 311 property.tariffName.AddBeforeNotifier(&tariffNotifier);
 
 312 property.passive.AddBeforeNotifier(&passiveNotifier);
 
 313 property.cash.AddBeforeNotifier(&cashNotifier);
 
 314 ips.AddAfterNotifier(&ipNotifier);
 
 316 property.SetProperties(u.property);
 
 318 pthread_mutexattr_t attr;
 
 319 pthread_mutexattr_init(&attr);
 
 320 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 
 321 pthread_mutex_init(&mutex, &attr);
 
 323 //-----------------------------------------------------------------------------
 
 324 USER_IMPL::~USER_IMPL()
 
 326 property.passive.DelBeforeNotifier(&passiveNotifier);
 
 327 property.tariffName.DelBeforeNotifier(&tariffNotifier);
 
 328 pthread_mutex_destroy(&mutex);
 
 330 //-----------------------------------------------------------------------------
 
 331 void USER_IMPL::SetLogin(string const & l)
 
 333 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 334 assert(login.empty() && "Login is already set");
 
 336 id = userIDGenerator.GetNextID();
 
 338 //-----------------------------------------------------------------------------
 
 339 int USER_IMPL::ReadConf()
 
 341 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 344 if (store->RestoreUserConf(&conf, login))
 
 346     WriteServLog("Cannot read conf for user %s.", login.c_str());
 
 347     WriteServLog("%s", store->GetStrError().c_str());
 
 348     printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
 
 349     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
 
 353 property.SetConf(conf);
 
 355 tariff = tariffs->FindByName(tariffName);
 
 358     WriteServLog("Cannot read user %s. Tariff %s not exist.",
 
 359                  login.c_str(), property.tariffName.Get().c_str());
 
 363 std::vector<STG_MSG_HDR> hdrsList;
 
 365 if (store->GetMessageHdrs(&hdrsList, login))
 
 367     printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
 
 368     WriteServLog("Cannot read user %s. Error reading message headers: %s.",
 
 370                  store->GetStrError().c_str());
 
 374 std::vector<STG_MSG_HDR>::const_iterator it;
 
 375 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
 
 378     if (store->GetMessage(it->id, &msg, login) == 0)
 
 380         messages.push_back(msg);
 
 386 //-----------------------------------------------------------------------------
 
 387 int USER_IMPL::ReadStat()
 
 389 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 392 if (store->RestoreUserStat(&stat, login))
 
 394     WriteServLog("Cannot read stat for user %s.", login.c_str());
 
 395     WriteServLog("%s", store->GetStrError().c_str());
 
 396     printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
 
 397     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
 
 401 property.SetStat(stat);
 
 405 //-----------------------------------------------------------------------------
 
 406 int USER_IMPL::WriteConf()
 
 408 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 409 USER_CONF conf(property.GetConf());
 
 411 printfd(__FILE__, "USER::WriteConf()\n");
 
 413 if (store->SaveUserConf(conf, login))
 
 415     WriteServLog("Cannot write conf for user %s.", login.c_str());
 
 416     WriteServLog("%s", store->GetStrError().c_str());
 
 417     printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
 
 418     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
 
 424 //-----------------------------------------------------------------------------
 
 425 int USER_IMPL::WriteStat()
 
 427 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 428 USER_STAT stat(property.GetStat());
 
 430 if (store->SaveUserStat(stat, login))
 
 432     WriteServLog("Cannot write stat for user %s.", login.c_str());
 
 433     WriteServLog("%s", store->GetStrError().c_str());
 
 434     printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
 
 435     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
 
 439 lastWriteStat = stgTime;
 
 443 //-----------------------------------------------------------------------------
 
 444 int USER_IMPL::WriteMonthStat()
 
 446 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 447 time_t tt = stgTime - 3600;
 
 449 localtime_r(&tt, &t1);
 
 451 USER_STAT stat(property.GetStat());
 
 452 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
 
 454     WriteServLog("Cannot write month stat for user %s.", login.c_str());
 
 455     WriteServLog("%s", store->GetStrError().c_str());
 
 456     printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
 
 457     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
 
 463 //-----------------------------------------------------------------------------
 
 464 int USER_IMPL::Authorize(uint32_t ip, uint32_t dirs, const AUTH * auth)
 
 466 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 468  *  Authorize user. It only means that user will be authorized. Nothing more.
 
 469  *  User can be connected or disconnected while authorized.
 
 470  *  Example: user is authorized but disconnected due to 0 money or blocking
 
 474  * Prevent double authorization by identical authorizers
 
 476 if (authorizedBy.find(auth) != authorizedBy.end())
 
 482 for (int i = 0; i < DIR_NUM; i++)
 
 484     enabledDirs[i] = dirs & (1 << i);
 
 487 if (!authorizedBy.empty())
 
 491         //  We are already authorized, but with different IP address
 
 492         errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
 
 497     if (!users->FindByIPIdx(ip, &u))
 
 499         //  Address is already present in IP-index
 
 500         //  If it's not our IP - throw an error
 
 503             errorStr = "IP address " + inet_ntostring(ip) + " already in use";
 
 510     if (users->IsIPInIndex(ip))
 
 512         //  Address is already present in IP-index
 
 513         errorStr = "IP address " + inet_ntostring(ip) + " already in use";
 
 517     if (ips.ConstData().IsIPInIPS(ip))
 
 520         lastIPForDisconnect = currIP;
 
 524         printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
 
 525         errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
 
 530 authorizedBy.insert(auth);
 
 536 //-----------------------------------------------------------------------------
 
 537 void USER_IMPL::Unauthorize(const AUTH * auth)
 
 539 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 541  *  Authorizer tries to unauthorize user, that was not authorized by it
 
 543 if (!authorizedBy.erase(auth))
 
 546 if (authorizedBy.empty())
 
 548     lastIPForDisconnect = currIP;
 
 549     currIP = 0; // DelUser in traffcounter
 
 553 //-----------------------------------------------------------------------------
 
 554 bool USER_IMPL::IsAuthorizedBy(const AUTH * auth) const
 
 556 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 557 //  Is this user authorized by specified authorizer?
 
 558 return authorizedBy.find(auth) != authorizedBy.end();
 
 560 //-----------------------------------------------------------------------------
 
 561 void USER_IMPL::Connect(bool fakeConnect)
 
 564  *  Connect user to Internet. This function is differ from Authorize() !!!
 
 567 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 571     string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
 
 573     if (access(scriptOnConnect.c_str(), X_OK) == 0)
 
 575         char dirsStr[DIR_NUM + 1];
 
 576         dirsStr[DIR_NUM] = 0;
 
 577         for (int i = 0; i < DIR_NUM; i++)
 
 579             dirsStr[i] = enabledDirs[i] ? '1' : '0';
 
 582         string scriptOnConnectParams;
 
 583         strprintf(&scriptOnConnectParams,
 
 584                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
 
 585                 scriptOnConnect.c_str(),
 
 587                 inet_ntostring(currIP).c_str(),
 
 592         ScriptExec(scriptOnConnectParams.c_str());
 
 596         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
 
 602 if (store->WriteUserConnect(login, currIP))
 
 604     WriteServLog("Cannot write connect for user %s.", login.c_str());
 
 605     WriteServLog("%s", store->GetStrError().c_str());
 
 609     lastIPForDisconnect = currIP;
 
 611 //-----------------------------------------------------------------------------
 
 612 void USER_IMPL::Disconnect(bool fakeDisconnect, const std::string & reason)
 
 615  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
 
 618 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 620 if (!lastIPForDisconnect)
 
 622     printfd(__FILE__, "lastIPForDisconnect\n");
 
 628     string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
 
 630     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
 
 632         char dirsStr[DIR_NUM + 1];
 
 633         dirsStr[DIR_NUM] = 0;
 
 634         for (int i = 0; i < DIR_NUM; i++)
 
 636             dirsStr[i] = enabledDirs[i] ? '1' : '0';
 
 639         string scriptOnDisonnectParams;
 
 640         strprintf(&scriptOnDisonnectParams,
 
 641                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
 
 642                 scriptOnDisonnect.c_str(),
 
 644                 inet_ntostring(lastIPForDisconnect).c_str(),
 
 649         ScriptExec(scriptOnDisonnectParams.c_str());
 
 653         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
 
 659 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, cash, freeMb, reason))
 
 661     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
 
 662     WriteServLog("%s", store->GetStrError().c_str());
 
 666     lastIPForDisconnect = 0;
 
 668 DIR_TRAFF zeroSesssion;
 
 670 sessionUpload = zeroSesssion;
 
 671 sessionDownload = zeroSesssion;
 
 673 //-----------------------------------------------------------------------------
 
 674 void USER_IMPL::PrintUser() const
 
 677 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 678 cout << "============================================================" << endl;
 
 679 cout << "id=" << id << endl;
 
 680 cout << "login=" << login << endl;
 
 681 cout << "password=" << password << endl;
 
 682 cout << "passive=" << passive << endl;
 
 683 cout << "disabled=" << disabled << endl;
 
 684 cout << "disabledDetailStat=" << disabledDetailStat << endl;
 
 685 cout << "alwaysOnline=" << alwaysOnline << endl;
 
 686 cout << "tariffName=" << tariffName << endl;
 
 687 cout << "address=" << address << endl;
 
 688 cout << "phone=" << phone << endl;
 
 689 cout << "email=" << email << endl;
 
 690 cout << "note=" << note << endl;
 
 691 cout << "realName=" <<realName << endl;
 
 692 cout << "group=" << group << endl;
 
 693 cout << "credit=" << credit << endl;
 
 694 cout << "nextTariff=" << nextTariff << endl;
 
 695 cout << "userdata0" << userdata0 << endl;
 
 696 cout << "userdata1" << userdata1 << endl;
 
 697 cout << "creditExpire=" << creditExpire << endl;
 
 698 cout << "ips=" << ips << endl;
 
 699 cout << "------------------------" << endl;
 
 700 cout << "up=" << up << endl;
 
 701 cout << "down=" << down << endl;
 
 702 cout << "cash=" << cash << endl;
 
 703 cout << "freeMb=" << freeMb << endl;
 
 704 cout << "lastCashAdd=" << lastCashAdd << endl;
 
 705 cout << "lastCashAddTime=" << lastCashAddTime << endl;
 
 706 cout << "passiveTime=" << passiveTime << endl;
 
 707 cout << "lastActivityTime=" << lastActivityTime << endl;
 
 708 cout << "============================================================" << endl;
 
 710 //-----------------------------------------------------------------------------
 
 711 void USER_IMPL::Run()
 
 713 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 715 if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
 
 717     printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
 
 720 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
 
 722     WriteServLog("User: %s. Credit expired.", login.c_str());
 
 728 if (passive.ConstData()
 
 729     && (stgTime % 30 == 0)
 
 730     && (passiveTime.ModificationTime() != stgTime))
 
 732     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
 
 733     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
 
 736 if (!authorizedBy.empty())
 
 740         property.Stat().lastActivityTime = stgTime;
 
 742     if (!connected && IsInetable())
 
 746     if (connected && !IsInetable())
 
 749             Disconnect(false, "disabled");
 
 751             Disconnect(false, "passive");
 
 753             Disconnect(false, "no cash");
 
 756     if (stgTime - lastScanMessages > 10)
 
 759         lastScanMessages = stgTime;
 
 766         Disconnect(false, "not authorized");
 
 771 //-----------------------------------------------------------------------------
 
 772 void USER_IMPL::UpdatePingTime(time_t t)
 
 774 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 775 //printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
 
 781 //-----------------------------------------------------------------------------
 
 782 bool USER_IMPL::IsInetable()
 
 784 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 786 if (disabled || passive)
 
 789 if (settings->GetFreeMbAllowInet())
 
 795 if (settings->GetShowFeeInCash() || tariff == NULL)
 
 797     return (cash >= -credit);
 
 800 return (cash - tariff->GetFee() >= -credit);
 
 802 //-----------------------------------------------------------------------------
 
 803 string USER_IMPL::GetEnabledDirs()
 
 805 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 808 for(int i = 0; i < DIR_NUM; i++)
 
 809     dirs += enabledDirs[i] ? "1" : "0";
 
 812 //-----------------------------------------------------------------------------
 
 813 #ifdef TRAFF_STAT_WITH_PORTS
 
 814 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
 
 816 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
 
 819 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 821 if (!connected || tariff == NULL)
 
 827 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
 
 828 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
 
 832 int tt = tariff->GetTraffType();
 
 833 if (tt == TRAFF_UP ||
 
 834     tt == TRAFF_UP_DOWN ||
 
 835     // Check NEW traff data
 
 836     (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
 
 839     if (traff < threshold &&
 
 840         traff + len >= threshold)
 
 842         // cash = partBeforeThreshold * priceBeforeThreshold +
 
 843         //        partAfterThreshold * priceAfterThreshold
 
 844         int64_t before = threshold - traff; // Chunk part before threshold
 
 845         int64_t after = len - before; // Chunk part after threshold
 
 846         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
 
 847                                            down.ConstData()[dir],
 
 850              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
 
 851                                            down.ConstData()[dir],
 
 857         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
 
 858                                            down.ConstData()[dir],
 
 863     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
 
 865     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
 
 866         cost = dc - freeMb.ConstData();
 
 868     // Direct access to internal data structures via friend-specifier
 
 869     property.Stat().freeMb -= dc;
 
 870     property.Stat().cash -= cost;
 
 876 sessionUpload[dir] += len;
 
 880 if (!settings->GetWriteFreeMbTraffCost() &&
 
 881      freeMb.ConstData() >= 0)
 
 884 #ifdef TRAFF_STAT_WITH_PORTS
 
 885 IP_DIR_PAIR idp(ip, dir, port);
 
 887 IP_DIR_PAIR idp(ip, dir);
 
 890 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
 
 891 lb = traffStat.lower_bound(idp);
 
 892 if (lb == traffStat.end() || lb->first != idp)
 
 895                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
 
 896                                                   STAT_NODE(len, 0, cost)));
 
 900     lb->second.cash += cost;
 
 901     lb->second.up += len;
 
 904 //-----------------------------------------------------------------------------
 
 905 #ifdef TRAFF_STAT_WITH_PORTS
 
 906 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
 
 908 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
 
 911 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 913 if (!connected || tariff == NULL)
 
 919 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
 
 920 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
 
 924 int tt = tariff->GetTraffType();
 
 925 if (tt == TRAFF_DOWN ||
 
 926     tt == TRAFF_UP_DOWN ||
 
 927     // Check NEW traff data
 
 928     (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
 
 931     if (traff < threshold &&
 
 932         traff + len >= threshold)
 
 934         // cash = partBeforeThreshold * priceBeforeThreshold +
 
 935         //        partAfterThreshold * priceAfterThreshold
 
 936         int64_t before = threshold - traff; // Chunk part before threshold
 
 937         int64_t after = len - before; // Chunk part after threshold
 
 938         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
 
 939                                            down.ConstData()[dir], // Traff before chunk
 
 942              tariff->GetPriceWithTraffType(up.ConstData()[dir],
 
 943                                            dt[dir], // Traff after chunk
 
 949         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
 
 950                                            down.ConstData()[dir],
 
 955     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
 
 957     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
 
 958         cost = dc - freeMb.ConstData();
 
 960     property.Stat().freeMb -= dc;
 
 961     property.Stat().cash -= cost;
 
 967 sessionDownload[dir] += len;
 
 971 if (!settings->GetWriteFreeMbTraffCost() &&
 
 972      freeMb.ConstData() >= 0)
 
 975 #ifdef TRAFF_STAT_WITH_PORTS
 
 976 IP_DIR_PAIR idp(ip, dir, port);
 
 978 IP_DIR_PAIR idp(ip, dir);
 
 981 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
 
 982 lb = traffStat.lower_bound(idp);
 
 983 if (lb == traffStat.end() || lb->first != idp)
 
 986                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
 
 987                                                   STAT_NODE(0, len, cost)));
 
 991     lb->second.cash += cost;
 
 992     lb->second.down += len;
 
 995 //-----------------------------------------------------------------------------
 
 996 void USER_IMPL::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
 
 998 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
 999 currIP.AddBeforeNotifier(n);
 
1001 //-----------------------------------------------------------------------------
 
1002 void USER_IMPL::DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
 
1004 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1005 currIP.DelBeforeNotifier(n);
 
1007 //-----------------------------------------------------------------------------
 
1008 void USER_IMPL::AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
 
1010 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1011 currIP.AddAfterNotifier(n);
 
1013 //-----------------------------------------------------------------------------
 
1014 void USER_IMPL::DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
 
1016 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1017 currIP.DelAfterNotifier(n);
 
1019 //-----------------------------------------------------------------------------
 
1020 void USER_IMPL::AddConnectedBeforeNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
 
1022 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1023 connected.AddBeforeNotifier(n);
 
1025 //-----------------------------------------------------------------------------
 
1026 void USER_IMPL::DelConnectedBeforeNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
 
1028 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1029 connected.DelBeforeNotifier(n);
 
1031 //-----------------------------------------------------------------------------
 
1032 void USER_IMPL::AddConnectedAfterNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
 
1034 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1035 connected.AddAfterNotifier(n);
 
1037 //-----------------------------------------------------------------------------
 
1038 void USER_IMPL::DelConnectedAfterNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
 
1040 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1041 connected.DelAfterNotifier(n);
 
1043 //-----------------------------------------------------------------------------
 
1044 void USER_IMPL::OnAdd()
 
1046 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1048 string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
 
1050 if (access(scriptOnAdd.c_str(), X_OK) == 0)
 
1052     string scriptOnAddParams;
 
1053     strprintf(&scriptOnAddParams,
 
1055             scriptOnAdd.c_str(),
 
1058     ScriptExec(scriptOnAddParams.c_str());
 
1062     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
 
1065 //-----------------------------------------------------------------------------
 
1066 void USER_IMPL::OnDelete()
 
1068 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1070 string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
 
1072 if (access(scriptOnDel.c_str(), X_OK) == 0)
 
1074     string scriptOnDelParams;
 
1075     strprintf(&scriptOnDelParams,
 
1077             scriptOnDel.c_str(),
 
1080     ScriptExec(scriptOnDelParams.c_str());
 
1084     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
 
1089 //-----------------------------------------------------------------------------
 
1090 int USER_IMPL::WriteDetailStat(bool hard)
 
1092 printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
 
1094 if (!traffStatSaved.second.empty())
 
1096     if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
 
1098         printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
 
1099         WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
 
1100         WriteServLog("%s", store->GetStrError().c_str());
 
1103     traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
 
1109     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1113 printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
 
1115 if (ts.size() && !disabledDetailStat)
 
1117     if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
 
1119         printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
 
1120         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
 
1121         WriteServLog("%s", store->GetStrError().c_str());
 
1124             printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
 
1125             STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1126             traffStatSaved.second.swap(ts);
 
1127             traffStatSaved.first = lastWriteDetailedStat;
 
1132 lastWriteDetailedStat = stgTime;
 
1135 //-----------------------------------------------------------------------------
 
1136 double USER_IMPL::GetPassiveTimePart() const
 
1138 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1140 static int daysInMonth[12] =
 
1141 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
1145 localtime_r(&t, &tms);
 
1147 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
 
1149 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
 
1152     secMonth += 24 * 3600;
 
1155 int dt = secMonth - passiveTime;
 
1160 return double(dt) / (secMonth);
 
1162 //-----------------------------------------------------------------------------
 
1163 void USER_IMPL::SetPassiveTimeAsNewUser()
 
1165 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1169 localtime_r(&t, &tm);
 
1170 int daysCurrMon = DaysInCurrentMonth();
 
1171 double pt = (tm.tm_mday - 1) / (double)daysCurrMon;
 
1173 passiveTime = (time_t)(pt * 24 * 3600 * daysCurrMon);
 
1175 //-----------------------------------------------------------------------------
 
1176 void USER_IMPL::MidnightResetSessionStat()
 
1178 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1182     Disconnect(true, "fake");
 
1186 //-----------------------------------------------------------------------------
 
1187 void USER_IMPL::ProcessNewMonth()
 
1189 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1193     Disconnect(true, "fake");
 
1195 DIR_TRAFF zeroTarff;
 
1208 if (nextTariff.ConstData() != "")
 
1211     nt = tariffs->FindByName(nextTariff);
 
1214         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
 
1215                      login.c_str(), property.tariffName.Get().c_str());
 
1219         property.tariffName.Set(nextTariff, sysAdmin, login, store);
 
1226 //-----------------------------------------------------------------------------
 
1227 void USER_IMPL::ProcessDayFeeSpread()
 
1229 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1231 if (passive.ConstData() || tariff == NULL)
 
1234 double fee = tariff->GetFee() / DaysInCurrentMonth();
 
1240 switch (settings->GetFeeChargeType())
 
1243         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 
1246         if (c + credit >= 0)
 
1247             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 
1250         if (c + credit >= fee)
 
1251             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 
1256 //-----------------------------------------------------------------------------
 
1257 void USER_IMPL::ProcessDayFee()
 
1259 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1264 double passiveTimePart = 1.0;
 
1265 if (!settings->GetFullFee())
 
1267     passiveTimePart = GetPassiveTimePart();
 
1271     if (passive.ConstData())
 
1273         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
 
1277 double fee = tariff->GetFee() * passiveTimePart;
 
1288 printfd(__FILE__, "login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
 
1295 switch (settings->GetFeeChargeType())
 
1298         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 
1302         if (c + credit >= 0)
 
1304             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 
1309         if (c + credit >= fee)
 
1311             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
 
1317 //-----------------------------------------------------------------------------
 
1318 void USER_IMPL::SetPrepaidTraff()
 
1321     property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
 
1323 //-----------------------------------------------------------------------------
 
1324 int USER_IMPL::AddMessage(STG_MSG * msg)
 
1326 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
1328 if (SendMessage(*msg))
 
1330     if (store->AddMessage(msg, login))
 
1332         errorStr = store->GetStrError();
 
1333         WriteServLog("Error adding message: '%s'", errorStr.c_str());
 
1334         printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
 
1337     messages.push_back(*msg);
 
1341     if (msg->header.repeat > 0)
 
1343         msg->header.repeat--;
 
1345         //TODO: gcc v. 4.x generate ICE on x86_64
 
1346         msg->header.lastSendTime = time(NULL);
 
1348         msg->header.lastSendTime = stgTime;
 
1350         if (store->AddMessage(msg, login))
 
1352             errorStr = store->GetStrError();
 
1353             WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
 
1354             printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
 
1357         messages.push_back(*msg);
 
1362 //-----------------------------------------------------------------------------
 
1363 int USER_IMPL::SendMessage(STG_MSG & msg) const
 
1365 // No lock `cause we are already locked from caller
 
1367 set<const AUTH*>::iterator it(authorizedBy.begin());
 
1368 while (it != authorizedBy.end())
 
1370     if (!(*it++)->SendMessage(msg, currIP))
 
1376     //TODO: gcc v. 4.x generate ICE on x86_64
 
1377     msg.header.lastSendTime = time(NULL);
 
1379     msg.header.lastSendTime = stgTime;
 
1381     msg.header.repeat--;
 
1385 //-----------------------------------------------------------------------------
 
1386 void USER_IMPL::ScanMessage()
 
1388 // No lock `cause we are already locked from caller
 
1389 // We need not check for the authorizedBy `cause it has already checked by caller
 
1391 std::list<STG_MSG>::iterator it(messages.begin());
 
1392 while (it != messages.end())
 
1394     if (settings->GetMessageTimeout() > 0 &&
 
1395         difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
 
1398         if (store->DelMessage(it->header.id, login))
 
1400             WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
 
1401             printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
 
1403         messages.erase(it++);
 
1406     if (it->GetNextSendTime() <= stgTime)
 
1408         if (SendMessage(*it))
 
1410             // We need to check all messages in queue for timeout
 
1414         if (it->header.repeat < 0)
 
1416             if (store->DelMessage(it->header.id, login))
 
1418                 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
 
1419                 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
 
1421             messages.erase(it++);
 
1425             if (store->EditMessage(*it, login))
 
1427                 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
 
1428                 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
 
1439 //-----------------------------------------------------------------------------
 
1440 //-----------------------------------------------------------------------------
 
1441 //-----------------------------------------------------------------------------
 
1442 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
 
1444 if (newPassive && !oldPassive && user->tariff != NULL)
 
1445     user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
 
1451 //-----------------------------------------------------------------------------
 
1452 void CHG_TARIFF_NOTIFIER::Notify(const string &, const string & newTariff)
 
1454 if (user->settings->GetReconnectOnTariffChange() && user->connected)
 
1455     user->Disconnect(false, "Change tariff");
 
1456 user->tariff = user->tariffs->FindByName(newTariff);
 
1457 if (user->settings->GetReconnectOnTariffChange() &&
 
1458     !user->authorizedBy.empty() &&
 
1460     user->Connect(false);
 
1462 //-----------------------------------------------------------------------------
 
1463 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
 
1465 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
 
1466 user->lastCashAdd = newCash - oldCash;
 
1468 //-----------------------------------------------------------------------------
 
1469 void CHG_IPS_NOTIFIER::Notify(const USER_IPS & from, const USER_IPS & to)
 
1471     printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.GetIpStr().c_str(), to.GetIpStr().c_str());
 
1472     if (user->connected)
 
1473         user->Disconnect(false, "Change IP");
 
1474     if (!user->authorizedBy.empty() && user->IsInetable())
 
1475         user->Connect(false);
 
1477 //-----------------------------------------------------------------------------