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