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