]> git.stg.codes - stg.git/blob - projects/stargazer/user_impl.cpp
Ticket. The MaybeSet() function call for the 'change-policy' parameter added in
[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     return;
561     }
562 }
563 //-----------------------------------------------------------------------------
564 bool USER_IMPL::IsAuthorizedBy(const AUTH * auth) const
565 {
566 STG_LOCKER lock(&mutex);
567 // Is this user authorized by specified authorizer?
568 return authorizedBy.find(auth) != authorizedBy.end();
569 }
570 //-----------------------------------------------------------------------------
571 std::vector<std::string> USER_IMPL::GetAuthorizers() const
572 {
573     STG_LOCKER lock(&mutex);
574     std::vector<std::string> list;
575     std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), std::mem_fun(&AUTH::GetVersion));
576     return list;
577 }
578 //-----------------------------------------------------------------------------
579 void USER_IMPL::Connect(bool fakeConnect)
580 {
581 /*
582  * Connect user to Internet. This function is differ from Authorize() !!!
583  */
584
585 STG_LOCKER lock(&mutex);
586
587 if (!fakeConnect)
588     {
589     std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
590
591     if (access(scriptOnConnect.c_str(), X_OK) == 0)
592         {
593         std::string dirs = dirsToString(enabledDirs);
594
595         std::string scriptOnConnectParams;
596         strprintf(&scriptOnConnectParams,
597                   "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
598                   scriptOnConnect.c_str(),
599                   login.c_str(),
600                   inet_ntostring(currIP).c_str(),
601                   cash.ConstData(),
602                   id,
603                   dirs.c_str());
604
605         std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
606         while (it != settings->GetScriptParams().end())
607             {
608             scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
609             ++it;
610             }
611
612         ScriptExec(scriptOnConnectParams.c_str());
613         }
614     else
615         {
616         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
617         }
618
619     connected = true;
620     }
621
622 if (store->WriteUserConnect(login, currIP))
623     {
624     WriteServLog("Cannot write connect for user %s.", login.c_str());
625     WriteServLog("%s", store->GetStrError().c_str());
626     }
627
628 if (!fakeConnect)
629     lastIPForDisconnect = currIP;
630 }
631 //-----------------------------------------------------------------------------
632 void USER_IMPL::Disconnect(bool fakeDisconnect, const std::string & reason)
633 {
634 /*
635  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
636  */
637
638 STG_LOCKER lock(&mutex);
639
640 if (!lastIPForDisconnect)
641     {
642     printfd(__FILE__, "lastIPForDisconnect\n");
643     return;
644     }
645
646 if (!fakeDisconnect)
647     {
648     lastDisconnectReason = reason;
649     std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
650
651     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
652         {
653         std::string dirs = dirsToString(enabledDirs);
654
655         std::string scriptOnDisonnectParams;
656         strprintf(&scriptOnDisonnectParams,
657                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
658                 scriptOnDisonnect.c_str(),
659                 login.c_str(),
660                 inet_ntostring(lastIPForDisconnect).c_str(),
661                 cash.ConstData(),
662                 id,
663                 dirs.c_str());
664
665         std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
666         while (it != settings->GetScriptParams().end())
667             {
668             scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
669             ++it;
670             }
671
672         ScriptExec(scriptOnDisonnectParams.c_str());
673         }
674     else
675         {
676         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
677         }
678
679     connected = false;
680     }
681
682 std::string reasonMessage(reason);
683 if (!lastDisconnectReason.empty())
684     reasonMessage += ": " + lastDisconnectReason;
685
686 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
687                                cash, freeMb, reasonMessage))
688     {
689     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
690     WriteServLog("%s", store->GetStrError().c_str());
691     }
692
693 if (!fakeDisconnect)
694     lastIPForDisconnect = 0;
695
696 sessionUpload.Reset();
697 sessionDownload.Reset();
698 sessionUploadModTime = stgTime;
699 sessionDownloadModTime = stgTime;
700 }
701 //-----------------------------------------------------------------------------
702 void USER_IMPL::Run()
703 {
704 STG_LOCKER lock(&mutex);
705
706 if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
707     {
708     printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
709     WriteStat();
710     }
711 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
712     {
713     WriteServLog("User: %s. Credit expired.", login.c_str());
714     credit = 0;
715     creditExpire = 0;
716     WriteConf();
717     }
718
719 if (passive.ConstData()
720     && (stgTime % 30 == 0)
721     && (passiveTime.ModificationTime() != stgTime))
722     {
723     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
724     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
725     }
726
727 if (!authorizedBy.empty())
728     {
729     if (connected)
730         property.Stat().lastActivityTime = stgTime;
731
732     if (!connected && IsInetable())
733         Connect();
734
735     if (connected && !IsInetable())
736         {
737         if (disabled)
738             Disconnect(false, "disabled");
739         else if (passive)
740             Disconnect(false, "passive");
741         else
742             Disconnect(false, "no cash");
743         }
744
745     if (stgTime - lastScanMessages > 10)
746         {
747         ScanMessage();
748         lastScanMessages = stgTime;
749         }
750     }
751 else
752     {
753     if (connected)
754         Disconnect(false, "not authorized");
755     }
756
757 }
758 //-----------------------------------------------------------------------------
759 void USER_IMPL::UpdatePingTime(time_t t)
760 {
761 STG_LOCKER lock(&mutex);
762 if (t)
763     pingTime = t;
764 else
765     pingTime = stgTime;
766 }
767 //-----------------------------------------------------------------------------
768 bool USER_IMPL::IsInetable()
769 {
770 if (disabled || passive)
771     return false;
772
773 if (settings->GetFreeMbAllowInet())
774     {
775     if (freeMb >= 0)
776         return true;
777     }
778
779 if (settings->GetShowFeeInCash() || tariff == NULL)
780     return (cash >= -credit);
781
782 return (cash - tariff->GetFee() >= -credit);
783 }
784 //-----------------------------------------------------------------------------
785 std::string USER_IMPL::GetEnabledDirs() const
786 {
787 return dirsToString(enabledDirs);
788 }
789 //-----------------------------------------------------------------------------
790 #ifdef TRAFF_STAT_WITH_PORTS
791 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
792 #else
793 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
794 #endif
795 {
796 STG_LOCKER lock(&mutex);
797
798 if (!connected || tariff == NULL)
799     return;
800
801 double cost = 0;
802 DIR_TRAFF dt(up);
803
804 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
805 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
806
807 dt[dir] += len;
808
809 int tt = tariff->GetTraffType();
810 if (tt == TARIFF::TRAFF_UP ||
811     tt == TARIFF::TRAFF_UP_DOWN ||
812     // Check NEW traff data
813     (tt == TARIFF::TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
814     {
815     double dc = 0;
816     if (traff < threshold &&
817         traff + len >= threshold)
818         {
819         // cash = partBeforeThreshold * priceBeforeThreshold +
820         //        partAfterThreshold * priceAfterThreshold
821         int64_t before = threshold - traff; // Chunk part before threshold
822         int64_t after = len - before; // Chunk part after threshold
823         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
824                                            down.ConstData()[dir],
825                                            dir,
826                                            stgTime) * before +
827              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
828                                            down.ConstData()[dir],
829                                            dir,
830                                            stgTime) * after;
831         }
832     else
833         {
834         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
835                                            down.ConstData()[dir],
836                                            dir,
837                                            stgTime) * len;
838         }
839
840     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
841         cost = dc;
842     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
843         cost = dc - freeMb.ConstData();
844
845     // Direct access to internal data structures via friend-specifier
846     property.Stat().freeMb -= dc;
847     property.Stat().cash -= cost;
848     cash.ModifyTime();
849     freeMb.ModifyTime();
850     }
851
852 up = dt;
853 sessionUpload[dir] += len;
854 sessionUploadModTime = stgTime;
855
856 //Add detailed stat
857
858 if (!settings->GetWriteFreeMbTraffCost() &&
859      freeMb.ConstData() >= 0)
860     cost = 0;
861
862 #ifdef TRAFF_STAT_WITH_PORTS
863 IP_DIR_PAIR idp(ip, dir, port);
864 #else
865 IP_DIR_PAIR idp(ip, dir);
866 #endif
867
868 std::map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
869 lb = traffStat.lower_bound(idp);
870 if (lb == traffStat.end() || lb->first != idp)
871     {
872     traffStat.insert(lb,
873                      std::make_pair(idp,
874                                     STAT_NODE(len, 0, cost)));
875     }
876 else
877     {
878     lb->second.cash += cost;
879     lb->second.up += len;
880     }
881 }
882 //-----------------------------------------------------------------------------
883 #ifdef TRAFF_STAT_WITH_PORTS
884 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
885 #else
886 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
887 #endif
888 {
889 STG_LOCKER lock(&mutex);
890
891 if (!connected || tariff == NULL)
892     return;
893
894 double cost = 0;
895 DIR_TRAFF dt(down);
896
897 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
898 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
899
900 dt[dir] += len;
901
902 int tt = tariff->GetTraffType();
903 if (tt == TARIFF::TRAFF_DOWN ||
904     tt == TARIFF::TRAFF_UP_DOWN ||
905     // Check NEW traff data
906     (tt == TARIFF::TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
907     {
908     double dc = 0;
909     if (traff < threshold &&
910         traff + len >= threshold)
911         {
912         // cash = partBeforeThreshold * priceBeforeThreshold +
913         //        partAfterThreshold * priceAfterThreshold
914         int64_t before = threshold - traff; // Chunk part before threshold
915         int64_t after = len - before; // Chunk part after threshold
916         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
917                                            down.ConstData()[dir], // Traff before chunk
918                                            dir,
919                                            stgTime) * before +
920              tariff->GetPriceWithTraffType(up.ConstData()[dir],
921                                            dt[dir], // Traff after chunk
922                                            dir,
923                                            stgTime) * after;
924         }
925     else
926         {
927         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
928                                            down.ConstData()[dir],
929                                            dir,
930                                            stgTime) * len;
931         }
932
933     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
934         cost = dc;
935     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
936         cost = dc - freeMb.ConstData();
937
938     property.Stat().freeMb -= dc;
939     property.Stat().cash -= cost;
940     cash.ModifyTime();
941     freeMb.ModifyTime();
942     }
943
944 down = dt;
945 sessionDownload[dir] += len;
946 sessionDownloadModTime = stgTime;
947
948 //Add detailed stat
949
950 if (!settings->GetWriteFreeMbTraffCost() &&
951      freeMb.ConstData() >= 0)
952     cost = 0;
953
954 #ifdef TRAFF_STAT_WITH_PORTS
955 IP_DIR_PAIR idp(ip, dir, port);
956 #else
957 IP_DIR_PAIR idp(ip, dir);
958 #endif
959
960 std::map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
961 lb = traffStat.lower_bound(idp);
962 if (lb == traffStat.end() || lb->first != idp)
963     {
964     traffStat.insert(lb,
965                      std::make_pair(idp,
966                                     STAT_NODE(0, len, cost)));
967     }
968 else
969     {
970     lb->second.cash += cost;
971     lb->second.down += len;
972     }
973 }
974 //-----------------------------------------------------------------------------
975 void USER_IMPL::AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier)
976 {
977 STG_LOCKER lock(&mutex);
978 currIP.AddBeforeNotifier(notifier);
979 }
980 //-----------------------------------------------------------------------------
981 void USER_IMPL::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier)
982 {
983 STG_LOCKER lock(&mutex);
984 currIP.DelBeforeNotifier(notifier);
985 }
986 //-----------------------------------------------------------------------------
987 void USER_IMPL::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier)
988 {
989 STG_LOCKER lock(&mutex);
990 currIP.AddAfterNotifier(notifier);
991 }
992 //-----------------------------------------------------------------------------
993 void USER_IMPL::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier)
994 {
995 STG_LOCKER lock(&mutex);
996 currIP.DelAfterNotifier(notifier);
997 }
998 //-----------------------------------------------------------------------------
999 void USER_IMPL::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier)
1000 {
1001 STG_LOCKER lock(&mutex);
1002 connected.AddBeforeNotifier(notifier);
1003 }
1004 //-----------------------------------------------------------------------------
1005 void USER_IMPL::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier)
1006 {
1007 STG_LOCKER lock(&mutex);
1008 connected.DelBeforeNotifier(notifier);
1009 }
1010 //-----------------------------------------------------------------------------
1011 void USER_IMPL::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier)
1012 {
1013 STG_LOCKER lock(&mutex);
1014 connected.AddAfterNotifier(notifier);
1015 }
1016 //-----------------------------------------------------------------------------
1017 void USER_IMPL::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier)
1018 {
1019 STG_LOCKER lock(&mutex);
1020 connected.DelAfterNotifier(notifier);
1021 }
1022 //-----------------------------------------------------------------------------
1023 void USER_IMPL::OnAdd()
1024 {
1025 STG_LOCKER lock(&mutex);
1026
1027 std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
1028
1029 if (access(scriptOnAdd.c_str(), X_OK) == 0)
1030     {
1031     std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
1032
1033     ScriptExec(scriptOnAddParams.c_str());
1034     }
1035 else
1036     {
1037     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
1038     }
1039 }
1040 //-----------------------------------------------------------------------------
1041 void USER_IMPL::OnDelete()
1042 {
1043 STG_LOCKER lock(&mutex);
1044
1045 std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
1046
1047 if (access(scriptOnDel.c_str(), X_OK) == 0)
1048     {
1049     std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
1050
1051     ScriptExec(scriptOnDelParams.c_str());
1052     }
1053 else
1054     {
1055     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
1056     }
1057
1058 Run();
1059 }
1060 //-----------------------------------------------------------------------------
1061 int USER_IMPL::WriteDetailStat(bool hard)
1062 {
1063 printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
1064
1065 if (!traffStatSaved.second.empty())
1066     {
1067     if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
1068         {
1069         printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
1070         WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
1071         WriteServLog("%s", store->GetStrError().c_str());
1072         return -1;
1073         }
1074     traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
1075     }
1076
1077 TRAFF_STAT ts;
1078
1079     {
1080     STG_LOCKER lock(&mutex);
1081     ts.swap(traffStat);
1082     }
1083
1084 printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
1085
1086 if (ts.size() && !disabledDetailStat)
1087     {
1088     if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
1089         {
1090         printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
1091         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
1092         WriteServLog("%s", store->GetStrError().c_str());
1093         if (!hard)
1094             {
1095             printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
1096             STG_LOCKER lock(&mutex);
1097             traffStatSaved.second.swap(ts);
1098             traffStatSaved.first = lastWriteDetailedStat;
1099             }
1100         return -1;
1101         }
1102     }
1103 lastWriteDetailedStat = stgTime;
1104 return 0;
1105 }
1106 //-----------------------------------------------------------------------------
1107 double USER_IMPL::GetPassiveTimePart() const
1108 {
1109 STG_LOCKER lock(&mutex);
1110
1111 static int daysInMonth[12] =
1112 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1113
1114 struct tm tms;
1115 time_t t = stgTime;
1116 localtime_r(&t, &tms);
1117
1118 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
1119
1120 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
1121     {
1122     // Leap year
1123     secMonth += 24 * 3600;
1124     }
1125
1126 time_t dt = secMonth - passiveTime;
1127
1128 if (dt < 0)
1129     dt = 0;
1130
1131 return static_cast<double>(dt) / secMonth;
1132 }
1133 //-----------------------------------------------------------------------------
1134 void USER_IMPL::SetPassiveTimeAsNewUser()
1135 {
1136 STG_LOCKER lock(&mutex);
1137
1138 time_t t = stgTime;
1139 struct tm tm;
1140 localtime_r(&t, &tm);
1141 int daysCurrMon = DaysInCurrentMonth();
1142 double pt = tm.tm_mday - 1;
1143 pt /= daysCurrMon;
1144
1145 passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
1146 }
1147 //-----------------------------------------------------------------------------
1148 void USER_IMPL::MidnightResetSessionStat()
1149 {
1150 STG_LOCKER lock(&mutex);
1151
1152 if (connected)
1153     {
1154     Disconnect(true, "fake");
1155     Connect(true);
1156     }
1157 }
1158 //-----------------------------------------------------------------------------
1159 void USER_IMPL::ProcessNewMonth()
1160 {
1161 STG_LOCKER lock(&mutex);
1162 //  Reset traff
1163 if (connected)
1164     Disconnect(true, "fake");
1165
1166 WriteMonthStat();
1167
1168 property.Stat().monthUp.Reset();
1169 property.Stat().monthDown.Reset();
1170
1171 if (connected)
1172     Connect(true);
1173
1174 //  Set new tariff
1175 if (nextTariff.ConstData() != "")
1176     {
1177     const TARIFF * nt = tariffs->FindByName(nextTariff);
1178     if (nt == NULL)
1179         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1180                      login.c_str(), property.tariffName.Get().c_str());
1181     else
1182         property.tariffName.Set(nextTariff, sysAdmin, login, store);
1183     ResetNextTariff();
1184     WriteConf();
1185     }
1186 }
1187 //-----------------------------------------------------------------------------
1188 void USER_IMPL::ProcessDayFeeSpread()
1189 {
1190 STG_LOCKER lock(&mutex);
1191
1192 if (passive.ConstData() || tariff == NULL)
1193     return;
1194
1195 if (tariff->GetPeriod() != TARIFF::MONTH)
1196     return;
1197
1198 double fee = tariff->GetFee() / DaysInCurrentMonth();
1199
1200 if (std::fabs(fee) < 1.0e-3)
1201     return;
1202
1203 double c = cash;
1204 switch (settings->GetFeeChargeType())
1205     {
1206     case 0:
1207         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1208         break;
1209     case 1:
1210         if (c + credit >= 0)
1211             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1212         break;
1213     case 2:
1214         if (c + credit >= fee)
1215             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1216         break;
1217     case 3:
1218         if (c >= 0)
1219             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1220         break;
1221     }
1222 ResetPassiveTime();
1223 }
1224 //-----------------------------------------------------------------------------
1225 void USER_IMPL::ProcessDayFee()
1226 {
1227 STG_LOCKER lock(&mutex);
1228
1229 if (tariff == NULL)
1230     return;
1231
1232 if (tariff->GetPeriod() != TARIFF::MONTH)
1233     return;
1234
1235 double passiveTimePart = 1.0;
1236 if (!settings->GetFullFee())
1237     {
1238     passiveTimePart = GetPassiveTimePart();
1239     }
1240 else
1241     {
1242     if (passive.ConstData())
1243         {
1244         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1245         return;
1246         }
1247     }
1248 double fee = tariff->GetFee() * passiveTimePart;
1249
1250 ResetPassiveTime();
1251
1252 if (std::fabs(fee) < 1.0e-3)
1253     {
1254     SetPrepaidTraff();
1255     return;
1256     }
1257
1258 double c = cash;
1259 printfd(__FILE__, "login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
1260         login.c_str(),
1261         cash.ConstData(),
1262         credit.ConstData(),
1263         tariff->GetFee(),
1264         passiveTimePart,
1265         fee);
1266 switch (settings->GetFeeChargeType())
1267     {
1268     case 0:
1269         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1270         SetPrepaidTraff();
1271         break;
1272     case 1:
1273         if (c + credit >= 0)
1274             {
1275             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1276             SetPrepaidTraff();
1277             }
1278         break;
1279     case 2:
1280         if (c + credit >= fee)
1281             {
1282             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1283             SetPrepaidTraff();
1284             }
1285         break;
1286     case 3:
1287         if (c >= 0)
1288             {
1289             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1290             SetPrepaidTraff();
1291             }
1292         break;
1293     }
1294 }
1295 //-----------------------------------------------------------------------------
1296 void USER_IMPL::ProcessDailyFee()
1297 {
1298 STG_LOCKER lock(&mutex);
1299
1300 if (passive.ConstData() || tariff == NULL)
1301     return;
1302
1303 if (tariff->GetPeriod() != TARIFF::DAY)
1304     return;
1305
1306 double fee = tariff->GetFee();
1307
1308 if (fee == 0.0)
1309     return;
1310
1311 double c = cash;
1312 switch (settings->GetFeeChargeType())
1313     {
1314     case 0:
1315         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1316         break;
1317     case 1:
1318         if (c + credit >= 0)
1319             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1320         break;
1321     case 2:
1322         if (c + credit >= fee)
1323             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1324         break;
1325     }
1326 ResetPassiveTime();
1327 }
1328 //-----------------------------------------------------------------------------
1329 void USER_IMPL::ProcessServices()
1330 {
1331 struct tm tms;
1332 time_t t = stgTime;
1333 localtime_r(&t, &tms);
1334
1335 double passiveTimePart = 1.0;
1336 if (!settings->GetFullFee())
1337     {
1338     passiveTimePart = GetPassiveTimePart();
1339     }
1340 else
1341     {
1342     if (passive.ConstData())
1343         {
1344         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1345         return;
1346         }
1347     }
1348
1349 for (size_t i = 0; i < property.Conf().services.size(); ++i)
1350     {
1351     SERVICE_CONF conf;
1352     if (m_services.Find(property.Conf().services[i], &conf))
1353         continue;
1354     if (conf.payDay == tms.tm_mday ||
1355         (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
1356         {
1357         double c = cash;
1358         double fee = conf.cost * passiveTimePart;
1359         printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
1360                 login.c_str(),
1361                 cash.ConstData(),
1362                 credit.ConstData(),
1363                 tariff->GetFee(),
1364                 passiveTimePart,
1365                 fee);
1366         switch (settings->GetFeeChargeType())
1367             {
1368             case 0:
1369                 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1370                 SetPrepaidTraff();
1371                 break;
1372             case 1:
1373                 if (c + credit >= 0)
1374                     {
1375                     property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1376                     SetPrepaidTraff();
1377                     }
1378                 break;
1379             case 2:
1380                 if (c + credit >= fee)
1381                     {
1382                     property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1383                     SetPrepaidTraff();
1384                     }
1385                 break;
1386             case 3:
1387                 if (c >= 0)
1388                     {
1389                     property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1390                     SetPrepaidTraff();
1391                     }
1392                 break;
1393             }
1394         }
1395     }
1396 }
1397 //-----------------------------------------------------------------------------
1398 void USER_IMPL::SetPrepaidTraff()
1399 {
1400 if (tariff != NULL)
1401     property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1402 }
1403 //-----------------------------------------------------------------------------
1404 int USER_IMPL::AddMessage(STG_MSG * msg)
1405 {
1406 STG_LOCKER lock(&mutex);
1407
1408 if (SendMessage(*msg))
1409     {
1410     if (store->AddMessage(msg, login))
1411         {
1412         errorStr = store->GetStrError();
1413         WriteServLog("Error adding message: '%s'", errorStr.c_str());
1414         printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1415         return -1;
1416         }
1417     messages.push_back(*msg);
1418     }
1419 else
1420     {
1421     if (msg->header.repeat > 0)
1422         {
1423         msg->header.repeat--;
1424         #ifndef DEBUG
1425         //TODO: gcc v. 4.x generate ICE on x86_64
1426         msg->header.lastSendTime = static_cast<int>(time(NULL));
1427         #else
1428         msg->header.lastSendTime = static_cast<int>(stgTime);
1429         #endif
1430         if (store->AddMessage(msg, login))
1431             {
1432             errorStr = store->GetStrError();
1433             WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1434             printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1435             return -1;
1436             }
1437         messages.push_back(*msg);
1438         }
1439     }
1440 return 0;
1441 }
1442 //-----------------------------------------------------------------------------
1443 int USER_IMPL::SendMessage(STG_MSG & msg) const
1444 {
1445 // No lock `cause we are already locked from caller
1446 int ret = -1;
1447 std::set<const AUTH*>::iterator it(authorizedBy.begin());
1448 while (it != authorizedBy.end())
1449     {
1450     if (!(*it++)->SendMessage(msg, currIP))
1451         ret = 0;
1452     }
1453 if (!ret)
1454     {
1455 #ifndef DEBUG
1456     //TODO: gcc v. 4.x generate ICE on x86_64
1457     msg.header.lastSendTime = static_cast<int>(time(NULL));
1458 #else
1459     msg.header.lastSendTime = static_cast<int>(stgTime);
1460 #endif
1461     msg.header.repeat--;
1462     }
1463 return ret;
1464 }
1465 //-----------------------------------------------------------------------------
1466 void USER_IMPL::ScanMessage()
1467 {
1468 // No lock `cause we are already locked from caller
1469 // We need not check for the authorizedBy `cause it has already checked by caller
1470
1471 std::list<STG_MSG>::iterator it(messages.begin());
1472 while (it != messages.end())
1473     {
1474     if (settings->GetMessageTimeout() > 0 &&
1475         difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1476         {
1477         // Timeout exceeded
1478         if (store->DelMessage(it->header.id, login))
1479             {
1480             WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1481             printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1482             }
1483         messages.erase(it++);
1484         continue;
1485         }
1486     if (it->GetNextSendTime() <= stgTime)
1487         {
1488         if (SendMessage(*it))
1489             {
1490             // We need to check all messages in queue for timeout
1491             ++it;
1492             continue;
1493             }
1494         if (it->header.repeat < 0)
1495             {
1496             if (store->DelMessage(it->header.id, login))
1497                 {
1498                 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1499                 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1500                 }
1501             messages.erase(it++);
1502             }
1503         else
1504             {
1505             if (store->EditMessage(*it, login))
1506                 {
1507                 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1508                 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1509                 }
1510             ++it;
1511             }
1512         }
1513     else
1514         {
1515         ++it;
1516         }
1517     }
1518 }
1519 //-----------------------------------------------------------------------------
1520 std::string USER_IMPL::GetParamValue(const std::string & name) const
1521 {
1522     std::string lowerName = ToLower(name);
1523     if (lowerName == "id")
1524         {
1525         std::ostringstream stream;
1526         stream << id;
1527         return stream.str();
1528         }
1529     if (lowerName == "login")       return login;
1530     if (lowerName == "currip")      return currIP.ToString();
1531     if (lowerName == "enableddirs") return GetEnabledDirs();
1532     if (lowerName == "tariff")      return property.tariffName;
1533     if (property.Exists(lowerName))
1534         return property.GetPropertyValue(lowerName);
1535     else
1536         {
1537         WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
1538         return "";
1539         }
1540 }
1541 //-----------------------------------------------------------------------------
1542 //-----------------------------------------------------------------------------
1543 //-----------------------------------------------------------------------------
1544 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1545 {
1546 if (newPassive && !oldPassive && user->tariff != NULL)
1547     user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1548                             user->sysAdmin,
1549                             user->login,
1550                             user->store,
1551                             "Freeze");
1552 }
1553 //-----------------------------------------------------------------------------
1554 void CHG_DISABLED_NOTIFIER::Notify(const int & oldValue, const int & newValue)
1555 {
1556 if (oldValue && !newValue && user->GetConnected())
1557     user->Disconnect(false, "disabled");
1558 else if (!oldValue && newValue && user->IsInetable())
1559     user->Connect(false);
1560 }
1561 //-----------------------------------------------------------------------------
1562 void CHG_TARIFF_NOTIFIER::Notify(const std::string &, const std::string & newTariff)
1563 {
1564 if (user->settings->GetReconnectOnTariffChange() && user->connected)
1565     user->Disconnect(false, "Change tariff");
1566 user->tariff = user->tariffs->FindByName(newTariff);
1567 if (user->settings->GetReconnectOnTariffChange() &&
1568     !user->authorizedBy.empty() &&
1569     user->IsInetable())
1570     user->Connect(false);
1571 }
1572 //-----------------------------------------------------------------------------
1573 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1574 {
1575 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1576 user->lastCashAdd = newCash - oldCash;
1577 }
1578 //-----------------------------------------------------------------------------
1579 void CHG_IPS_NOTIFIER::Notify(const USER_IPS & from, const USER_IPS & to)
1580 {
1581 printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.GetIpStr().c_str(), to.GetIpStr().c_str());
1582 if (user->connected)
1583     user->Disconnect(false, "Change IP");
1584 if (!user->authorizedBy.empty() && user->IsInetable())
1585     user->Connect(false);
1586 }