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