]> git.stg.codes - stg.git/blob - projects/stargazer/user_impl.cpp
Fix build on Darwin.
[stg.git] / projects / stargazer / user_impl.cpp
1 /*
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.
6  *
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.
11  *
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
15  */
16
17 /*
18  *    Date: 27.10.2002
19  */
20
21 /*
22  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
23  */
24
25 /*
26  $Revision: 1.101 $
27  $Date: 2010/11/03 10:50:03 $
28  $Author: faust $
29  */
30
31 #ifndef _GNU_SOURCE
32 #define _GNU_SOURCE
33 #endif
34
35 #include "user_impl.h"
36 #include "settings_impl.h"
37 #include "stg_timer.h"
38
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"
47
48 #include <algorithm>
49 #include <functional>
50 #include <array>
51
52 #include <cassert>
53 #include <cstdlib>
54 #include <cmath>
55
56 #include <pthread.h>
57 #include <unistd.h> // access
58
59 using STG::UserImpl;
60
61 namespace
62 {
63
64 std::string dirsToString(const bool * dirs)
65 {
66 std::string res;
67 for (size_t i = 0; i < DIR_NUM; i++)
68     res += dirs[i] ? '1' : '0';
69 return res;
70 }
71
72 void dirsFromBits(bool * dirs, uint32_t bits)
73 {
74 for (size_t i = 0; i < DIR_NUM; i++)
75     dirs[i] = bits & (1 << i);
76 }
77
78 }
79
80 UserImpl::UserImpl(const Settings * s,
81            const Store * st,
82            const Tariffs * t,
83            const Admin * a,
84            const Users * u,
85            const Services & svcs)
86     : users(u),
87       properties(*s),
88       WriteServLog(Logger::get()),
89       lastScanMessages(0),
90       id(0),
91       lastIPForDisconnect(0),
92       pingTime(0),
93       sysAdmin(a),
94       store(st),
95       tariffs(t),
96       tariff(NULL),
97       m_services(svcs),
98       settings(s),
99       authorizedModificationTime(0),
100       deleted(false),
101       lastWriteStat(0),
102       lastWriteDetailedStat(0),
103       cash(properties.cash),
104       up(properties.up),
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),
126       ips(properties.ips),
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)
139 {
140     Init();
141 }
142 //-----------------------------------------------------------------------------
143 void UserImpl::Init()
144 {
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;
151
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); });
157
158 pthread_mutexattr_t attr;
159 pthread_mutexattr_init(&attr);
160 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
161 pthread_mutex_init(&mutex, &attr);
162 }
163 //-----------------------------------------------------------------------------
164 UserImpl::UserImpl(const UserImpl & u)
165     : users(u.users),
166       properties(*u.settings),
167       WriteServLog(Logger::get()),
168       lastScanMessages(0),
169       login(u.login),
170       id(u.id),
171       lastIPForDisconnect(0),
172       pingTime(u.pingTime),
173       sysAdmin(u.sysAdmin),
174       store(u.store),
175       tariffs(u.tariffs),
176       tariff(u.tariff),
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),
183       deleted(u.deleted),
184       lastWriteStat(u.lastWriteStat),
185       lastWriteDetailedStat(u.lastWriteDetailedStat),
186       cash(properties.cash),
187       up(properties.up),
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),
209       ips(properties.ips),
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),
220       sessionUpload(),
221       sessionDownload(),
222       sessionUploadModTime(stgTime),
223       sessionDownloadModTime(stgTime)
224 {
225     if (&u == this)
226         return;
227
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); });
233
234     properties.SetProperties(u.properties);
235
236     pthread_mutexattr_t attr;
237     pthread_mutexattr_init(&attr);
238     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
239     pthread_mutex_init(&mutex, &attr);
240 }
241 //-----------------------------------------------------------------------------
242 UserImpl::~UserImpl()
243 {
244 pthread_mutex_destroy(&mutex);
245 }
246 //-----------------------------------------------------------------------------
247 void UserImpl::SetLogin(const std::string & l)
248 {
249 STG_LOCKER lock(&mutex);
250 static int idGen = 0;
251 assert(login.empty() && "Login is already set");
252 login = l;
253 id = idGen++;
254 }
255 //-----------------------------------------------------------------------------
256 int UserImpl::ReadConf()
257 {
258 STG_LOCKER lock(&mutex);
259 UserConf conf;
260
261 if (store->RestoreUserConf(&conf, login))
262     {
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());
267     return -1;
268     }
269
270 properties.SetConf(conf);
271
272 tariff = tariffs->FindByName(tariffName);
273 if (tariff == NULL)
274     {
275     WriteServLog("Cannot read user %s. Tariff %s not exist.",
276                  login.c_str(), properties.tariffName.Get().c_str());
277     return -1;
278     }
279
280 std::vector<Message::Header> hdrsList;
281
282 if (store->GetMessageHdrs(&hdrsList, login))
283     {
284     printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
285     WriteServLog("Cannot read user %s. Error reading message headers: %s.",
286                  login.c_str(),
287                  store->GetStrError().c_str());
288     return -1;
289     }
290
291 std::vector<Message::Header>::const_iterator it;
292 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
293     {
294     Message msg;
295     if (store->GetMessage(it->id, &msg, login) == 0)
296         {
297         messages.push_back(msg);
298         }
299     }
300
301 return 0;
302 }
303 //-----------------------------------------------------------------------------
304 int UserImpl::ReadStat()
305 {
306 STG_LOCKER lock(&mutex);
307 UserStat stat;
308
309 if (store->RestoreUserStat(&stat, login))
310     {
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());
315     return -1;
316     }
317
318 properties.SetStat(stat);
319
320 return 0;
321 }
322 //-----------------------------------------------------------------------------
323 int UserImpl::WriteConf()
324 {
325 STG_LOCKER lock(&mutex);
326 UserConf conf(properties.GetConf());
327
328 printfd(__FILE__, "UserImpl::WriteConf()\n");
329
330 if (store->SaveUserConf(conf, login))
331     {
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());
336     return -1;
337     }
338
339 return 0;
340 }
341 //-----------------------------------------------------------------------------
342 int UserImpl::WriteStat()
343 {
344 STG_LOCKER lock(&mutex);
345 UserStat stat(properties.GetStat());
346
347 if (store->SaveUserStat(stat, login))
348     {
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());
353     return -1;
354     }
355
356 lastWriteStat = stgTime;
357
358 return 0;
359 }
360 //-----------------------------------------------------------------------------
361 int UserImpl::WriteMonthStat()
362 {
363 STG_LOCKER lock(&mutex);
364 time_t tt = stgTime - 3600;
365 struct tm t1;
366 localtime_r(&tt, &t1);
367
368 UserStat stat(properties.GetStat());
369 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
370     {
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());
375     return -1;
376     }
377
378 return 0;
379 }
380 //-----------------------------------------------------------------------------
381 int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth)
382 {
383 STG_LOCKER lock(&mutex);
384 /*
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
388  */
389
390 /*
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
393  * fixed in future.
394  */
395
396 /*
397  * Prevent double authorization by identical authorizers
398  */
399 if (authorizedBy.find(auth) != authorizedBy.end())
400     return 0;
401
402 if (!ip)
403     return -1;
404
405 dirsFromBits(enabledDirs, dirs);
406
407 if (!authorizedBy.empty())
408     {
409     if (m_currIP != ip)
410         {
411         // We are already authorized, but with different IP address
412         errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
413         return -1;
414         }
415
416     User * u = NULL;
417     if (!users->FindByIPIdx(ip, &u))
418         {
419         // Address presents in IP-index.
420         // If it's not our IP - report it.
421         if (u != this)
422             {
423             errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
424             return -1;
425             }
426         }
427     }
428 else
429     {
430     if (users->IsIPInIndex(ip))
431         {
432         // Address is already present in IP-index.
433         errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
434         return -1;
435         }
436
437     if (ips.ConstData().find(ip))
438         {
439         m_currIP = ip;
440         lastIPForDisconnect = m_currIP;
441         }
442     else
443         {
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;
446         return -1;
447         }
448     }
449
450 if (authorizedBy.empty())
451     authorizedModificationTime = stgTime;
452 authorizedBy.insert(auth);
453
454 ScanMessage();
455
456 return 0;
457 }
458 //-----------------------------------------------------------------------------
459 void UserImpl::Unauthorize(const Auth * auth, const std::string & reason)
460 {
461 STG_LOCKER lock(&mutex);
462 /*
463  *  Authorizer tries to unauthorize user, that was not authorized by it
464  */
465 if (!authorizedBy.erase(auth))
466     return;
467
468 authorizedModificationTime = stgTime;
469
470 if (authorizedBy.empty())
471     {
472     lastDisconnectReason = reason;
473     lastIPForDisconnect = m_currIP;
474     m_currIP = 0; // DelUser in traffcounter
475     if (m_connected)
476         Disconnect(false, "not authorized");
477     return;
478     }
479 }
480 //-----------------------------------------------------------------------------
481 bool UserImpl::IsAuthorizedBy(const Auth * auth) const
482 {
483 STG_LOCKER lock(&mutex);
484 // Is this user authorized by specified authorizer?
485 return authorizedBy.find(auth) != authorizedBy.end();
486 }
487 //-----------------------------------------------------------------------------
488 std::vector<std::string> UserImpl::GetAuthorizers() const
489 {
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(); });
493     return list;
494 }
495 //-----------------------------------------------------------------------------
496 void UserImpl::Connect(bool fakeConnect)
497 {
498 /*
499  * Connect user to Internet. This function is differ from Authorize() !!!
500  */
501
502 STG_LOCKER lock(&mutex);
503
504 if (!fakeConnect)
505     {
506     std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
507
508     if (access(scriptOnConnect.c_str(), X_OK) == 0)
509         {
510         std::string dirs = dirsToString(enabledDirs);
511
512         std::string scriptOnConnectParams;
513         strprintf(&scriptOnConnectParams,
514                   "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
515                   scriptOnConnect.c_str(),
516                   login.c_str(),
517                   inet_ntostring(m_currIP).c_str(),
518                   cash.ConstData(),
519                   id,
520                   dirs.c_str());
521
522         std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
523         while (it != settings->GetScriptParams().end())
524             {
525             scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
526             ++it;
527             }
528
529         ScriptExec(scriptOnConnectParams.c_str());
530         }
531     else
532         {
533         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
534         }
535
536     m_connected = true;
537     }
538
539 if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, m_currIP))
540     {
541     WriteServLog("Cannot write connect for user %s.", login.c_str());
542     WriteServLog("%s", store->GetStrError().c_str());
543     }
544
545 if (!fakeConnect)
546     lastIPForDisconnect = m_currIP;
547 }
548 //-----------------------------------------------------------------------------
549 void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason)
550 {
551 /*
552  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
553  */
554
555 STG_LOCKER lock(&mutex);
556
557 if (!lastIPForDisconnect)
558     {
559     printfd(__FILE__, "lastIPForDisconnect\n");
560     return;
561     }
562
563 if (!fakeDisconnect)
564     {
565     lastDisconnectReason = reason;
566     std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
567
568     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
569         {
570         std::string dirs = dirsToString(enabledDirs);
571
572         std::string scriptOnDisonnectParams;
573         strprintf(&scriptOnDisonnectParams,
574                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
575                 scriptOnDisonnect.c_str(),
576                 login.c_str(),
577                 inet_ntostring(lastIPForDisconnect).c_str(),
578                 cash.ConstData(),
579                 id,
580                 dirs.c_str());
581
582         std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
583         while (it != settings->GetScriptParams().end())
584             {
585             scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
586             ++it;
587             }
588
589         ScriptExec(scriptOnDisonnectParams.c_str());
590         }
591     else
592         {
593         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
594         }
595
596     m_connected = false;
597     }
598
599 std::string reasonMessage(reason);
600 if (!lastDisconnectReason.empty())
601     reasonMessage += ": " + lastDisconnectReason;
602
603 if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
604                                                                     cash, freeMb, reasonMessage))
605     {
606     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
607     WriteServLog("%s", store->GetStrError().c_str());
608     }
609
610 if (!fakeDisconnect)
611     lastIPForDisconnect = 0;
612
613 sessionUpload.reset();
614 sessionDownload.reset();
615 sessionUploadModTime = stgTime;
616 sessionDownloadModTime = stgTime;
617 }
618 //-----------------------------------------------------------------------------
619 void UserImpl::Run()
620 {
621 STG_LOCKER lock(&mutex);
622
623 if (stgTime > lastWriteStat + settings->GetStatWritePeriod())
624     {
625     printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str());
626     WriteStat();
627     }
628 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
629     {
630     WriteServLog("User: %s. Credit expired.", login.c_str());
631     credit = 0;
632     creditExpire = 0;
633     WriteConf();
634     }
635
636 if (passive.ConstData()
637     && (stgTime % 30 == 0)
638     && (passiveTime.ModificationTime() != stgTime))
639     {
640     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
641     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
642     }
643
644 if (!authorizedBy.empty())
645     {
646     if (m_connected)
647         properties.Stat().lastActivityTime = stgTime;
648
649     if (!m_connected && IsInetable())
650         Connect();
651
652     if (m_connected && !IsInetable())
653         {
654         if (disabled)
655             Disconnect(false, "disabled");
656         else if (passive)
657             Disconnect(false, "passive");
658         else
659             Disconnect(false, "no cash");
660         }
661
662     if (stgTime - lastScanMessages > 10)
663         {
664         ScanMessage();
665         lastScanMessages = stgTime;
666         }
667     }
668 else
669     {
670     if (m_connected)
671         Disconnect(false, "not authorized");
672     }
673
674 }
675 //-----------------------------------------------------------------------------
676 void UserImpl::UpdatePingTime(time_t t)
677 {
678 STG_LOCKER lock(&mutex);
679 if (t)
680     pingTime = t;
681 else
682     pingTime = stgTime;
683 }
684 //-----------------------------------------------------------------------------
685 bool UserImpl::IsInetable()
686 {
687 if (disabled || passive)
688     return false;
689
690 if (settings->GetFreeMbAllowInet())
691     {
692     if (freeMb >= 0)
693         return true;
694     }
695
696 if (settings->GetShowFeeInCash() || tariff == NULL)
697     return (cash >= -credit);
698
699 return (cash - tariff->GetFee() >= -credit);
700 }
701 //-----------------------------------------------------------------------------
702 std::string UserImpl::GetEnabledDirs() const
703 {
704 return dirsToString(enabledDirs);
705 }
706 //-----------------------------------------------------------------------------
707 #ifdef TRAFF_STAT_WITH_PORTS
708 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
709 #else
710 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
711 #endif
712 {
713 STG_LOCKER lock(&mutex);
714
715 if (!m_connected || tariff == NULL)
716     return;
717
718 double cost = 0;
719 DirTraff dt(up);
720
721 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
722 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
723
724 dt[dir] += len;
725
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]))
731     {
732     double dc = 0;
733     if (traff < threshold &&
734         traff + len >= threshold)
735         {
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],
742                                            dir,
743                                            stgTime) * before +
744              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
745                                            down.ConstData()[dir],
746                                            dir,
747                                            stgTime) * after;
748         }
749     else
750         {
751         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
752                                            down.ConstData()[dir],
753                                            dir,
754                                            stgTime) * len;
755         }
756
757     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
758         cost = dc;
759     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
760         cost = dc - freeMb.ConstData();
761
762     // Direct access to internal data structures via friend-specifier
763     properties.Stat().freeMb -= dc;
764     properties.Stat().cash -= cost;
765     cash.ModifyTime();
766     freeMb.ModifyTime();
767     }
768
769 up = dt;
770 sessionUpload[dir] += len;
771 sessionUploadModTime = stgTime;
772
773 //Add detailed stat
774
775 if (!settings->GetWriteFreeMbTraffCost() &&
776      freeMb.ConstData() >= 0)
777     cost = 0;
778
779 #ifdef TRAFF_STAT_WITH_PORTS
780 IPDirPair idp(ip, dir, port);
781 #else
782 IPDirPair idp(ip, dir);
783 #endif
784
785 std::map<IPDirPair, StatNode>::iterator lb;
786 lb = traffStat.lower_bound(idp);
787 if (lb == traffStat.end() || lb->first != idp)
788     {
789     traffStat.insert(lb,
790                      std::make_pair(idp,
791                                     StatNode(len, 0, cost)));
792     }
793 else
794     {
795     lb->second.cash += cost;
796     lb->second.up += len;
797     }
798 }
799 //-----------------------------------------------------------------------------
800 #ifdef TRAFF_STAT_WITH_PORTS
801 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
802 #else
803 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
804 #endif
805 {
806 STG_LOCKER lock(&mutex);
807
808 if (!m_connected || tariff == NULL)
809     return;
810
811 double cost = 0;
812 DirTraff dt(down);
813
814 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
815 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
816
817 dt[dir] += len;
818
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]))
824     {
825     double dc = 0;
826     if (traff < threshold &&
827         traff + len >= threshold)
828         {
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
835                                            dir,
836                                            stgTime) * before +
837              tariff->GetPriceWithTraffType(up.ConstData()[dir],
838                                            dt[dir], // Traff after chunk
839                                            dir,
840                                            stgTime) * after;
841         }
842     else
843         {
844         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
845                                            down.ConstData()[dir],
846                                            dir,
847                                            stgTime) * len;
848         }
849
850     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
851         cost = dc;
852     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
853         cost = dc - freeMb.ConstData();
854
855     properties.Stat().freeMb -= dc;
856     properties.Stat().cash -= cost;
857     cash.ModifyTime();
858     freeMb.ModifyTime();
859     }
860
861 down = dt;
862 sessionDownload[dir] += len;
863 sessionDownloadModTime = stgTime;
864
865 //Add detailed stat
866
867 if (!settings->GetWriteFreeMbTraffCost() &&
868      freeMb.ConstData() >= 0)
869     cost = 0;
870
871 #ifdef TRAFF_STAT_WITH_PORTS
872 IPDirPair idp(ip, dir, port);
873 #else
874 IPDirPair idp(ip, dir);
875 #endif
876
877 std::map<IPDirPair, StatNode>::iterator lb;
878 lb = traffStat.lower_bound(idp);
879 if (lb == traffStat.end() || lb->first != idp)
880     {
881     traffStat.insert(lb,
882                      std::make_pair(idp,
883                                     StatNode(0, len, cost)));
884     }
885 else
886     {
887     lb->second.cash += cost;
888     lb->second.down += len;
889     }
890 }
891 //-----------------------------------------------------------------------------
892 void UserImpl::OnAdd()
893 {
894 STG_LOCKER lock(&mutex);
895
896 std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
897
898 if (access(scriptOnAdd.c_str(), X_OK) == 0)
899     {
900     std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
901
902     ScriptExec(scriptOnAddParams.c_str());
903     }
904 else
905     {
906     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
907     }
908 }
909 //-----------------------------------------------------------------------------
910 void UserImpl::OnDelete()
911 {
912 STG_LOCKER lock(&mutex);
913
914 std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
915
916 if (access(scriptOnDel.c_str(), X_OK) == 0)
917     {
918     std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
919
920     ScriptExec(scriptOnDelParams.c_str());
921     }
922 else
923     {
924     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
925     }
926
927 Run();
928 }
929 //-----------------------------------------------------------------------------
930 int UserImpl::WriteDetailStat(bool hard)
931 {
932 printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
933
934 if (!traffStatSaved.second.empty())
935     {
936     if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
937         {
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());
941         return -1;
942         }
943     traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
944     }
945
946 TraffStat ts;
947
948     {
949     STG_LOCKER lock(&mutex);
950     ts.swap(traffStat);
951     }
952
953 printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size());
954
955 if (ts.size() && !disabledDetailStat)
956     {
957     if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
958         {
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());
962         if (!hard)
963             {
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;
968             }
969         return -1;
970         }
971     }
972 lastWriteDetailedStat = stgTime;
973 return 0;
974 }
975 //-----------------------------------------------------------------------------
976 double UserImpl::GetPassiveTimePart() const
977 {
978 STG_LOCKER lock(&mutex);
979
980 static const std::array<unsigned, 12> daysInMonth{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
981
982 struct tm tms;
983 time_t t = stgTime;
984 localtime_r(&t, &tms);
985
986 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
987
988 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
989     {
990     // Leap year
991     secMonth += 24 * 3600;
992     }
993
994 time_t dt = secMonth - passiveTime;
995
996 if (dt < 0)
997     dt = 0;
998
999 return static_cast<double>(dt) / secMonth;
1000 }
1001 //-----------------------------------------------------------------------------
1002 void UserImpl::SetPassiveTimeAsNewUser()
1003 {
1004 STG_LOCKER lock(&mutex);
1005
1006 time_t t = stgTime;
1007 struct tm tm;
1008 localtime_r(&t, &tm);
1009 int daysCurrMon = DaysInCurrentMonth();
1010 double pt = tm.tm_mday - 1;
1011 pt /= daysCurrMon;
1012
1013 passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
1014 }
1015 //-----------------------------------------------------------------------------
1016 void UserImpl::MidnightResetSessionStat()
1017 {
1018 STG_LOCKER lock(&mutex);
1019
1020 if (m_connected)
1021     {
1022     Disconnect(true, "fake");
1023     Connect(true);
1024     }
1025 }
1026 //-----------------------------------------------------------------------------
1027 void UserImpl::ProcessNewMonth()
1028 {
1029 STG_LOCKER lock(&mutex);
1030 //  Reset traff
1031 if (m_connected)
1032     Disconnect(true, "fake");
1033
1034 WriteMonthStat();
1035
1036 properties.Stat().monthUp.reset();
1037 properties.Stat().monthDown.reset();
1038
1039 if (m_connected)
1040     Connect(true);
1041
1042 //  Set new tariff
1043 if (nextTariff.ConstData() != "")
1044     {
1045     const Tariff * nt = tariffs->FindByName(nextTariff);
1046     if (nt == NULL)
1047         {
1048         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1049                      login.c_str(), properties.tariffName.Get().c_str());
1050         }
1051     else
1052         {
1053         std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime);
1054         if (message.empty())
1055             {
1056             properties.tariffName.Set(nextTariff, *sysAdmin, login, *store);
1057             }
1058         else
1059             {
1060             WriteServLog("Tariff change is prohibited for user %s. %s",
1061                          login.c_str(),
1062                          message.c_str());
1063             }
1064         }
1065     ResetNextTariff();
1066     WriteConf();
1067     }
1068 }
1069 //-----------------------------------------------------------------------------
1070 void UserImpl::ProcessDayFeeSpread()
1071 {
1072 STG_LOCKER lock(&mutex);
1073
1074 if (passive.ConstData() || tariff == NULL)
1075     return;
1076
1077 if (tariff->GetPeriod() != Tariff::MONTH)
1078     return;
1079
1080 double fee = tariff->GetFee() / DaysInCurrentMonth();
1081
1082 if (std::fabs(fee) < 1.0e-3)
1083     return;
1084
1085 double c = cash;
1086 switch (settings->GetFeeChargeType())
1087     {
1088     case 0:
1089         properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1090         break;
1091     case 1:
1092         if (c + credit >= 0)
1093             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1094         break;
1095     case 2:
1096         if (c + credit >= fee)
1097             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1098         break;
1099     case 3:
1100         if (c >= 0)
1101             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1102         break;
1103     }
1104 ResetPassiveTime();
1105 }
1106 //-----------------------------------------------------------------------------
1107 void UserImpl::ProcessDayFee()
1108 {
1109 STG_LOCKER lock(&mutex);
1110
1111 if (tariff == NULL)
1112     return;
1113
1114 if (tariff->GetPeriod() != Tariff::MONTH)
1115     return;
1116
1117 double passiveTimePart = 1.0;
1118 if (!settings->GetFullFee())
1119     {
1120     passiveTimePart = GetPassiveTimePart();
1121     }
1122 else
1123     {
1124     if (passive.ConstData())
1125         {
1126         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1127         return;
1128         }
1129     }
1130 double fee = tariff->GetFee() * passiveTimePart;
1131
1132 ResetPassiveTime();
1133
1134 if (std::fabs(fee) < 1.0e-3)
1135     {
1136     SetPrepaidTraff();
1137     return;
1138     }
1139
1140 double c = cash;
1141 printfd(__FILE__, "login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
1142         login.c_str(),
1143         cash.ConstData(),
1144         credit.ConstData(),
1145         tariff->GetFee(),
1146         passiveTimePart,
1147         fee);
1148 switch (settings->GetFeeChargeType())
1149     {
1150     case 0:
1151         properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1152         SetPrepaidTraff();
1153         break;
1154     case 1:
1155         if (c + credit >= 0)
1156             {
1157             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1158             SetPrepaidTraff();
1159             }
1160         break;
1161     case 2:
1162         if (c + credit >= fee)
1163             {
1164             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1165             SetPrepaidTraff();
1166             }
1167         break;
1168     case 3:
1169         if (c >= 0)
1170             {
1171             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1172             SetPrepaidTraff();
1173             }
1174         break;
1175     }
1176 }
1177 //-----------------------------------------------------------------------------
1178 void UserImpl::ProcessDailyFee()
1179 {
1180 STG_LOCKER lock(&mutex);
1181
1182 if (passive.ConstData() || tariff == NULL)
1183     return;
1184
1185 if (tariff->GetPeriod() != Tariff::DAY)
1186     return;
1187
1188 double fee = tariff->GetFee();
1189
1190 if (fee == 0.0)
1191     return;
1192
1193 double c = cash;
1194 switch (settings->GetFeeChargeType())
1195     {
1196     case 0:
1197         properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1198         break;
1199     case 1:
1200         if (c + credit >= 0)
1201             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1202         break;
1203     case 2:
1204         if (c + credit >= fee)
1205             properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1206         break;
1207     }
1208 ResetPassiveTime();
1209 }
1210 //-----------------------------------------------------------------------------
1211 void UserImpl::ProcessServices()
1212 {
1213 struct tm tms;
1214 time_t t = stgTime;
1215 localtime_r(&t, &tms);
1216
1217 double passiveTimePart = 1.0;
1218 if (!settings->GetFullFee())
1219     {
1220     passiveTimePart = GetPassiveTimePart();
1221     }
1222 else
1223     {
1224     if (passive.ConstData())
1225         {
1226         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1227         return;
1228         }
1229     }
1230
1231 for (size_t i = 0; i < properties.Conf().services.size(); ++i)
1232     {
1233     ServiceConf conf;
1234     if (m_services.Find(properties.Conf().services[i], &conf))
1235         continue;
1236     if (conf.payDay == tms.tm_mday ||
1237         (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
1238         {
1239         double c = cash;
1240         double fee = conf.cost * passiveTimePart;
1241         printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
1242                 login.c_str(),
1243                 cash.ConstData(),
1244                 credit.ConstData(),
1245                 tariff->GetFee(),
1246                 passiveTimePart,
1247                 fee);
1248         switch (settings->GetFeeChargeType())
1249             {
1250             case 0:
1251                 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1252                 SetPrepaidTraff();
1253                 break;
1254             case 1:
1255                 if (c + credit >= 0)
1256                     {
1257                     properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1258                     SetPrepaidTraff();
1259                     }
1260                 break;
1261             case 2:
1262                 if (c + credit >= fee)
1263                     {
1264                     properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1265                     SetPrepaidTraff();
1266                     }
1267                 break;
1268             case 3:
1269                 if (c >= 0)
1270                     {
1271                     properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1272                     SetPrepaidTraff();
1273                     }
1274                 break;
1275             }
1276         }
1277     }
1278 }
1279 //-----------------------------------------------------------------------------
1280 void UserImpl::SetPrepaidTraff()
1281 {
1282 if (tariff != NULL)
1283     properties.freeMb.Set(tariff->GetFree(), *sysAdmin, login, *store, "Prepaid traffic");
1284 }
1285 //-----------------------------------------------------------------------------
1286 int UserImpl::AddMessage(Message * msg)
1287 {
1288 STG_LOCKER lock(&mutex);
1289
1290 if (SendMessage(*msg))
1291     {
1292     if (store->AddMessage(msg, login))
1293         {
1294         errorStr = store->GetStrError();
1295         WriteServLog("Error adding message: '%s'", errorStr.c_str());
1296         printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1297         return -1;
1298         }
1299     messages.push_back(*msg);
1300     }
1301 else
1302     {
1303     if (msg->header.repeat > 0)
1304         {
1305         msg->header.repeat--;
1306         #ifndef DEBUG
1307         //TODO: gcc v. 4.x generate ICE on x86_64
1308         msg->header.lastSendTime = static_cast<int>(time(NULL));
1309         #else
1310         msg->header.lastSendTime = static_cast<int>(stgTime);
1311         #endif
1312         if (store->AddMessage(msg, login))
1313             {
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());
1317             return -1;
1318             }
1319         messages.push_back(*msg);
1320         }
1321     }
1322 return 0;
1323 }
1324 //-----------------------------------------------------------------------------
1325 int UserImpl::SendMessage(Message & msg) const
1326 {
1327 // No lock `cause we are already locked from caller
1328 int ret = -1;
1329 std::set<const Auth*>::iterator it(authorizedBy.begin());
1330 while (it != authorizedBy.end())
1331     {
1332     if (!(*it++)->SendMessage(msg, m_currIP))
1333         ret = 0;
1334     }
1335 if (!ret)
1336     {
1337 #ifndef DEBUG
1338     //TODO: gcc v. 4.x generate ICE on x86_64
1339     msg.header.lastSendTime = static_cast<int>(time(NULL));
1340 #else
1341     msg.header.lastSendTime = static_cast<int>(stgTime);
1342 #endif
1343     msg.header.repeat--;
1344     }
1345 return ret;
1346 }
1347 //-----------------------------------------------------------------------------
1348 void UserImpl::ScanMessage()
1349 {
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
1352
1353 auto it = messages.begin();
1354 while (it != messages.end())
1355     {
1356     if (settings->GetMessageTimeout() > 0 &&
1357         difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1358         {
1359         // Timeout exceeded
1360         if (store->DelMessage(it->header.id, login))
1361             {
1362             WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1363             printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1364             }
1365         messages.erase(it++);
1366         continue;
1367         }
1368     if (it->GetNextSendTime() <= stgTime)
1369         {
1370         if (SendMessage(*it))
1371             {
1372             // We need to check all messages in queue for timeout
1373             ++it;
1374             continue;
1375             }
1376         if (it->header.repeat < 0)
1377             {
1378             if (store->DelMessage(it->header.id, login))
1379                 {
1380                 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1381                 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1382                 }
1383             messages.erase(it++);
1384             }
1385         else
1386             {
1387             if (store->EditMessage(*it, login))
1388                 {
1389                 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1390                 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1391                 }
1392             ++it;
1393             }
1394         }
1395     else
1396         {
1397         ++it;
1398         }
1399     }
1400 }
1401 //-----------------------------------------------------------------------------
1402 std::string UserImpl::GetParamValue(const std::string & name) const
1403 {
1404     std::string lowerName = ToLower(name);
1405     if (lowerName == "id")
1406         {
1407         std::ostringstream stream;
1408         stream << id;
1409         return stream.str();
1410         }
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);
1417     else
1418         {
1419         WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
1420         return "";
1421         }
1422 }
1423 //-----------------------------------------------------------------------------
1424 //-----------------------------------------------------------------------------
1425 //-----------------------------------------------------------------------------
1426 void UserImpl::onPassiveChange(int oldVal, int newVal)
1427 {
1428     if (newVal && !oldVal && tariff != NULL)
1429         properties.cash.Set(cash - tariff->GetPassiveCost(),
1430                             *sysAdmin,
1431                             login,
1432                             *store,
1433                             "Freeze");
1434 }
1435 //-----------------------------------------------------------------------------
1436 void UserImpl::onDisabledChange(int oldVal, int newVal)
1437 {
1438     if (oldVal && !newVal && GetConnected())
1439         Disconnect(false, "disabled");
1440     else if (!oldVal && newVal && IsInetable())
1441         Connect(false);
1442 }
1443 //-----------------------------------------------------------------------------
1444 void UserImpl::onTariffChange(const std::string& /*oldVal*/, const std::string& newVal)
1445 {
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() &&
1452         IsInetable())
1453     {
1454         // This notifier gets called *before* changing the tariff, and in Connect we want to see new tariff name.
1455         properties.Conf().tariffName = newVal;
1456         Connect(false);
1457     }
1458 }
1459 //-----------------------------------------------------------------------------
1460 void UserImpl::onCashChange(double oldVal, double newVal)
1461 {
1462     time_t now = stgTime;
1463     lastCashAddTime = now;
1464     lastCashAdd = newVal - oldVal;
1465 }
1466 //-----------------------------------------------------------------------------
1467 void UserImpl::onIPChange(const UserIPs& oldVal, const UserIPs& newVal)
1468 {
1469     printfd(__FILE__, "Change IP from '%s' to '%s'\n", oldVal.toString().c_str(), newVal.toString().c_str());
1470     if (m_connected)
1471         Disconnect(false, "Change IP");
1472     if (!authorizedBy.empty() && IsInetable())
1473         Connect(false);
1474 }