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