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