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