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