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