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