]> git.stg.codes - stg.git/blob - projects/stargazer/user_impl.cpp
2b64ccc7062df4d94279f2510b3948191a7a785d
[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 <pthread.h>
36 #include <unistd.h> // access
37
38 #include <cassert>
39 #include <cstdlib>
40
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"
50
51 #ifdef USE_ABSTRACT_SETTINGS
52 USER_IMPL::USER_IMPL(const SETTINGS * s,
53            const STORE * st,
54            const TARIFFS * t,
55            const ADMIN * a,
56            const USERS * u)
57     : users(u),
58       property(s->GetScriptsDir()),
59       WriteServLog(GetStgLogger()),
60       login(),
61       id(0),
62       __connected(0),
63       connected(__connected),
64       userIDGenerator(),
65       __currIP(0),
66       currIP(__currIP),
67       lastIPForDisconnect(0),
68       pingTime(0),
69       sysAdmin(a),
70       store(st),
71       tariffs(t),
72       tariff(NULL),
73       cash(property.cash),
74       up(property.up),
75       down(property.down),
76       lastCashAdd(property.lastCashAdd),
77       passiveTime(property.passiveTime),
78       lastCashAddTime(property.lastCashAddTime),
79       freeMb(property.freeMb),
80       lastActivityTime(property.lastActivityTime),
81       password(property.password),
82       passive(property.passive),
83       disabled(property.disabled),
84       disabledDetailStat(property.disabledDetailStat),
85       alwaysOnline(property.alwaysOnline),
86       tariffName(property.tariffName),
87       nextTariff(property.nextTariff),
88       address(property.address),
89       note(property.note),
90       group(property.group),
91       email(property.email),
92       phone(property.phone),
93       realName(property.realName),
94       credit(property.credit),
95       creditExpire(property.creditExpire),
96       ips(property.ips),
97       userdata0(property.userdata0),
98       userdata1(property.userdata1),
99       userdata2(property.userdata2),
100       userdata3(property.userdata3),
101       userdata4(property.userdata4),
102       userdata5(property.userdata5),
103       userdata6(property.userdata6),
104       userdata7(property.userdata7),
105       userdata8(property.userdata8),
106       userdata9(property.userdata9),
107       passiveNotifier(this),
108       tariffNotifier(this),
109       cashNotifier(this),
110       ipNotifier(this)
111 {
112 settings = s;
113
114 password = "*_EMPTY_PASSWORD_*";
115 tariffName = NO_TARIFF_NAME;
116 connected = 0;
117 ips = StrToIPS("*");
118 deleted = false;
119 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
120 lastWriteDetailedStat = stgTime;
121
122 property.tariffName.AddBeforeNotifier(&tariffNotifier);
123 property.passive.AddBeforeNotifier(&passiveNotifier);
124 property.cash.AddBeforeNotifier(&cashNotifier);
125 ips.AddAfterNotifier(&ipNotifier);
126
127 lastScanMessages = 0;
128
129 pthread_mutexattr_t attr;
130 pthread_mutexattr_init(&attr);
131 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
132 pthread_mutex_init(&mutex, &attr);
133 }
134 #else
135 USER_IMPL::USER_IMPL(const SETTINGS_IMPL * s,
136            const STORE * st,
137            const TARIFFS * t,
138            const ADMIN * a,
139            const USERS * u)
140     : users(u),
141       property(s->GetScriptsDir()),
142       WriteServLog(GetStgLogger()),
143       login(),
144       id(0),
145       __connected(0),
146       connected(__connected),
147       userIDGenerator(),
148       __currIP(0),
149       currIP(__currIP),
150       lastIPForDisconnect(0),
151       pingTime(0),
152       sysAdmin(a),
153       store(st),
154       tariffs(t),
155       tariff(NULL),
156       cash(property.cash),
157       up(property.up),
158       down(property.down),
159       lastCashAdd(property.lastCashAdd),
160       passiveTime(property.passiveTime),
161       lastCashAddTime(property.lastCashAddTime),
162       freeMb(property.freeMb),
163       lastActivityTime(property.lastActivityTime),
164       password(property.password),
165       passive(property.passive),
166       disabled(property.disabled),
167       disabledDetailStat(property.disabledDetailStat),
168       alwaysOnline(property.alwaysOnline),
169       tariffName(property.tariffName),
170       nextTariff(property.nextTariff),
171       address(property.address),
172       note(property.note),
173       group(property.group),
174       email(property.email),
175       phone(property.phone),
176       realName(property.realName),
177       credit(property.credit),
178       creditExpire(property.creditExpire),
179       ips(property.ips),
180       userdata0(property.userdata0),
181       userdata1(property.userdata1),
182       userdata2(property.userdata2),
183       userdata3(property.userdata3),
184       userdata4(property.userdata4),
185       userdata5(property.userdata5),
186       userdata6(property.userdata6),
187       userdata7(property.userdata7),
188       userdata8(property.userdata8),
189       userdata9(property.userdata9),
190       passiveNotifier(this),
191       tariffNotifier(this),
192       cashNotifier(this),
193       ipNotifier(this)
194 {
195 settings = s;
196
197 password = "*_EMPTY_PASSWORD_*";
198 tariffName = NO_TARIFF_NAME;
199 connected = 0;
200 ips = StrToIPS("*");
201 deleted = false;
202 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
203 lastWriteDetailedStat = stgTime;
204
205 property.tariffName.AddBeforeNotifier(&tariffNotifier);
206 property.passive.AddBeforeNotifier(&passiveNotifier);
207 property.cash.AddBeforeNotifier(&cashNotifier);
208 ips.AddAfterNotifier(&ipNotifier);
209
210 lastScanMessages = 0;
211
212 pthread_mutexattr_t attr;
213 pthread_mutexattr_init(&attr);
214 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
215 pthread_mutex_init(&mutex, &attr);
216 }
217 #endif
218 //-----------------------------------------------------------------------------
219 USER_IMPL::USER_IMPL(const USER_IMPL & u)
220     : users(u.users),
221       property(u.settings->GetScriptsDir()),
222       WriteServLog(GetStgLogger()),
223       login(u.login),
224       id(u.id),
225       __connected(u.__connected),
226       connected(__connected),
227       __currIP(u.__currIP),
228       currIP(__currIP),
229       lastIPForDisconnect(0),
230       pingTime(u.pingTime),
231       sysAdmin(u.sysAdmin),
232       store(u.store),
233       tariffs(u.tariffs),
234       tariff(u.tariff),
235       cash(property.cash),
236       up(property.up),
237       down(property.down),
238       lastCashAdd(property.lastCashAdd),
239       passiveTime(property.passiveTime),
240       lastCashAddTime(property.lastCashAddTime),
241       freeMb(property.freeMb),
242       lastActivityTime(property.lastActivityTime),
243       password(property.password),
244       passive(property.passive),
245       disabled(property.disabled),
246       disabledDetailStat(property.disabledDetailStat),
247       alwaysOnline(property.alwaysOnline),
248       tariffName(property.tariffName),
249       nextTariff(property.nextTariff),
250       address(property.address),
251       note(property.note),
252       group(property.group),
253       email(property.email),
254       phone(property.phone),
255       realName(property.realName),
256       credit(property.credit),
257       creditExpire(property.creditExpire),
258       ips(property.ips),
259       userdata0(property.userdata0),
260       userdata1(property.userdata1),
261       userdata2(property.userdata2),
262       userdata3(property.userdata3),
263       userdata4(property.userdata4),
264       userdata5(property.userdata5),
265       userdata6(property.userdata6),
266       userdata7(property.userdata7),
267       userdata8(property.userdata8),
268       userdata9(property.userdata9),
269       passiveNotifier(this),
270       tariffNotifier(this),
271       cashNotifier(this),
272       ipNotifier(this)
273 {
274 if (&u == this)
275     return;
276
277 connected = 0;
278
279 deleted = u.deleted;
280
281 lastWriteStat = u.lastWriteStat;
282 lastWriteDetailedStat = u.lastWriteDetailedStat;
283
284 settings = u.settings;
285
286 property.tariffName.AddBeforeNotifier(&tariffNotifier);
287 property.passive.AddBeforeNotifier(&passiveNotifier);
288 property.cash.AddBeforeNotifier(&cashNotifier);
289 ips.AddAfterNotifier(&ipNotifier);
290
291 lastScanMessages = 0;
292
293 property.SetProperties(u.property);
294
295 pthread_mutexattr_t attr;
296 pthread_mutexattr_init(&attr);
297 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
298 pthread_mutex_init(&mutex, &attr);
299 }
300 //-----------------------------------------------------------------------------
301 USER_IMPL::~USER_IMPL()
302 {
303 property.passive.DelBeforeNotifier(&passiveNotifier);
304 property.tariffName.DelBeforeNotifier(&tariffNotifier);
305 pthread_mutex_destroy(&mutex);
306 }
307 //-----------------------------------------------------------------------------
308 void USER_IMPL::SetLogin(string const & l)
309 {
310 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
311 assert(login.empty() && "Login is already set");
312 login = l;
313 id = userIDGenerator.GetNextID();
314 }
315 //-----------------------------------------------------------------------------
316 int USER_IMPL::ReadConf()
317 {
318 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
319 USER_CONF conf;
320
321 if (store->RestoreUserConf(&conf, login))
322     {
323     WriteServLog("Cannot read conf for user %s.", login.c_str());
324     WriteServLog("%s", store->GetStrError().c_str());
325     printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
326     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
327     return -1;
328     }
329
330 property.SetConf(conf);
331
332 tariff = tariffs->FindByName(tariffName);
333 if (tariff == NULL)
334     {
335     WriteServLog("Cannot read user %s. Tariff %s not exist.",
336                  login.c_str(), property.tariffName.Get().c_str());
337     return -1;
338     }
339
340 std::vector<STG_MSG_HDR> hdrsList;
341
342 if (store->GetMessageHdrs(&hdrsList, login))
343     {
344     printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
345     return -1;
346     }
347
348 std::vector<STG_MSG_HDR>::const_iterator it;
349 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
350     {
351     STG_MSG msg;
352     if (store->GetMessage(it->id, &msg, login) == 0)
353         {
354         messages.push_back(msg);
355         }
356     }
357
358 return 0;
359 }
360 //-----------------------------------------------------------------------------
361 int USER_IMPL::ReadStat()
362 {
363 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
364 USER_STAT stat;
365
366 if (store->RestoreUserStat(&stat, login))
367     {
368     WriteServLog("Cannot read stat for user %s.", login.c_str());
369     WriteServLog("%s", store->GetStrError().c_str());
370     printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
371     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
372     return -1;
373     }
374
375 property.SetStat(stat);
376
377 return 0;
378 }
379 //-----------------------------------------------------------------------------
380 int USER_IMPL::WriteConf()
381 {
382 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
383 USER_CONF conf(property.GetConf());
384
385 printfd(__FILE__, "USER::WriteConf()\n");
386
387 if (store->SaveUserConf(conf, login))
388     {
389     WriteServLog("Cannot write conf for user %s.", login.c_str());
390     WriteServLog("%s", store->GetStrError().c_str());
391     printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
392     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
393     return -1;
394     }
395
396 return 0;
397 }
398 //-----------------------------------------------------------------------------
399 int USER_IMPL::WriteStat()
400 {
401 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
402 USER_STAT stat(property.GetStat());
403
404 if (store->SaveUserStat(stat, login))
405     {
406     WriteServLog("Cannot write stat for user %s.", login.c_str());
407     WriteServLog("%s", store->GetStrError().c_str());
408     printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
409     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
410     return -1;
411     }
412
413 lastWriteStat = stgTime;
414
415 return 0;
416 }
417 //-----------------------------------------------------------------------------
418 int USER_IMPL::WriteMonthStat()
419 {
420 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
421 time_t tt = stgTime - 3600;
422 struct tm t1;
423 localtime_r(&tt, &t1);
424
425 USER_STAT stat(property.GetStat());
426 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
427     {
428     WriteServLog("Cannot write month stat for user %s.", login.c_str());
429     WriteServLog("%s", store->GetStrError().c_str());
430     printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
431     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
432     return -1;
433     }
434
435 return 0;
436 }
437 //-----------------------------------------------------------------------------
438 int USER_IMPL::Authorize(uint32_t ip, uint32_t dirs, const AUTH * auth)
439 {
440 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
441 /*
442  *  Authorize user. It only means that user will be authorized. Nothing more.
443  *  User can be connected or disconnected while authorized.
444  *  Example: user is authorized but disconnected due to 0 money or blocking
445  */
446
447 /*
448  * Prevent double authorization by identical authorizers
449  */
450 if (authorizedBy.find(auth) != authorizedBy.end())
451     return 0;
452
453 if (!ip)
454     return -1;
455
456 for (int i = 0; i < DIR_NUM; i++)
457     {
458     enabledDirs[i] = dirs & (1 << i);
459     }
460
461 if (authorizedBy.size())
462     {
463     if (currIP != ip)
464         {
465         //  We are already authorized, but with different IP address
466         errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
467         return -1;
468         }
469
470     USER * u = NULL;
471     if (!users->FindByIPIdx(ip, &u))
472         {
473         //  Address is already present in IP-index
474         //  If it's not our IP - throw an error
475         if (u != this)
476             {
477             errorStr = "IP address " + inet_ntostring(ip) + " already in use";
478             return -1;
479             }
480         }
481     }
482 else
483     {
484     if (users->IsIPInIndex(ip))
485         {
486         //  Address is already present in IP-index
487         errorStr = "IP address " + inet_ntostring(ip) + " already in use";
488         return -1;
489         }
490
491     if (ips.ConstData().IsIPInIPS(ip))
492         {
493         currIP = ip;
494         lastIPForDisconnect = currIP;
495         }
496     else
497         {
498         printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
499         errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
500         return -1;
501         }
502     }
503
504 authorizedBy.insert(auth);
505
506 ScanMessage();
507
508 return 0;
509 }
510 //-----------------------------------------------------------------------------
511 void USER_IMPL::Unauthorize(const AUTH * auth)
512 {
513 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
514 /*
515  *  Authorizer tries to unauthorize user, that was not authorized by it
516  */
517 if (!authorizedBy.erase(auth))
518     return;
519
520 if (authorizedBy.empty())
521     {
522     lastIPForDisconnect = currIP;
523     currIP = 0; // DelUser in traffcounter
524     return;
525     }
526 }
527 //-----------------------------------------------------------------------------
528 bool USER_IMPL::IsAuthorizedBy(const AUTH * auth) const
529 {
530 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
531 //  Is this user authorized by specified authorizer?
532 return authorizedBy.find(auth) != authorizedBy.end();
533 }
534 //-----------------------------------------------------------------------------
535 void USER_IMPL::Connect(bool fakeConnect)
536 {
537 /*
538  *  Connect user to Internet. This function is differ from Authorize() !!!
539  */
540
541 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
542
543 if (!fakeConnect)
544     {
545     string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
546
547     if (access(scriptOnConnect.c_str(), X_OK) == 0)
548         {
549         char dirsStr[DIR_NUM + 1];
550         dirsStr[DIR_NUM] = 0;
551         for (int i = 0; i < DIR_NUM; i++)
552             {
553             dirsStr[i] = enabledDirs[i] ? '1' : '0';
554             }
555
556         string scriptOnConnectParams;
557         strprintf(&scriptOnConnectParams,
558                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
559                 scriptOnConnect.c_str(),
560                 login.c_str(),
561                 inet_ntostring(currIP).c_str(),
562                 (double)cash,
563                 id,
564                 dirsStr);
565
566         ScriptExec(scriptOnConnectParams);
567         }
568     else
569         {
570         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
571         }
572
573     connected = true;
574     }
575
576 if (store->WriteUserConnect(login, currIP))
577     {
578     WriteServLog("Cannot write connect for user %s.", login.c_str());
579     WriteServLog("%s", store->GetStrError().c_str());
580     }
581
582 if (!fakeConnect)
583     lastIPForDisconnect = currIP;
584 }
585 //-----------------------------------------------------------------------------
586 void USER_IMPL::Disconnect(bool fakeDisconnect, const std::string & reason)
587 {
588 /*
589  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
590  */
591
592 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
593
594 if (!lastIPForDisconnect)
595     {
596     printfd(__FILE__, "lastIPForDisconnect\n");
597     return;
598     }
599
600 if (!fakeDisconnect)
601     {
602     string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
603
604     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
605         {
606         char dirsStr[DIR_NUM + 1];
607         dirsStr[DIR_NUM] = 0;
608         for (int i = 0; i < DIR_NUM; i++)
609             {
610             dirsStr[i] = enabledDirs[i] ? '1' : '0';
611             }
612
613         string scriptOnDisonnectParams;
614         strprintf(&scriptOnDisonnectParams,
615                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
616                 scriptOnDisonnect.c_str(),
617                 login.c_str(),
618                 inet_ntostring(lastIPForDisconnect).c_str(),
619                 (double)cash,
620                 id,
621                 dirsStr);
622
623         ScriptExec(scriptOnDisonnectParams);
624         }
625     else
626         {
627         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
628         }
629
630     connected = false;
631     }
632
633 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, cash, freeMb, reason))
634     {
635     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
636     WriteServLog("%s", store->GetStrError().c_str());
637     }
638
639 if (!fakeDisconnect)
640     lastIPForDisconnect = 0;
641
642 DIR_TRAFF zeroSesssion;
643
644 sessionUpload = zeroSesssion;
645 sessionDownload = zeroSesssion;
646 }
647 //-----------------------------------------------------------------------------
648 void USER_IMPL::PrintUser() const
649 {
650 //return;
651 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
652 cout << "============================================================" << endl;
653 cout << "id=" << id << endl;
654 cout << "login=" << login << endl;
655 cout << "password=" << password << endl;
656 cout << "passive=" << passive << endl;
657 cout << "disabled=" << disabled << endl;
658 cout << "disabledDetailStat=" << disabledDetailStat << endl;
659 cout << "alwaysOnline=" << alwaysOnline << endl;
660 cout << "tariffName=" << tariffName << endl;
661 cout << "address=" << address << endl;
662 cout << "phone=" << phone << endl;
663 cout << "email=" << email << endl;
664 cout << "note=" << note << endl;
665 cout << "realName=" <<realName << endl;
666 cout << "group=" << group << endl;
667 cout << "credit=" << credit << endl;
668 cout << "nextTariff=" << nextTariff << endl;
669 cout << "userdata0" << userdata0 << endl;
670 cout << "userdata1" << userdata1 << endl;
671 cout << "creditExpire=" << creditExpire << endl;
672 cout << "ips=" << ips << endl;
673 cout << "------------------------" << endl;
674 cout << "up=" << up << endl;
675 cout << "down=" << down << endl;
676 cout << "cash=" << cash << endl;
677 cout << "freeMb=" << freeMb << endl;
678 cout << "lastCashAdd=" << lastCashAdd << endl;
679 cout << "lastCashAddTime=" << lastCashAddTime << endl;
680 cout << "passiveTime=" << passiveTime << endl;
681 cout << "lastActivityTime=" << lastActivityTime << endl;
682 cout << "============================================================" << endl;
683 }
684 //-----------------------------------------------------------------------------
685 void USER_IMPL::Run()
686 {
687 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
688
689 if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
690     {
691     printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
692     WriteStat();
693     }
694 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
695     {
696     WriteServLog("User: %s. Credit expired.", login.c_str());
697     credit = 0;
698     creditExpire = 0;
699     WriteConf();
700     }
701
702 if (passive.ConstData()
703     && (stgTime % 30 == 0)
704     && (passiveTime.ModificationTime() != stgTime))
705     {
706     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
707     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
708     }
709
710 if (!authorizedBy.empty())
711     {
712     if (connected)
713         {
714         property.Stat().lastActivityTime = stgTime;
715         }
716     if (!connected && IsInetable())
717         {
718         Connect();
719         }
720     if (connected && !IsInetable())
721         {
722         if (disabled)
723             Disconnect(false, "disabled");
724         else if (passive)
725             Disconnect(false, "passive");
726         else
727             Disconnect(false, "no cash");
728         }
729
730     if (stgTime - lastScanMessages > 10)
731         {
732         ScanMessage();
733         lastScanMessages = stgTime;
734         }
735     }
736 else
737     {
738     if (connected)
739         {
740         Disconnect(false, "not authorized");
741         }
742     }
743
744 }
745 //-----------------------------------------------------------------------------
746 void USER_IMPL::UpdatePingTime(time_t t)
747 {
748 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
749 //printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
750 if (t)
751     pingTime = t;
752 else
753     pingTime = stgTime;
754 }
755 //-----------------------------------------------------------------------------
756 bool USER_IMPL::IsInetable()
757 {
758 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
759
760 if (disabled || passive)
761     return false;
762
763 if (settings->GetFreeMbAllowInet())
764     {
765     if (freeMb >= 0)
766         return true;
767     }
768
769 if (settings->GetShowFeeInCash() || tariff == NULL)
770     {
771     return (cash >= -credit);
772     }
773
774 return (cash - tariff->GetFee() >= -credit);
775 }
776 //-----------------------------------------------------------------------------
777 string USER_IMPL::GetEnabledDirs()
778 {
779 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
780
781 string dirs = "";
782 for(int i = 0; i < DIR_NUM; i++)
783     dirs += enabledDirs[i] ? "1" : "0";
784 return dirs;
785 }
786 //-----------------------------------------------------------------------------
787 #ifdef TRAFF_STAT_WITH_PORTS
788 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
789 #else
790 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
791 #endif
792 {
793 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
794
795 if (!connected || tariff == NULL)
796     return;
797
798 double cost = 0;
799 DIR_TRAFF dt(up);
800
801 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
802 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
803
804 dt[dir] += len;
805
806 int tt = tariff->GetTraffType();
807 if (tt == TRAFF_UP ||
808     tt == TRAFF_UP_DOWN ||
809     // Check NEW traff data
810     (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
811     {
812     double dc = 0;
813     if (traff < threshold &&
814         traff + len >= threshold)
815         {
816         // cash = partBeforeThreshold * priceBeforeThreshold +
817         //        partAfterThreshold * priceAfterThreshold
818         int64_t before = threshold - traff; // Chunk part before threshold
819         int64_t after = len - before; // Chunk part after threshold
820         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
821                                            down.ConstData()[dir],
822                                            dir,
823                                            stgTime) * before +
824              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
825                                            down.ConstData()[dir],
826                                            dir,
827                                            stgTime) * after;
828         }
829     else
830         {
831         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
832                                            down.ConstData()[dir],
833                                            dir,
834                                            stgTime) * len;
835         }
836
837     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
838         cost = dc;
839     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
840         cost = dc - freeMb.ConstData();
841
842     // Direct access to internal data structures via friend-specifier
843     property.Stat().freeMb -= dc;
844     property.Stat().cash -= cost;
845     cash.ModifyTime();
846     freeMb.ModifyTime();
847     }
848
849 up = dt;
850 sessionUpload[dir] += len;
851
852 //Add detailed stat
853
854 if (!settings->GetWriteFreeMbTraffCost() &&
855      freeMb.ConstData() >= 0)
856     cost = 0;
857
858 #ifdef TRAFF_STAT_WITH_PORTS
859 IP_DIR_PAIR idp(ip, dir, port);
860 #else
861 IP_DIR_PAIR idp(ip, dir);
862 #endif
863
864 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
865 lb = traffStat.lower_bound(idp);
866 if (lb == traffStat.end() || lb->first != idp)
867     {
868     traffStat.insert(lb,
869                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
870                                                   STAT_NODE(len, 0, cost)));
871     }
872 else
873     {
874     lb->second.cash += cost;
875     lb->second.up += len;
876     }
877 }
878 //-----------------------------------------------------------------------------
879 #ifdef TRAFF_STAT_WITH_PORTS
880 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
881 #else
882 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
883 #endif
884 {
885 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
886
887 if (!connected || tariff == NULL)
888     return;
889
890 double cost = 0;
891 DIR_TRAFF dt(down);
892
893 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
894 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
895
896 dt[dir] += len;
897
898 int tt = tariff->GetTraffType();
899 if (tt == TRAFF_DOWN ||
900     tt == TRAFF_UP_DOWN ||
901     // Check NEW traff data
902     (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
903     {
904     double dc = 0;
905     if (traff < threshold &&
906         traff + len >= threshold)
907         {
908         // cash = partBeforeThreshold * priceBeforeThreshold +
909         //        partAfterThreshold * priceAfterThreshold
910         int64_t before = threshold - traff; // Chunk part before threshold
911         int64_t after = len - before; // Chunk part after threshold
912         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
913                                            down.ConstData()[dir], // Traff before chunk
914                                            dir,
915                                            stgTime) * before +
916              tariff->GetPriceWithTraffType(up.ConstData()[dir],
917                                            dt[dir], // Traff after chunk
918                                            dir,
919                                            stgTime) * after;
920         }
921     else
922         {
923         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
924                                            down.ConstData()[dir],
925                                            dir,
926                                            stgTime) * len;
927         }
928
929     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
930         cost = dc;
931     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
932         cost = dc - freeMb.ConstData();
933
934     property.Stat().freeMb -= dc;
935     property.Stat().cash -= cost;
936     cash.ModifyTime();
937     freeMb.ModifyTime();
938     }
939
940 down = dt;
941 sessionDownload[dir] += len;
942
943 //Add detailed stat
944
945 if (!settings->GetWriteFreeMbTraffCost() &&
946      freeMb.ConstData() >= 0)
947     cost = 0;
948
949 #ifdef TRAFF_STAT_WITH_PORTS
950 IP_DIR_PAIR idp(ip, dir, port);
951 #else
952 IP_DIR_PAIR idp(ip, dir);
953 #endif
954
955 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
956 lb = traffStat.lower_bound(idp);
957 if (lb == traffStat.end() || lb->first != idp)
958     {
959     traffStat.insert(lb,
960                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
961                                                   STAT_NODE(0, len, cost)));
962     }
963 else
964     {
965     lb->second.cash += cost;
966     lb->second.down += len;
967     }
968 }
969 //-----------------------------------------------------------------------------
970 void USER_IMPL::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
971 {
972 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
973 currIP.AddBeforeNotifier(n);
974 }
975 //-----------------------------------------------------------------------------
976 void USER_IMPL::DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
977 {
978 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
979 currIP.DelBeforeNotifier(n);
980 }
981 //-----------------------------------------------------------------------------
982 void USER_IMPL::AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
983 {
984 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
985 currIP.AddAfterNotifier(n);
986 }
987 //-----------------------------------------------------------------------------
988 void USER_IMPL::DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
989 {
990 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
991 currIP.DelAfterNotifier(n);
992 }
993 //-----------------------------------------------------------------------------
994 void USER_IMPL::AddConnectedBeforeNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
995 {
996 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
997 connected.AddBeforeNotifier(n);
998 }
999 //-----------------------------------------------------------------------------
1000 void USER_IMPL::DelConnectedBeforeNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1001 {
1002 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1003 connected.DelBeforeNotifier(n);
1004 }
1005 //-----------------------------------------------------------------------------
1006 void USER_IMPL::AddConnectedAfterNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1007 {
1008 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1009 connected.AddAfterNotifier(n);
1010 }
1011 //-----------------------------------------------------------------------------
1012 void USER_IMPL::DelConnectedAfterNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1013 {
1014 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1015 connected.DelAfterNotifier(n);
1016 }
1017 //-----------------------------------------------------------------------------
1018 void USER_IMPL::OnAdd()
1019 {
1020 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1021
1022 string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
1023
1024 if (access(scriptOnAdd.c_str(), X_OK) == 0)
1025     {
1026     string scriptOnAddParams;
1027     strprintf(&scriptOnAddParams,
1028             "%s \"%s\"",
1029             scriptOnAdd.c_str(),
1030             login.c_str());
1031
1032     ScriptExec(scriptOnAddParams);
1033     }
1034 else
1035     {
1036     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
1037     }
1038 }
1039 //-----------------------------------------------------------------------------
1040 void USER_IMPL::OnDelete()
1041 {
1042 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1043
1044 string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
1045
1046 if (access(scriptOnDel.c_str(), X_OK) == 0)
1047     {
1048     string scriptOnDelParams;
1049     strprintf(&scriptOnDelParams,
1050             "%s \"%s\"",
1051             scriptOnDel.c_str(),
1052             login.c_str());
1053
1054     ScriptExec(scriptOnDelParams);
1055     }
1056 else
1057     {
1058     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
1059     }
1060
1061 Run();
1062 }
1063 //-----------------------------------------------------------------------------
1064 int USER_IMPL::WriteDetailStat(bool hard)
1065 {
1066 printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
1067
1068 if (!traffStatSaved.second.empty())
1069     {
1070     if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
1071         {
1072         printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
1073         WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
1074         WriteServLog("%s", store->GetStrError().c_str());
1075         return -1;
1076         }
1077     traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
1078     }
1079
1080 TRAFF_STAT ts;
1081
1082     {
1083     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1084     ts.swap(traffStat);
1085     }
1086
1087 printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
1088
1089 if (ts.size() && !disabledDetailStat)
1090     {
1091     if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
1092         {
1093         printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
1094         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
1095         WriteServLog("%s", store->GetStrError().c_str());
1096         if (!hard)
1097             {
1098             printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
1099             STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1100             traffStatSaved.second.swap(ts);
1101             traffStatSaved.first = lastWriteDetailedStat;
1102             }
1103         return -1;
1104         }
1105     }
1106 lastWriteDetailedStat = stgTime;
1107 return 0;
1108 }
1109 //-----------------------------------------------------------------------------
1110 double USER_IMPL::GetPassiveTimePart() const
1111 {
1112 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1113
1114 static int daysInMonth[12] =
1115 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1116
1117 struct tm tms;
1118 time_t t = stgTime;
1119 localtime_r(&t, &tms);
1120
1121 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
1122
1123 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
1124     {
1125     // Leap year
1126     secMonth += 24 * 3600;
1127     }
1128
1129 int dt = secMonth - passiveTime;
1130
1131 if (dt < 0)
1132     dt = 0;
1133
1134 return double(dt) / (secMonth);
1135 }
1136 //-----------------------------------------------------------------------------
1137 void USER_IMPL::SetPassiveTimeAsNewUser()
1138 {
1139 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1140
1141 time_t t = stgTime;
1142 struct tm tm;
1143 localtime_r(&t, &tm);
1144 int daysCurrMon = DaysInCurrentMonth();
1145 double pt = (tm.tm_mday - 1) / (double)daysCurrMon;
1146
1147 passiveTime = (time_t)(pt * 24 * 3600 * daysCurrMon);
1148 }
1149 //-----------------------------------------------------------------------------
1150 void USER_IMPL::MidnightResetSessionStat()
1151 {
1152 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1153
1154 if (connected)
1155     {
1156     Disconnect(true, "fake");
1157     Connect(true);
1158     }
1159 }
1160 //-----------------------------------------------------------------------------
1161 void USER_IMPL::ProcessNewMonth()
1162 {
1163 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1164 //  Reset traff
1165 if (connected)
1166     {
1167     Disconnect(true, "fake");
1168     }
1169 DIR_TRAFF zeroTarff;
1170
1171 WriteMonthStat();
1172
1173 up = zeroTarff;
1174 down = zeroTarff;
1175
1176 if (connected)
1177     {
1178     Connect(true);
1179     }
1180
1181 //  Set new tariff
1182 if (nextTariff.ConstData() != "")
1183     {
1184     const TARIFF * nt;
1185     nt = tariffs->FindByName(nextTariff);
1186     if (nt == NULL)
1187         {
1188         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1189                      login.c_str(), property.tariffName.Get().c_str());
1190         }
1191     else
1192         {
1193         property.tariffName.Set(nextTariff, sysAdmin, login, store);
1194         //tariff = nt;
1195         }
1196     ResetNextTariff();
1197     WriteConf();
1198     }
1199 }
1200 //-----------------------------------------------------------------------------
1201 void USER_IMPL::ProcessDayFeeSpread()
1202 {
1203 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1204
1205 if (passive.ConstData() || tariff == NULL)
1206     return;
1207
1208 double fee = tariff->GetFee() / DaysInCurrentMonth();
1209
1210 if (fee == 0.0)
1211     return;
1212
1213 double c = cash;
1214 switch (settings->GetFeeChargeType())
1215     {
1216     case 0:
1217         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1218         break;
1219     case 1:
1220         if (c > 0)
1221             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1222         break;
1223     case 2:
1224         if (c > fee)
1225             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1226         break;
1227     }
1228 ResetPassiveTime();
1229 }
1230 //-----------------------------------------------------------------------------
1231 void USER_IMPL::ProcessDayFee()
1232 {
1233 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1234
1235 if (tariff == NULL)
1236     return;
1237
1238 double passiveTimePart = 1.0;
1239 if (!settings->GetFullFee())
1240     {
1241     passiveTimePart = GetPassiveTimePart();
1242     }
1243 else
1244     {
1245     if (passive.ConstData())
1246         {
1247         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1248         return;
1249         }
1250     }
1251 double fee = tariff->GetFee() * passiveTimePart;
1252
1253 ResetPassiveTime();
1254
1255 if (fee == 0.0)
1256     {
1257     SetPrepaidTraff();
1258     return;
1259     }
1260
1261 double c = cash;
1262 printfd(__FILE__, "login: %8s   Fee=%f PassiveTimePart=%f fee=%f\n",
1263         login.c_str(),
1264         tariff->GetFee(),
1265         passiveTimePart,
1266         fee);
1267 switch (settings->GetFeeChargeType())
1268     {
1269     case 0:
1270         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1271         SetPrepaidTraff();
1272         break;
1273     case 1:
1274         if (c > 0)
1275             {
1276             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1277             SetPrepaidTraff();
1278             }
1279         break;
1280     case 2:
1281         if (c > fee)
1282             {
1283             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1284             SetPrepaidTraff();
1285             }
1286         break;
1287     }
1288 }
1289 //-----------------------------------------------------------------------------
1290 void USER_IMPL::SetPrepaidTraff()
1291 {
1292 if (tariff != NULL)
1293     property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1294 }
1295 //-----------------------------------------------------------------------------
1296 int USER_IMPL::AddMessage(STG_MSG * msg)
1297 {
1298 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1299
1300 if (SendMessage(*msg))
1301     {
1302     if (store->AddMessage(msg, login))
1303         {
1304         errorStr = store->GetStrError();
1305         WriteServLog("Error adding message: '%s'", errorStr.c_str());
1306         printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1307         return -1;
1308         }
1309     messages.push_back(*msg);
1310     }
1311 else
1312     {
1313     if (msg->header.repeat > 0)
1314         {
1315         msg->header.repeat--;
1316         #ifndef DEBUG
1317         //TODO: gcc v. 4.x generate ICE on x86_64
1318         msg->header.lastSendTime = time(NULL);
1319         #else
1320         msg->header.lastSendTime = stgTime;
1321         #endif
1322         if (store->AddMessage(msg, login))
1323             {
1324             errorStr = store->GetStrError();
1325             WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1326             printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1327             return -1;
1328             }
1329         messages.push_back(*msg);
1330         }
1331     }
1332 return 0;
1333 }
1334 //-----------------------------------------------------------------------------
1335 int USER_IMPL::SendMessage(STG_MSG & msg) const
1336 {
1337 // No lock `cause we are already locked from caller
1338 int ret = -1;
1339 set<const AUTH*>::iterator it(authorizedBy.begin());
1340 while (it != authorizedBy.end())
1341     {
1342     if (!(*it++)->SendMessage(msg, currIP))
1343         ret = 0;
1344     }
1345 if (!ret)
1346     {
1347 #ifndef DEBUG
1348     //TODO: gcc v. 4.x generate ICE on x86_64
1349     msg.header.lastSendTime = time(NULL);
1350 #else
1351     msg.header.lastSendTime = stgTime;
1352 #endif
1353     msg.header.repeat--;
1354     }
1355 return ret;
1356 }
1357 //-----------------------------------------------------------------------------
1358 void USER_IMPL::ScanMessage()
1359 {
1360 // No lock `cause we are already locked from caller
1361 // We need not check for the authorizedBy `cause it has already checked by caller
1362
1363 std::list<STG_MSG>::iterator it(messages.begin());
1364 while (it != messages.end())
1365     {
1366     if (settings->GetMessageTimeout() > 0 &&
1367         difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1368         {
1369         // Timeout exceeded
1370         if (store->DelMessage(it->header.id, login))
1371             {
1372             WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1373             printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1374             }
1375         messages.erase(it++);
1376         continue;
1377         }
1378     if (it->GetNextSendTime() <= stgTime)
1379         {
1380         if (SendMessage(*it))
1381             {
1382             // We need to check all messages in queue for timeout
1383             ++it;
1384             continue;
1385             }
1386         if (it->header.repeat < 0)
1387             {
1388             if (store->DelMessage(it->header.id, login))
1389                 {
1390                 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1391                 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1392                 }
1393             messages.erase(it++);
1394             }
1395         else
1396             {
1397             if (store->EditMessage(*it, login))
1398                 {
1399                 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1400                 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1401                 }
1402             ++it;
1403             }
1404         }
1405     else
1406         {
1407         ++it;
1408         }
1409     }
1410 }
1411 //-----------------------------------------------------------------------------
1412 //-----------------------------------------------------------------------------
1413 //-----------------------------------------------------------------------------
1414 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1415 {
1416 if (newPassive && !oldPassive && user->tariff != NULL)
1417     user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1418                             user->sysAdmin,
1419                             user->login,
1420                             user->store,
1421                             "Freeze");
1422 }
1423 //-----------------------------------------------------------------------------
1424 void CHG_TARIFF_NOTIFIER::Notify(const string &, const string & newTariff)
1425 {
1426 if (user->settings->GetReconnectOnTariffChange() && user->connected)
1427     user->Disconnect(true, "Change tariff");
1428 user->tariff = user->tariffs->FindByName(newTariff);
1429 if (user->settings->GetReconnectOnTariffChange() && user->IsInetable())
1430     user->Connect(true);
1431 }
1432 //-----------------------------------------------------------------------------
1433 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1434 {
1435 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1436 user->lastCashAdd = newCash - oldCash;
1437 }
1438 //-----------------------------------------------------------------------------
1439 void CHG_IPS_NOTIFIER::Notify(const USER_IPS & from, const USER_IPS & to)
1440 {
1441     printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.GetIpStr().c_str(), to.GetIpStr().c_str());
1442     if (user->connected)
1443         user->Disconnect(true, "Change IP");
1444     if (user->IsInetable())
1445         user->Connect(true);
1446 }
1447 //-----------------------------------------------------------------------------