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 $
35 #include "user_impl.h"
36 #include "settings_impl.h"
37 #include "stg_timer.h"
39 #include "stg/users.h"
40 #include "stg/common.h"
41 #include "stg/scriptexecuter.h"
42 #include "stg/tariff.h"
43 #include "stg/tariffs.h"
44 #include "stg/services.h"
45 #include "stg/service_conf.h"
46 #include "stg/admin.h"
57 #include <unistd.h> // access
64 std::string dirsToString(const bool * dirs)
67 for (size_t i = 0; i < DIR_NUM; i++)
68 res += dirs[i] ? '1' : '0';
72 void dirsFromBits(bool * dirs, uint32_t bits)
74 for (size_t i = 0; i < DIR_NUM; i++)
75 dirs[i] = bits & (1 << i);
80 UserImpl::UserImpl(const Settings * s,
85 const Services & svcs)
88 WriteServLog(Logger::get()),
91 lastIPForDisconnect(0),
99 authorizedModificationTime(0),
102 lastWriteDetailedStat(0),
103 cash(properties.cash),
105 down(properties.down),
106 lastCashAdd(properties.lastCashAdd),
107 passiveTime(properties.passiveTime),
108 lastCashAddTime(properties.lastCashAddTime),
109 freeMb(properties.freeMb),
110 lastActivityTime(properties.lastActivityTime),
111 password(properties.password),
112 passive(properties.passive),
113 disabled(properties.disabled),
114 disabledDetailStat(properties.disabledDetailStat),
115 alwaysOnline(properties.alwaysOnline),
116 tariffName(properties.tariffName),
117 nextTariff(properties.nextTariff),
118 address(properties.address),
119 note(properties.note),
120 group(properties.group),
121 email(properties.email),
122 phone(properties.phone),
123 realName(properties.realName),
124 credit(properties.credit),
125 creditExpire(properties.creditExpire),
127 userdata0(properties.userdata0),
128 userdata1(properties.userdata1),
129 userdata2(properties.userdata2),
130 userdata3(properties.userdata3),
131 userdata4(properties.userdata4),
132 userdata5(properties.userdata5),
133 userdata6(properties.userdata6),
134 userdata7(properties.userdata7),
135 userdata8(properties.userdata8),
136 userdata9(properties.userdata9),
137 sessionUploadModTime(stgTime),
138 sessionDownloadModTime(stgTime)
142 //-----------------------------------------------------------------------------
143 void UserImpl::Init()
145 password = "*_EMPTY_PASSWORD_*";
146 tariffName = NO_TARIFF_NAME;
147 tariff = tariffs->FindByName(tariffName);
148 ips = UserIPs::parse("*");
149 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
150 lastWriteDetailedStat = stgTime;
152 m_beforePassiveConn = properties.passive.beforeChange([this](auto oldVal, auto newVal){ onPassiveChange(oldVal, newVal); });
153 m_afterDisabledConn = properties.disabled.afterChange([this](auto oldVal, auto newVal){ onDisabledChange(oldVal, newVal); });
154 m_beforeTariffConn = properties.tariffName.beforeChange([this](const auto& oldVal, const auto& newVal){ onTariffChange(oldVal, newVal); });
155 m_beforeCashConn = properties.cash.beforeChange([this](auto oldVal, auto newVal){ onCashChange(oldVal, newVal); });
156 m_afterIPConn = ips.afterChange([this](const auto& oldVal, const auto& newVal){ onIPChange(oldVal, newVal); });
158 pthread_mutexattr_t attr;
159 pthread_mutexattr_init(&attr);
160 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
161 pthread_mutex_init(&mutex, &attr);
163 //-----------------------------------------------------------------------------
164 UserImpl::UserImpl(const UserImpl & u)
166 properties(*u.settings),
167 WriteServLog(Logger::get()),
171 lastIPForDisconnect(0),
172 pingTime(u.pingTime),
173 sysAdmin(u.sysAdmin),
177 m_services(u.m_services),
178 traffStat(u.traffStat),
179 traffStatSaved(u.traffStatSaved),
180 settings(u.settings),
181 authorizedModificationTime(u.authorizedModificationTime),
182 messages(u.messages),
184 lastWriteStat(u.lastWriteStat),
185 lastWriteDetailedStat(u.lastWriteDetailedStat),
186 cash(properties.cash),
188 down(properties.down),
189 lastCashAdd(properties.lastCashAdd),
190 passiveTime(properties.passiveTime),
191 lastCashAddTime(properties.lastCashAddTime),
192 freeMb(properties.freeMb),
193 lastActivityTime(properties.lastActivityTime),
194 password(properties.password),
195 passive(properties.passive),
196 disabled(properties.disabled),
197 disabledDetailStat(properties.disabledDetailStat),
198 alwaysOnline(properties.alwaysOnline),
199 tariffName(properties.tariffName),
200 nextTariff(properties.nextTariff),
201 address(properties.address),
202 note(properties.note),
203 group(properties.group),
204 email(properties.email),
205 phone(properties.phone),
206 realName(properties.realName),
207 credit(properties.credit),
208 creditExpire(properties.creditExpire),
210 userdata0(properties.userdata0),
211 userdata1(properties.userdata1),
212 userdata2(properties.userdata2),
213 userdata3(properties.userdata3),
214 userdata4(properties.userdata4),
215 userdata5(properties.userdata5),
216 userdata6(properties.userdata6),
217 userdata7(properties.userdata7),
218 userdata8(properties.userdata8),
219 userdata9(properties.userdata9),
222 sessionUploadModTime(stgTime),
223 sessionDownloadModTime(stgTime)
228 m_beforePassiveConn = properties.passive.beforeChange([this](auto oldVal, auto newVal){ onPassiveChange(oldVal, newVal); });
229 m_afterDisabledConn = properties.disabled.afterChange([this](auto oldVal, auto newVal){ onDisabledChange(oldVal, newVal); });
230 m_beforeTariffConn = properties.tariffName.beforeChange([this](const auto& oldVal, const auto& newVal){ onTariffChange(oldVal, newVal); });
231 m_beforeCashConn = properties.cash.beforeChange([this](auto oldVal, auto newVal){ onCashChange(oldVal, newVal); });
232 m_afterIPConn = ips.afterChange([this](const auto& oldVal, const auto& newVal){ onIPChange(oldVal, newVal); });
234 properties.SetProperties(u.properties);
236 pthread_mutexattr_t attr;
237 pthread_mutexattr_init(&attr);
238 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
239 pthread_mutex_init(&mutex, &attr);
241 //-----------------------------------------------------------------------------
242 UserImpl::~UserImpl()
244 pthread_mutex_destroy(&mutex);
246 //-----------------------------------------------------------------------------
247 void UserImpl::SetLogin(const std::string & l)
249 STG_LOCKER lock(&mutex);
250 static int idGen = 0;
251 assert(login.empty() && "Login is already set");
255 //-----------------------------------------------------------------------------
256 int UserImpl::ReadConf()
258 STG_LOCKER lock(&mutex);
261 if (store->RestoreUserConf(&conf, login))
263 WriteServLog("Cannot read conf for user %s.", login.c_str());
264 WriteServLog("%s", store->GetStrError().c_str());
265 printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
266 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
270 properties.SetConf(conf);
272 tariff = tariffs->FindByName(tariffName);
275 WriteServLog("Cannot read user %s. Tariff %s not exist.",
276 login.c_str(), properties.tariffName.Get().c_str());
280 std::vector<Message::Header> hdrsList;
282 if (store->GetMessageHdrs(&hdrsList, login))
284 printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
285 WriteServLog("Cannot read user %s. Error reading message headers: %s.",
287 store->GetStrError().c_str());
291 std::vector<Message::Header>::const_iterator it;
292 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
295 if (store->GetMessage(it->id, &msg, login) == 0)
297 messages.push_back(msg);
303 //-----------------------------------------------------------------------------
304 int UserImpl::ReadStat()
306 STG_LOCKER lock(&mutex);
309 if (store->RestoreUserStat(&stat, login))
311 WriteServLog("Cannot read stat for user %s.", login.c_str());
312 WriteServLog("%s", store->GetStrError().c_str());
313 printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
314 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
318 properties.SetStat(stat);
322 //-----------------------------------------------------------------------------
323 int UserImpl::WriteConf()
325 STG_LOCKER lock(&mutex);
326 UserConf conf(properties.GetConf());
328 printfd(__FILE__, "UserImpl::WriteConf()\n");
330 if (store->SaveUserConf(conf, login))
332 WriteServLog("Cannot write conf for user %s.", login.c_str());
333 WriteServLog("%s", store->GetStrError().c_str());
334 printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
335 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
341 //-----------------------------------------------------------------------------
342 int UserImpl::WriteStat()
344 STG_LOCKER lock(&mutex);
345 UserStat stat(properties.GetStat());
347 if (store->SaveUserStat(stat, login))
349 WriteServLog("Cannot write stat for user %s.", login.c_str());
350 WriteServLog("%s", store->GetStrError().c_str());
351 printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
352 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
356 lastWriteStat = stgTime;
360 //-----------------------------------------------------------------------------
361 int UserImpl::WriteMonthStat()
363 STG_LOCKER lock(&mutex);
364 time_t tt = stgTime - 3600;
366 localtime_r(&tt, &t1);
368 UserStat stat(properties.GetStat());
369 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
371 WriteServLog("Cannot write month stat for user %s.", login.c_str());
372 WriteServLog("%s", store->GetStrError().c_str());
373 printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
374 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
380 //-----------------------------------------------------------------------------
381 int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth)
383 STG_LOCKER lock(&mutex);
385 * Authorize user. It only means that user will be authorized. Nothing more.
386 * User can be connected or disconnected while authorized.
387 * Example: user is authorized but disconnected due to 0 money or blocking
391 * TODO: in fact "authorization" means allowing access to a service. What we
392 * call "authorization" here, int STG, is "authentication". So this should be
397 * Prevent double authorization by identical authorizers
399 if (authorizedBy.find(auth) != authorizedBy.end())
405 dirsFromBits(enabledDirs, dirs);
407 if (!authorizedBy.empty())
411 // We are already authorized, but with different IP address
412 errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
417 if (!users->FindByIPIdx(ip, &u))
419 // Address presents in IP-index.
420 // If it's not our IP - report it.
423 errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
430 if (users->IsIPInIndex(ip))
432 // Address is already present in IP-index.
433 errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
437 if (ips.ConstData().find(ip))
440 lastIPForDisconnect = m_currIP;
444 printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().toString().c_str());
445 errorStr = "IP address " + inet_ntostring(ip) + " does not belong to user " + login;
450 if (authorizedBy.empty())
451 authorizedModificationTime = stgTime;
452 authorizedBy.insert(auth);
458 //-----------------------------------------------------------------------------
459 void UserImpl::Unauthorize(const Auth * auth, const std::string & reason)
461 STG_LOCKER lock(&mutex);
463 * Authorizer tries to unauthorize user, that was not authorized by it
465 if (!authorizedBy.erase(auth))
468 authorizedModificationTime = stgTime;
470 if (authorizedBy.empty())
472 lastDisconnectReason = reason;
473 lastIPForDisconnect = m_currIP;
474 m_currIP = 0; // DelUser in traffcounter
476 Disconnect(false, "not authorized");
480 //-----------------------------------------------------------------------------
481 bool UserImpl::IsAuthorizedBy(const Auth * auth) const
483 STG_LOCKER lock(&mutex);
484 // Is this user authorized by specified authorizer?
485 return authorizedBy.find(auth) != authorizedBy.end();
487 //-----------------------------------------------------------------------------
488 std::vector<std::string> UserImpl::GetAuthorizers() const
490 STG_LOCKER lock(&mutex);
491 std::vector<std::string> list;
492 std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), [](const auto auth){ return auth->GetVersion(); });
495 //-----------------------------------------------------------------------------
496 void UserImpl::Connect(bool fakeConnect)
499 * Connect user to Internet. This function is differ from Authorize() !!!
502 STG_LOCKER lock(&mutex);
506 std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
508 if (access(scriptOnConnect.c_str(), X_OK) == 0)
510 std::string dirs = dirsToString(enabledDirs);
512 std::string scriptOnConnectParams;
513 strprintf(&scriptOnConnectParams,
514 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
515 scriptOnConnect.c_str(),
517 inet_ntostring(m_currIP).c_str(),
522 std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
523 while (it != settings->GetScriptParams().end())
525 scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
529 ScriptExec(scriptOnConnectParams.c_str());
533 WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
539 if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, m_currIP))
541 WriteServLog("Cannot write connect for user %s.", login.c_str());
542 WriteServLog("%s", store->GetStrError().c_str());
546 lastIPForDisconnect = m_currIP;
548 //-----------------------------------------------------------------------------
549 void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason)
552 * Disconnect user from Internet. This function is differ from UnAuthorize() !!!
555 STG_LOCKER lock(&mutex);
557 if (!lastIPForDisconnect)
559 printfd(__FILE__, "lastIPForDisconnect\n");
565 lastDisconnectReason = reason;
566 std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
568 if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
570 std::string dirs = dirsToString(enabledDirs);
572 std::string scriptOnDisonnectParams;
573 strprintf(&scriptOnDisonnectParams,
574 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
575 scriptOnDisonnect.c_str(),
577 inet_ntostring(lastIPForDisconnect).c_str(),
582 std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
583 while (it != settings->GetScriptParams().end())
585 scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
589 ScriptExec(scriptOnDisonnectParams.c_str());
593 WriteServLog("Script OnDisconnect cannot be executed. File not found.");
599 std::string reasonMessage(reason);
600 if (!lastDisconnectReason.empty())
601 reasonMessage += ": " + lastDisconnectReason;
603 if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
604 cash, freeMb, reasonMessage))
606 WriteServLog("Cannot write disconnect for user %s.", login.c_str());
607 WriteServLog("%s", store->GetStrError().c_str());
611 lastIPForDisconnect = 0;
613 sessionUpload.reset();
614 sessionDownload.reset();
615 sessionUploadModTime = stgTime;
616 sessionDownloadModTime = stgTime;
618 //-----------------------------------------------------------------------------
621 STG_LOCKER lock(&mutex);
623 if (stgTime > lastWriteStat + settings->GetStatWritePeriod())
625 printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str());
628 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
630 WriteServLog("User: %s. Credit expired.", login.c_str());
636 if (passive.ConstData()
637 && (stgTime % 30 == 0)
638 && (passiveTime.ModificationTime() != stgTime))
640 passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
641 printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
644 if (!authorizedBy.empty())
647 properties.Stat().lastActivityTime = stgTime;
649 if (!m_connected && IsInetable())
652 if (m_connected && !IsInetable())
655 Disconnect(false, "disabled");
657 Disconnect(false, "passive");
659 Disconnect(false, "no cash");
662 if (stgTime - lastScanMessages > 10)
665 lastScanMessages = stgTime;
671 Disconnect(false, "not authorized");
675 //-----------------------------------------------------------------------------
676 void UserImpl::UpdatePingTime(time_t t)
678 STG_LOCKER lock(&mutex);
684 //-----------------------------------------------------------------------------
685 bool UserImpl::IsInetable()
687 if (disabled || passive)
690 if (settings->GetFreeMbAllowInet())
696 if (settings->GetShowFeeInCash() || tariff == NULL)
697 return (cash >= -credit);
699 return (cash - tariff->GetFee() >= -credit);
701 //-----------------------------------------------------------------------------
702 std::string UserImpl::GetEnabledDirs() const
704 return dirsToString(enabledDirs);
706 //-----------------------------------------------------------------------------
707 #ifdef TRAFF_STAT_WITH_PORTS
708 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
710 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
713 STG_LOCKER lock(&mutex);
715 if (!m_connected || tariff == NULL)
721 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
722 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
726 int tt = tariff->GetTraffType();
727 if (tt == Tariff::TRAFF_UP ||
728 tt == Tariff::TRAFF_UP_DOWN ||
729 // Check NEW traff data
730 (tt == Tariff::TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
733 if (traff < threshold &&
734 traff + len >= threshold)
736 // cash = partBeforeThreshold * priceBeforeThreshold +
737 // partAfterThreshold * priceAfterThreshold
738 int64_t before = threshold - traff; // Chunk part before threshold
739 int64_t after = len - before; // Chunk part after threshold
740 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
741 down.ConstData()[dir],
744 tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
745 down.ConstData()[dir],
751 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
752 down.ConstData()[dir],
757 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
759 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
760 cost = dc - freeMb.ConstData();
762 // Direct access to internal data structures via friend-specifier
763 properties.Stat().freeMb -= dc;
764 properties.Stat().cash -= cost;
770 sessionUpload[dir] += len;
771 sessionUploadModTime = stgTime;
775 if (!settings->GetWriteFreeMbTraffCost() &&
776 freeMb.ConstData() >= 0)
779 #ifdef TRAFF_STAT_WITH_PORTS
780 IPDirPair idp(ip, dir, port);
782 IPDirPair idp(ip, dir);
785 std::map<IPDirPair, StatNode>::iterator lb;
786 lb = traffStat.lower_bound(idp);
787 if (lb == traffStat.end() || lb->first != idp)
791 StatNode(len, 0, cost)));
795 lb->second.cash += cost;
796 lb->second.up += len;
799 //-----------------------------------------------------------------------------
800 #ifdef TRAFF_STAT_WITH_PORTS
801 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
803 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
806 STG_LOCKER lock(&mutex);
808 if (!m_connected || tariff == NULL)
814 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
815 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
819 int tt = tariff->GetTraffType();
820 if (tt == Tariff::TRAFF_DOWN ||
821 tt == Tariff::TRAFF_UP_DOWN ||
822 // Check NEW traff data
823 (tt == Tariff::TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
826 if (traff < threshold &&
827 traff + len >= threshold)
829 // cash = partBeforeThreshold * priceBeforeThreshold +
830 // partAfterThreshold * priceAfterThreshold
831 int64_t before = threshold - traff; // Chunk part before threshold
832 int64_t after = len - before; // Chunk part after threshold
833 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
834 down.ConstData()[dir], // Traff before chunk
837 tariff->GetPriceWithTraffType(up.ConstData()[dir],
838 dt[dir], // Traff after chunk
844 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
845 down.ConstData()[dir],
850 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
852 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
853 cost = dc - freeMb.ConstData();
855 properties.Stat().freeMb -= dc;
856 properties.Stat().cash -= cost;
862 sessionDownload[dir] += len;
863 sessionDownloadModTime = stgTime;
867 if (!settings->GetWriteFreeMbTraffCost() &&
868 freeMb.ConstData() >= 0)
871 #ifdef TRAFF_STAT_WITH_PORTS
872 IPDirPair idp(ip, dir, port);
874 IPDirPair idp(ip, dir);
877 std::map<IPDirPair, StatNode>::iterator lb;
878 lb = traffStat.lower_bound(idp);
879 if (lb == traffStat.end() || lb->first != idp)
883 StatNode(0, len, cost)));
887 lb->second.cash += cost;
888 lb->second.down += len;
891 //-----------------------------------------------------------------------------
892 void UserImpl::OnAdd()
894 STG_LOCKER lock(&mutex);
896 std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
898 if (access(scriptOnAdd.c_str(), X_OK) == 0)
900 std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
902 ScriptExec(scriptOnAddParams.c_str());
906 WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
909 //-----------------------------------------------------------------------------
910 void UserImpl::OnDelete()
912 STG_LOCKER lock(&mutex);
914 std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
916 if (access(scriptOnDel.c_str(), X_OK) == 0)
918 std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
920 ScriptExec(scriptOnDelParams.c_str());
924 WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
929 //-----------------------------------------------------------------------------
930 int UserImpl::WriteDetailStat(bool hard)
932 printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
934 if (!traffStatSaved.second.empty())
936 if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
938 printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write detail stat from queue\n");
939 WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
940 WriteServLog("%s", store->GetStrError().c_str());
943 traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
949 STG_LOCKER lock(&mutex);
953 printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size());
955 if (ts.size() && !disabledDetailStat)
957 if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
959 printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write current detail stat\n");
960 WriteServLog("Cannot write detail stat for user %s.", login.c_str());
961 WriteServLog("%s", store->GetStrError().c_str());
964 printfd(__FILE__, "UserImpl::WriteDetailStat() - pushing detail stat to queue\n");
965 STG_LOCKER lock(&mutex);
966 traffStatSaved.second.swap(ts);
967 traffStatSaved.first = lastWriteDetailedStat;
972 lastWriteDetailedStat = stgTime;
975 //-----------------------------------------------------------------------------
976 double UserImpl::GetPassiveTimePart() const
978 STG_LOCKER lock(&mutex);
980 static const std::array<unsigned, 12> daysInMonth{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
984 localtime_r(&t, &tms);
986 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
988 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
991 secMonth += 24 * 3600;
994 time_t dt = secMonth - passiveTime;
999 return static_cast<double>(dt) / secMonth;
1001 //-----------------------------------------------------------------------------
1002 void UserImpl::SetPassiveTimeAsNewUser()
1004 STG_LOCKER lock(&mutex);
1008 localtime_r(&t, &tm);
1009 int daysCurrMon = DaysInCurrentMonth();
1010 double pt = tm.tm_mday - 1;
1013 passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
1015 //-----------------------------------------------------------------------------
1016 void UserImpl::MidnightResetSessionStat()
1018 STG_LOCKER lock(&mutex);
1022 Disconnect(true, "fake");
1026 //-----------------------------------------------------------------------------
1027 void UserImpl::ProcessNewMonth()
1029 STG_LOCKER lock(&mutex);
1032 Disconnect(true, "fake");
1036 properties.Stat().monthUp.reset();
1037 properties.Stat().monthDown.reset();
1043 if (nextTariff.ConstData() != "")
1045 const Tariff * nt = tariffs->FindByName(nextTariff);
1048 WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1049 login.c_str(), properties.tariffName.Get().c_str());
1053 std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime);
1054 if (message.empty())
1056 properties.tariffName.Set(nextTariff, *sysAdmin, login, *store);
1060 WriteServLog("Tariff change is prohibited for user %s. %s",
1069 //-----------------------------------------------------------------------------
1070 void UserImpl::ProcessDayFeeSpread()
1072 STG_LOCKER lock(&mutex);
1074 if (passive.ConstData() || tariff == NULL)
1077 if (tariff->GetPeriod() != Tariff::MONTH)
1080 double fee = tariff->GetFee() / DaysInCurrentMonth();
1082 if (std::fabs(fee) < 1.0e-3)
1086 switch (settings->GetFeeChargeType())
1089 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1092 if (c + credit >= 0)
1093 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1096 if (c + credit >= fee)
1097 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1101 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1106 //-----------------------------------------------------------------------------
1107 void UserImpl::ProcessDayFee()
1109 STG_LOCKER lock(&mutex);
1114 if (tariff->GetPeriod() != Tariff::MONTH)
1117 double passiveTimePart = 1.0;
1118 if (!settings->GetFullFee())
1120 passiveTimePart = GetPassiveTimePart();
1124 if (passive.ConstData())
1126 printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1130 double fee = tariff->GetFee() * passiveTimePart;
1134 if (std::fabs(fee) < 1.0e-3)
1141 printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
1148 switch (settings->GetFeeChargeType())
1151 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1155 if (c + credit >= 0)
1157 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1162 if (c + credit >= fee)
1164 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1171 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1177 //-----------------------------------------------------------------------------
1178 void UserImpl::ProcessDailyFee()
1180 STG_LOCKER lock(&mutex);
1182 if (passive.ConstData() || tariff == NULL)
1185 if (tariff->GetPeriod() != Tariff::DAY)
1188 double fee = tariff->GetFee();
1194 switch (settings->GetFeeChargeType())
1197 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1200 if (c + credit >= 0)
1201 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1204 if (c + credit >= fee)
1205 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1210 //-----------------------------------------------------------------------------
1211 void UserImpl::ProcessServices()
1215 localtime_r(&t, &tms);
1217 double passiveTimePart = 1.0;
1218 if (!settings->GetFullFee())
1220 passiveTimePart = GetPassiveTimePart();
1224 if (passive.ConstData())
1226 printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1231 for (size_t i = 0; i < properties.Conf().services.size(); ++i)
1234 if (m_services.Find(properties.Conf().services[i], &conf))
1236 if (conf.payDay == tms.tm_mday ||
1237 (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
1240 double fee = conf.cost * passiveTimePart;
1241 printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
1248 switch (settings->GetFeeChargeType())
1251 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1255 if (c + credit >= 0)
1257 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1262 if (c + credit >= fee)
1264 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1271 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1279 //-----------------------------------------------------------------------------
1280 void UserImpl::SetPrepaidTraff()
1283 properties.freeMb.Set(tariff->GetFree(), *sysAdmin, login, *store, "Prepaid traffic");
1285 //-----------------------------------------------------------------------------
1286 int UserImpl::AddMessage(Message * msg)
1288 STG_LOCKER lock(&mutex);
1290 if (SendMessage(*msg))
1292 if (store->AddMessage(msg, login))
1294 errorStr = store->GetStrError();
1295 WriteServLog("Error adding message: '%s'", errorStr.c_str());
1296 printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1299 messages.push_back(*msg);
1303 if (msg->header.repeat > 0)
1305 msg->header.repeat--;
1307 //TODO: gcc v. 4.x generate ICE on x86_64
1308 msg->header.lastSendTime = static_cast<int>(time(NULL));
1310 msg->header.lastSendTime = static_cast<int>(stgTime);
1312 if (store->AddMessage(msg, login))
1314 errorStr = store->GetStrError();
1315 WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1316 printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1319 messages.push_back(*msg);
1324 //-----------------------------------------------------------------------------
1325 int UserImpl::SendMessage(Message & msg) const
1327 // No lock `cause we are already locked from caller
1329 std::set<const Auth*>::iterator it(authorizedBy.begin());
1330 while (it != authorizedBy.end())
1332 if (!(*it++)->SendMessage(msg, m_currIP))
1338 //TODO: gcc v. 4.x generate ICE on x86_64
1339 msg.header.lastSendTime = static_cast<int>(time(NULL));
1341 msg.header.lastSendTime = static_cast<int>(stgTime);
1343 msg.header.repeat--;
1347 //-----------------------------------------------------------------------------
1348 void UserImpl::ScanMessage()
1350 // No lock `cause we are already locked from caller
1351 // We need not check for the authorizedBy `cause it has already checked by caller
1353 auto it = messages.begin();
1354 while (it != messages.end())
1356 if (settings->GetMessageTimeout() > 0 &&
1357 difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1360 if (store->DelMessage(it->header.id, login))
1362 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1363 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1365 messages.erase(it++);
1368 if (it->GetNextSendTime() <= stgTime)
1370 if (SendMessage(*it))
1372 // We need to check all messages in queue for timeout
1376 if (it->header.repeat < 0)
1378 if (store->DelMessage(it->header.id, login))
1380 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1381 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1383 messages.erase(it++);
1387 if (store->EditMessage(*it, login))
1389 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1390 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1401 //-----------------------------------------------------------------------------
1402 std::string UserImpl::GetParamValue(const std::string & name) const
1404 std::string lowerName = ToLower(name);
1405 if (lowerName == "id")
1407 std::ostringstream stream;
1409 return stream.str();
1411 if (lowerName == "login") return login;
1412 if (lowerName == "currip") return m_currIP.ToString();
1413 if (lowerName == "enableddirs") return GetEnabledDirs();
1414 if (lowerName == "tariff") return properties.tariffName;
1415 if (properties.Exists(lowerName))
1416 return properties.GetPropertyValue(lowerName);
1419 WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
1423 //-----------------------------------------------------------------------------
1424 //-----------------------------------------------------------------------------
1425 //-----------------------------------------------------------------------------
1426 void UserImpl::onPassiveChange(int oldVal, int newVal)
1428 if (newVal && !oldVal && tariff != NULL)
1429 properties.cash.Set(cash - tariff->GetPassiveCost(),
1435 //-----------------------------------------------------------------------------
1436 void UserImpl::onDisabledChange(int oldVal, int newVal)
1438 if (oldVal && !newVal && GetConnected())
1439 Disconnect(false, "disabled");
1440 else if (!oldVal && newVal && IsInetable())
1443 //-----------------------------------------------------------------------------
1444 void UserImpl::onTariffChange(const std::string& /*oldVal*/, const std::string& newVal)
1446 STG_LOCKER lock(&mutex);
1447 if (settings->GetReconnectOnTariffChange() && m_connected)
1448 Disconnect(false, "Change tariff");
1449 tariff = tariffs->FindByName(newVal);
1450 if (settings->GetReconnectOnTariffChange() &&
1451 !authorizedBy.empty() &&
1454 // This notifier gets called *before* changing the tariff, and in Connect we want to see new tariff name.
1455 properties.Conf().tariffName = newVal;
1459 //-----------------------------------------------------------------------------
1460 void UserImpl::onCashChange(double oldVal, double newVal)
1462 time_t now = stgTime;
1463 lastCashAddTime = now;
1464 lastCashAdd = newVal - oldVal;
1466 //-----------------------------------------------------------------------------
1467 void UserImpl::onIPChange(const UserIPs& oldVal, const UserIPs& newVal)
1469 printfd(__FILE__, "Change IP from '%s' to '%s'\n", oldVal.toString().c_str(), newVal.toString().c_str());
1471 Disconnect(false, "Change IP");
1472 if (!authorizedBy.empty() && IsInetable())