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