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