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