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