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