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