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