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