]> git.stg.codes - stg.git/blob - stargazer/user_impl.cpp
Public interfaces: part 4
[stg.git] / 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
51 #include <cassert>
52 #include <cstdlib>
53 #include <cmath>
54
55 #include <pthread.h>
56 #include <unistd.h> // access
57
58 using STG::UserImpl;
59
60 namespace
61 {
62
63 std::string dirsToString(const bool * dirs)
64 {
65 std::string res;
66 for (size_t i = 0; i < DIR_NUM; i++)
67     res += dirs[i] ? '1' : '0';
68 return res;
69 }
70
71 void dirsFromBits(bool * dirs, uint32_t bits)
72 {
73 for (size_t i = 0; i < DIR_NUM; i++)
74     dirs[i] = bits & (1 << i);
75 }
76
77 }
78
79 UserImpl::UserImpl(const Settings * s,
80            const Store * st,
81            const Tariffs * t,
82            const Admin * a,
83            const Users * u,
84            const Services & svcs)
85     : users(u),
86       properties(*s),
87       WriteServLog(Logger::get()),
88       lastScanMessages(0),
89       id(0),
90       __connected(0),
91       connected(__connected),
92       __currIP(0),
93       currIP(__currIP),
94       lastIPForDisconnect(0),
95       pingTime(0),
96       sysAdmin(a),
97       store(st),
98       tariffs(t),
99       tariff(NULL),
100       m_services(svcs),
101       settings(s),
102       authorizedModificationTime(0),
103       deleted(false),
104       lastWriteStat(0),
105       lastWriteDetailedStat(0),
106       cash(properties.cash),
107       up(properties.up),
108       down(properties.down),
109       lastCashAdd(properties.lastCashAdd),
110       passiveTime(properties.passiveTime),
111       lastCashAddTime(properties.lastCashAddTime),
112       freeMb(properties.freeMb),
113       lastActivityTime(properties.lastActivityTime),
114       password(properties.password),
115       passive(properties.passive),
116       disabled(properties.disabled),
117       disabledDetailStat(properties.disabledDetailStat),
118       alwaysOnline(properties.alwaysOnline),
119       tariffName(properties.tariffName),
120       nextTariff(properties.nextTariff),
121       address(properties.address),
122       note(properties.note),
123       group(properties.group),
124       email(properties.email),
125       phone(properties.phone),
126       realName(properties.realName),
127       credit(properties.credit),
128       creditExpire(properties.creditExpire),
129       ips(properties.ips),
130       userdata0(properties.userdata0),
131       userdata1(properties.userdata1),
132       userdata2(properties.userdata2),
133       userdata3(properties.userdata3),
134       userdata4(properties.userdata4),
135       userdata5(properties.userdata5),
136       userdata6(properties.userdata6),
137       userdata7(properties.userdata7),
138       userdata8(properties.userdata8),
139       userdata9(properties.userdata9),
140       sessionUploadModTime(stgTime),
141       sessionDownloadModTime(stgTime),
142       passiveNotifier(this),
143       disabledNotifier(this),
144       tariffNotifier(this),
145       cashNotifier(this),
146       ipNotifier(this)
147 {
148 Init();
149 }
150 //-----------------------------------------------------------------------------
151 void UserImpl::Init()
152 {
153 password = "*_EMPTY_PASSWORD_*";
154 tariffName = NO_TARIFF_NAME;
155 tariff = tariffs->FindByName(tariffName);
156 ips = UserIPs::parse("*");
157 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
158 lastWriteDetailedStat = stgTime;
159
160 properties.tariffName.AddBeforeNotifier(&tariffNotifier);
161 properties.passive.AddBeforeNotifier(&passiveNotifier);
162 properties.disabled.AddAfterNotifier(&disabledNotifier);
163 properties.cash.AddBeforeNotifier(&cashNotifier);
164 ips.AddAfterNotifier(&ipNotifier);
165
166 pthread_mutexattr_t attr;
167 pthread_mutexattr_init(&attr);
168 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
169 pthread_mutex_init(&mutex, &attr);
170 }
171 //-----------------------------------------------------------------------------
172 UserImpl::UserImpl(const UserImpl & u)
173     : users(u.users),
174       properties(*u.settings),
175       WriteServLog(Logger::get()),
176       lastScanMessages(0),
177       login(u.login),
178       id(u.id),
179       __connected(0),
180       connected(__connected),
181       __currIP(u.__currIP),
182       currIP(__currIP),
183       lastIPForDisconnect(0),
184       pingTime(u.pingTime),
185       sysAdmin(u.sysAdmin),
186       store(u.store),
187       tariffs(u.tariffs),
188       tariff(u.tariff),
189       m_services(u.m_services),
190       traffStat(u.traffStat),
191       traffStatSaved(u.traffStatSaved),
192       settings(u.settings),
193       authorizedModificationTime(u.authorizedModificationTime),
194       messages(u.messages),
195       deleted(u.deleted),
196       lastWriteStat(u.lastWriteStat),
197       lastWriteDetailedStat(u.lastWriteDetailedStat),
198       cash(properties.cash),
199       up(properties.up),
200       down(properties.down),
201       lastCashAdd(properties.lastCashAdd),
202       passiveTime(properties.passiveTime),
203       lastCashAddTime(properties.lastCashAddTime),
204       freeMb(properties.freeMb),
205       lastActivityTime(properties.lastActivityTime),
206       password(properties.password),
207       passive(properties.passive),
208       disabled(properties.disabled),
209       disabledDetailStat(properties.disabledDetailStat),
210       alwaysOnline(properties.alwaysOnline),
211       tariffName(properties.tariffName),
212       nextTariff(properties.nextTariff),
213       address(properties.address),
214       note(properties.note),
215       group(properties.group),
216       email(properties.email),
217       phone(properties.phone),
218       realName(properties.realName),
219       credit(properties.credit),
220       creditExpire(properties.creditExpire),
221       ips(properties.ips),
222       userdata0(properties.userdata0),
223       userdata1(properties.userdata1),
224       userdata2(properties.userdata2),
225       userdata3(properties.userdata3),
226       userdata4(properties.userdata4),
227       userdata5(properties.userdata5),
228       userdata6(properties.userdata6),
229       userdata7(properties.userdata7),
230       userdata8(properties.userdata8),
231       userdata9(properties.userdata9),
232       sessionUpload(),
233       sessionDownload(),
234       sessionUploadModTime(stgTime),
235       sessionDownloadModTime(stgTime),
236       passiveNotifier(this),
237       disabledNotifier(this),
238       tariffNotifier(this),
239       cashNotifier(this),
240       ipNotifier(this)
241 {
242 if (&u == this)
243     return;
244
245 properties.tariffName.AddBeforeNotifier(&tariffNotifier);
246 properties.passive.AddBeforeNotifier(&passiveNotifier);
247 properties.disabled.AddAfterNotifier(&disabledNotifier);
248 properties.cash.AddBeforeNotifier(&cashNotifier);
249 ips.AddAfterNotifier(&ipNotifier);
250
251 properties.SetProperties(u.properties);
252
253 pthread_mutexattr_t attr;
254 pthread_mutexattr_init(&attr);
255 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
256 pthread_mutex_init(&mutex, &attr);
257 }
258 //-----------------------------------------------------------------------------
259 UserImpl::~UserImpl()
260 {
261 properties.tariffName.DelBeforeNotifier(&tariffNotifier);
262 properties.passive.DelBeforeNotifier(&passiveNotifier);
263 properties.disabled.DelAfterNotifier(&disabledNotifier);
264 properties.cash.DelBeforeNotifier(&cashNotifier);
265 pthread_mutex_destroy(&mutex);
266 }
267 //-----------------------------------------------------------------------------
268 void UserImpl::SetLogin(const std::string & l)
269 {
270 STG_LOCKER lock(&mutex);
271 static int idGen = 0;
272 assert(login.empty() && "Login is already set");
273 login = l;
274 id = idGen++;
275 }
276 //-----------------------------------------------------------------------------
277 int UserImpl::ReadConf()
278 {
279 STG_LOCKER lock(&mutex);
280 UserConf conf;
281
282 if (store->RestoreUserConf(&conf, login))
283     {
284     WriteServLog("Cannot read conf for user %s.", login.c_str());
285     WriteServLog("%s", store->GetStrError().c_str());
286     printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
287     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
288     return -1;
289     }
290
291 properties.SetConf(conf);
292
293 tariff = tariffs->FindByName(tariffName);
294 if (tariff == NULL)
295     {
296     WriteServLog("Cannot read user %s. Tariff %s not exist.",
297                  login.c_str(), properties.tariffName.Get().c_str());
298     return -1;
299     }
300
301 std::vector<Message::Header> hdrsList;
302
303 if (store->GetMessageHdrs(&hdrsList, login))
304     {
305     printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
306     WriteServLog("Cannot read user %s. Error reading message headers: %s.",
307                  login.c_str(),
308                  store->GetStrError().c_str());
309     return -1;
310     }
311
312 std::vector<Message::Header>::const_iterator it;
313 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
314     {
315     Message msg;
316     if (store->GetMessage(it->id, &msg, login) == 0)
317         {
318         messages.push_back(msg);
319         }
320     }
321
322 return 0;
323 }
324 //-----------------------------------------------------------------------------
325 int UserImpl::ReadStat()
326 {
327 STG_LOCKER lock(&mutex);
328 UserStat stat;
329
330 if (store->RestoreUserStat(&stat, login))
331     {
332     WriteServLog("Cannot read stat for user %s.", login.c_str());
333     WriteServLog("%s", store->GetStrError().c_str());
334     printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
335     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
336     return -1;
337     }
338
339 properties.SetStat(stat);
340
341 return 0;
342 }
343 //-----------------------------------------------------------------------------
344 int UserImpl::WriteConf()
345 {
346 STG_LOCKER lock(&mutex);
347 UserConf conf(properties.GetConf());
348
349 printfd(__FILE__, "UserImpl::WriteConf()\n");
350
351 if (store->SaveUserConf(conf, login))
352     {
353     WriteServLog("Cannot write conf for user %s.", login.c_str());
354     WriteServLog("%s", store->GetStrError().c_str());
355     printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
356     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
357     return -1;
358     }
359
360 return 0;
361 }
362 //-----------------------------------------------------------------------------
363 int UserImpl::WriteStat()
364 {
365 STG_LOCKER lock(&mutex);
366 UserStat stat(properties.GetStat());
367
368 if (store->SaveUserStat(stat, login))
369     {
370     WriteServLog("Cannot write stat for user %s.", login.c_str());
371     WriteServLog("%s", store->GetStrError().c_str());
372     printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
373     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
374     return -1;
375     }
376
377 lastWriteStat = stgTime;
378
379 return 0;
380 }
381 //-----------------------------------------------------------------------------
382 int UserImpl::WriteMonthStat()
383 {
384 STG_LOCKER lock(&mutex);
385 time_t tt = stgTime - 3600;
386 struct tm t1;
387 localtime_r(&tt, &t1);
388
389 UserStat stat(properties.GetStat());
390 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
391     {
392     WriteServLog("Cannot write month stat for user %s.", login.c_str());
393     WriteServLog("%s", store->GetStrError().c_str());
394     printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
395     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
396     return -1;
397     }
398
399 return 0;
400 }
401 //-----------------------------------------------------------------------------
402 int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth)
403 {
404 STG_LOCKER lock(&mutex);
405 /*
406  *  Authorize user. It only means that user will be authorized. Nothing more.
407  *  User can be connected or disconnected while authorized.
408  *  Example: user is authorized but disconnected due to 0 money or blocking
409  */
410
411 /*
412  * TODO: in fact "authorization" means allowing access to a service. What we
413  * call "authorization" here, int STG, is "authentication". So this should be
414  * fixed in future.
415  */
416
417 /*
418  * Prevent double authorization by identical authorizers
419  */
420 if (authorizedBy.find(auth) != authorizedBy.end())
421     return 0;
422
423 if (!ip)
424     return -1;
425
426 dirsFromBits(enabledDirs, dirs);
427
428 if (!authorizedBy.empty())
429     {
430     if (currIP != ip)
431         {
432         // We are already authorized, but with different IP address
433         errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
434         return -1;
435         }
436
437     User * u = NULL;
438     if (!users->FindByIPIdx(ip, &u))
439         {
440         // Address presents in IP-index.
441         // If it's not our IP - report it.
442         if (u != this)
443             {
444             errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
445             return -1;
446             }
447         }
448     }
449 else
450     {
451     if (users->IsIPInIndex(ip))
452         {
453         // Address is already present in IP-index.
454         errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
455         return -1;
456         }
457
458     if (ips.ConstData().find(ip))
459         {
460         currIP = ip;
461         lastIPForDisconnect = currIP;
462         }
463     else
464         {
465         printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().toString().c_str());
466         errorStr = "IP address " + inet_ntostring(ip) + " does not belong to user " + login;
467         return -1;
468         }
469     }
470
471 if (authorizedBy.empty())
472     authorizedModificationTime = stgTime;
473 authorizedBy.insert(auth);
474
475 ScanMessage();
476
477 return 0;
478 }
479 //-----------------------------------------------------------------------------
480 void UserImpl::Unauthorize(const Auth * auth, const std::string & reason)
481 {
482 STG_LOCKER lock(&mutex);
483 /*
484  *  Authorizer tries to unauthorize user, that was not authorized by it
485  */
486 if (!authorizedBy.erase(auth))
487     return;
488
489 authorizedModificationTime = stgTime;
490
491 if (authorizedBy.empty())
492     {
493     lastDisconnectReason = reason;
494     lastIPForDisconnect = currIP;
495     currIP = 0; // DelUser in traffcounter
496     if (connected)
497         Disconnect(false, "not authorized");
498     return;
499     }
500 }
501 //-----------------------------------------------------------------------------
502 bool UserImpl::IsAuthorizedBy(const Auth * auth) const
503 {
504 STG_LOCKER lock(&mutex);
505 // Is this user authorized by specified authorizer?
506 return authorizedBy.find(auth) != authorizedBy.end();
507 }
508 //-----------------------------------------------------------------------------
509 std::vector<std::string> UserImpl::GetAuthorizers() const
510 {
511     STG_LOCKER lock(&mutex);
512     std::vector<std::string> list;
513     std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), [](const auto auth){ return auth->GetVersion(); });
514     return list;
515 }
516 //-----------------------------------------------------------------------------
517 void UserImpl::Connect(bool fakeConnect)
518 {
519 /*
520  * Connect user to Internet. This function is differ from Authorize() !!!
521  */
522
523 STG_LOCKER lock(&mutex);
524
525 if (!fakeConnect)
526     {
527     std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
528
529     if (access(scriptOnConnect.c_str(), X_OK) == 0)
530         {
531         std::string dirs = dirsToString(enabledDirs);
532
533         std::string scriptOnConnectParams;
534         strprintf(&scriptOnConnectParams,
535                   "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
536                   scriptOnConnect.c_str(),
537                   login.c_str(),
538                   inet_ntostring(currIP).c_str(),
539                   cash.ConstData(),
540                   id,
541                   dirs.c_str());
542
543         std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
544         while (it != settings->GetScriptParams().end())
545             {
546             scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
547             ++it;
548             }
549
550         ScriptExec(scriptOnConnectParams.c_str());
551         }
552     else
553         {
554         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
555         }
556
557     connected = true;
558     }
559
560 if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, currIP))
561     {
562     WriteServLog("Cannot write connect for user %s.", login.c_str());
563     WriteServLog("%s", store->GetStrError().c_str());
564     }
565
566 if (!fakeConnect)
567     lastIPForDisconnect = currIP;
568 }
569 //-----------------------------------------------------------------------------
570 void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason)
571 {
572 /*
573  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
574  */
575
576 STG_LOCKER lock(&mutex);
577
578 if (!lastIPForDisconnect)
579     {
580     printfd(__FILE__, "lastIPForDisconnect\n");
581     return;
582     }
583
584 if (!fakeDisconnect)
585     {
586     lastDisconnectReason = reason;
587     std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
588
589     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
590         {
591         std::string dirs = dirsToString(enabledDirs);
592
593         std::string scriptOnDisonnectParams;
594         strprintf(&scriptOnDisonnectParams,
595                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
596                 scriptOnDisonnect.c_str(),
597                 login.c_str(),
598                 inet_ntostring(lastIPForDisconnect).c_str(),
599                 cash.ConstData(),
600                 id,
601                 dirs.c_str());
602
603         std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
604         while (it != settings->GetScriptParams().end())
605             {
606             scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
607             ++it;
608             }
609
610         ScriptExec(scriptOnDisonnectParams.c_str());
611         }
612     else
613         {
614         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
615         }
616
617     connected = false;
618     }
619
620 std::string reasonMessage(reason);
621 if (!lastDisconnectReason.empty())
622     reasonMessage += ": " + lastDisconnectReason;
623
624 if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
625                                                                     cash, freeMb, reasonMessage))
626     {
627     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
628     WriteServLog("%s", store->GetStrError().c_str());
629     }
630
631 if (!fakeDisconnect)
632     lastIPForDisconnect = 0;
633
634 sessionUpload.reset();
635 sessionDownload.reset();
636 sessionUploadModTime = stgTime;
637 sessionDownloadModTime = stgTime;
638 }
639 //-----------------------------------------------------------------------------
640 void UserImpl::Run()
641 {
642 STG_LOCKER lock(&mutex);
643
644 if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
645     {
646     printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str());
647     WriteStat();
648     }
649 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
650     {
651     WriteServLog("User: %s. Credit expired.", login.c_str());
652     credit = 0;
653     creditExpire = 0;
654     WriteConf();
655     }
656
657 if (passive.ConstData()
658     && (stgTime % 30 == 0)
659     && (passiveTime.ModificationTime() != stgTime))
660     {
661     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
662     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
663     }
664
665 if (!authorizedBy.empty())
666     {
667     if (connected)
668         properties.Stat().lastActivityTime = stgTime;
669
670     if (!connected && IsInetable())
671         Connect();
672
673     if (connected && !IsInetable())
674         {
675         if (disabled)
676             Disconnect(false, "disabled");
677         else if (passive)
678             Disconnect(false, "passive");
679         else
680             Disconnect(false, "no cash");
681         }
682
683     if (stgTime - lastScanMessages > 10)
684         {
685         ScanMessage();
686         lastScanMessages = stgTime;
687         }
688     }
689 else
690     {
691     if (connected)
692         Disconnect(false, "not authorized");
693     }
694
695 }
696 //-----------------------------------------------------------------------------
697 void UserImpl::UpdatePingTime(time_t t)
698 {
699 STG_LOCKER lock(&mutex);
700 if (t)
701     pingTime = t;
702 else
703     pingTime = stgTime;
704 }
705 //-----------------------------------------------------------------------------
706 bool UserImpl::IsInetable()
707 {
708 if (disabled || passive)
709     return false;
710
711 if (settings->GetFreeMbAllowInet())
712     {
713     if (freeMb >= 0)
714         return true;
715     }
716
717 if (settings->GetShowFeeInCash() || tariff == NULL)
718     return (cash >= -credit);
719
720 return (cash - tariff->GetFee() >= -credit);
721 }
722 //-----------------------------------------------------------------------------
723 std::string UserImpl::GetEnabledDirs() const
724 {
725 return dirsToString(enabledDirs);
726 }
727 //-----------------------------------------------------------------------------
728 #ifdef TRAFF_STAT_WITH_PORTS
729 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
730 #else
731 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
732 #endif
733 {
734 STG_LOCKER lock(&mutex);
735
736 if (!connected || tariff == NULL)
737     return;
738
739 double cost = 0;
740 DirTraff dt(up);
741
742 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
743 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
744
745 dt[dir] += len;
746
747 int tt = tariff->GetTraffType();
748 if (tt == Tariff::TRAFF_UP ||
749     tt == Tariff::TRAFF_UP_DOWN ||
750     // Check NEW traff data
751     (tt == Tariff::TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
752     {
753     double dc = 0;
754     if (traff < threshold &&
755         traff + len >= threshold)
756         {
757         // cash = partBeforeThreshold * priceBeforeThreshold +
758         //        partAfterThreshold * priceAfterThreshold
759         int64_t before = threshold - traff; // Chunk part before threshold
760         int64_t after = len - before; // Chunk part after threshold
761         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
762                                            down.ConstData()[dir],
763                                            dir,
764                                            stgTime) * before +
765              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
766                                            down.ConstData()[dir],
767                                            dir,
768                                            stgTime) * after;
769         }
770     else
771         {
772         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
773                                            down.ConstData()[dir],
774                                            dir,
775                                            stgTime) * len;
776         }
777
778     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
779         cost = dc;
780     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
781         cost = dc - freeMb.ConstData();
782
783     // Direct access to internal data structures via friend-specifier
784     properties.Stat().freeMb -= dc;
785     properties.Stat().cash -= cost;
786     cash.ModifyTime();
787     freeMb.ModifyTime();
788     }
789
790 up = dt;
791 sessionUpload[dir] += len;
792 sessionUploadModTime = stgTime;
793
794 //Add detailed stat
795
796 if (!settings->GetWriteFreeMbTraffCost() &&
797      freeMb.ConstData() >= 0)
798     cost = 0;
799
800 #ifdef TRAFF_STAT_WITH_PORTS
801 IPDirPair idp(ip, dir, port);
802 #else
803 IPDirPair idp(ip, dir);
804 #endif
805
806 std::map<IPDirPair, StatNode>::iterator lb;
807 lb = traffStat.lower_bound(idp);
808 if (lb == traffStat.end() || lb->first != idp)
809     {
810     traffStat.insert(lb,
811                      std::make_pair(idp,
812                                     StatNode(len, 0, cost)));
813     }
814 else
815     {
816     lb->second.cash += cost;
817     lb->second.up += len;
818     }
819 }
820 //-----------------------------------------------------------------------------
821 #ifdef TRAFF_STAT_WITH_PORTS
822 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
823 #else
824 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
825 #endif
826 {
827 STG_LOCKER lock(&mutex);
828
829 if (!connected || tariff == NULL)
830     return;
831
832 double cost = 0;
833 DirTraff dt(down);
834
835 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
836 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
837
838 dt[dir] += len;
839
840 int tt = tariff->GetTraffType();
841 if (tt == Tariff::TRAFF_DOWN ||
842     tt == Tariff::TRAFF_UP_DOWN ||
843     // Check NEW traff data
844     (tt == Tariff::TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
845     {
846     double dc = 0;
847     if (traff < threshold &&
848         traff + len >= threshold)
849         {
850         // cash = partBeforeThreshold * priceBeforeThreshold +
851         //        partAfterThreshold * priceAfterThreshold
852         int64_t before = threshold - traff; // Chunk part before threshold
853         int64_t after = len - before; // Chunk part after threshold
854         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
855                                            down.ConstData()[dir], // Traff before chunk
856                                            dir,
857                                            stgTime) * before +
858              tariff->GetPriceWithTraffType(up.ConstData()[dir],
859                                            dt[dir], // Traff after chunk
860                                            dir,
861                                            stgTime) * after;
862         }
863     else
864         {
865         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
866                                            down.ConstData()[dir],
867                                            dir,
868                                            stgTime) * len;
869         }
870
871     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
872         cost = dc;
873     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
874         cost = dc - freeMb.ConstData();
875
876     properties.Stat().freeMb -= dc;
877     properties.Stat().cash -= cost;
878     cash.ModifyTime();
879     freeMb.ModifyTime();
880     }
881
882 down = dt;
883 sessionDownload[dir] += len;
884 sessionDownloadModTime = stgTime;
885
886 //Add detailed stat
887
888 if (!settings->GetWriteFreeMbTraffCost() &&
889      freeMb.ConstData() >= 0)
890     cost = 0;
891
892 #ifdef TRAFF_STAT_WITH_PORTS
893 IPDirPair idp(ip, dir, port);
894 #else
895 IPDirPair idp(ip, dir);
896 #endif
897
898 std::map<IPDirPair, StatNode>::iterator lb;
899 lb = traffStat.lower_bound(idp);
900 if (lb == traffStat.end() || lb->first != idp)
901     {
902     traffStat.insert(lb,
903                      std::make_pair(idp,
904                                     StatNode(0, len, cost)));
905     }
906 else
907     {
908     lb->second.cash += cost;
909     lb->second.down += len;
910     }
911 }
912 //-----------------------------------------------------------------------------
913 void UserImpl::AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier)
914 {
915 STG_LOCKER lock(&mutex);
916 currIP.AddBeforeNotifier(notifier);
917 }
918 //-----------------------------------------------------------------------------
919 void UserImpl::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier)
920 {
921 STG_LOCKER lock(&mutex);
922 currIP.DelBeforeNotifier(notifier);
923 }
924 //-----------------------------------------------------------------------------
925 void UserImpl::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier)
926 {
927 STG_LOCKER lock(&mutex);
928 currIP.AddAfterNotifier(notifier);
929 }
930 //-----------------------------------------------------------------------------
931 void UserImpl::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier)
932 {
933 STG_LOCKER lock(&mutex);
934 currIP.DelAfterNotifier(notifier);
935 }
936 //-----------------------------------------------------------------------------
937 void UserImpl::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier)
938 {
939 STG_LOCKER lock(&mutex);
940 connected.AddBeforeNotifier(notifier);
941 }
942 //-----------------------------------------------------------------------------
943 void UserImpl::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier)
944 {
945 STG_LOCKER lock(&mutex);
946 connected.DelBeforeNotifier(notifier);
947 }
948 //-----------------------------------------------------------------------------
949 void UserImpl::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier)
950 {
951 STG_LOCKER lock(&mutex);
952 connected.AddAfterNotifier(notifier);
953 }
954 //-----------------------------------------------------------------------------
955 void UserImpl::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier)
956 {
957 STG_LOCKER lock(&mutex);
958 connected.DelAfterNotifier(notifier);
959 }
960 //-----------------------------------------------------------------------------
961 void UserImpl::OnAdd()
962 {
963 STG_LOCKER lock(&mutex);
964
965 std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
966
967 if (access(scriptOnAdd.c_str(), X_OK) == 0)
968     {
969     std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
970
971     ScriptExec(scriptOnAddParams.c_str());
972     }
973 else
974     {
975     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
976     }
977 }
978 //-----------------------------------------------------------------------------
979 void UserImpl::OnDelete()
980 {
981 STG_LOCKER lock(&mutex);
982
983 std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
984
985 if (access(scriptOnDel.c_str(), X_OK) == 0)
986     {
987     std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
988
989     ScriptExec(scriptOnDelParams.c_str());
990     }
991 else
992     {
993     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
994     }
995
996 Run();
997 }
998 //-----------------------------------------------------------------------------
999 int UserImpl::WriteDetailStat(bool hard)
1000 {
1001 printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
1002
1003 if (!traffStatSaved.second.empty())
1004     {
1005     if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
1006         {
1007         printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write detail stat from queue\n");
1008         WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
1009         WriteServLog("%s", store->GetStrError().c_str());
1010         return -1;
1011         }
1012     traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
1013     }
1014
1015 TraffStat ts;
1016
1017     {
1018     STG_LOCKER lock(&mutex);
1019     ts.swap(traffStat);
1020     }
1021
1022 printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size());
1023
1024 if (ts.size() && !disabledDetailStat)
1025     {
1026     if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
1027         {
1028         printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write current detail stat\n");
1029         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
1030         WriteServLog("%s", store->GetStrError().c_str());
1031         if (!hard)
1032             {
1033             printfd(__FILE__, "UserImpl::WriteDetailStat() - pushing detail stat to queue\n");
1034             STG_LOCKER lock(&mutex);
1035             traffStatSaved.second.swap(ts);
1036             traffStatSaved.first = lastWriteDetailedStat;
1037             }
1038         return -1;
1039         }
1040     }
1041 lastWriteDetailedStat = stgTime;
1042 return 0;
1043 }
1044 //-----------------------------------------------------------------------------
1045 double UserImpl::GetPassiveTimePart() const
1046 {
1047 STG_LOCKER lock(&mutex);
1048
1049 static int daysInMonth[12] =
1050 {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 }