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