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