]> git.stg.codes - stg.git/blob - projects/stargazer/user_impl.cpp
7b0348bc57e75928936640cbed90d90bd9b28481
[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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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()
825 {
826 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
1020 currIP.AddBeforeNotifier(notifier);
1021 }
1022 //-----------------------------------------------------------------------------
1023 void USER_IMPL::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier)
1024 {
1025 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1026 currIP.DelBeforeNotifier(notifier);
1027 }
1028 //-----------------------------------------------------------------------------
1029 void USER_IMPL::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier)
1030 {
1031 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1032 currIP.AddAfterNotifier(notifier);
1033 }
1034 //-----------------------------------------------------------------------------
1035 void USER_IMPL::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier)
1036 {
1037 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1038 currIP.DelAfterNotifier(notifier);
1039 }
1040 //-----------------------------------------------------------------------------
1041 void USER_IMPL::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier)
1042 {
1043 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1044 connected.AddBeforeNotifier(notifier);
1045 }
1046 //-----------------------------------------------------------------------------
1047 void USER_IMPL::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier)
1048 {
1049 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1050 connected.DelBeforeNotifier(notifier);
1051 }
1052 //-----------------------------------------------------------------------------
1053 void USER_IMPL::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier)
1054 {
1055 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1056 connected.AddAfterNotifier(notifier);
1057 }
1058 //-----------------------------------------------------------------------------
1059 void USER_IMPL::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier)
1060 {
1061 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1062 connected.DelAfterNotifier(notifier);
1063 }
1064 //-----------------------------------------------------------------------------
1065 void USER_IMPL::OnAdd()
1066 {
1067 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
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, __FILE__, __LINE__);
1252
1253 if (passive.ConstData() || tariff == NULL)
1254     return;
1255
1256 double fee = tariff->GetFee() / DaysInCurrentMonth();
1257
1258 if (std::fabs(fee) < 1.0e-3)
1259     return;
1260
1261 double c = cash;
1262 switch (settings->GetFeeChargeType())
1263     {
1264     case 0:
1265         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1266         break;
1267     case 1:
1268         if (c + credit >= 0)
1269             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1270         break;
1271     case 2:
1272         if (c + credit >= fee)
1273             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1274         break;
1275     case 3:
1276         if (c >= 0)
1277             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1278         break;
1279     }
1280 ResetPassiveTime();
1281 }
1282 //-----------------------------------------------------------------------------
1283 void USER_IMPL::ProcessDayFee()
1284 {
1285 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1286
1287 if (tariff == NULL)
1288     return;
1289
1290 double passiveTimePart = 1.0;
1291 if (!settings->GetFullFee())
1292     {
1293     passiveTimePart = GetPassiveTimePart();
1294     }
1295 else
1296     {
1297     if (passive.ConstData())
1298         {
1299         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1300         return;
1301         }
1302     }
1303 double fee = tariff->GetFee() * passiveTimePart;
1304
1305 ResetPassiveTime();
1306
1307 if (std::fabs(fee) < 1.0e-3)
1308     {
1309     SetPrepaidTraff();
1310     return;
1311     }
1312
1313 double c = cash;
1314 printfd(__FILE__, "login: %8s Cash=%f Credit=%f  Fee=%f PassiveTimePart=%f fee=%f\n",
1315         login.c_str(),
1316         cash.ConstData(),
1317         credit.ConstData(),
1318         tariff->GetFee(),
1319         passiveTimePart,
1320         fee);
1321 switch (settings->GetFeeChargeType())
1322     {
1323     case 0:
1324         property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1325         SetPrepaidTraff();
1326         break;
1327     case 1:
1328         if (c + credit >= 0)
1329             {
1330             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1331             SetPrepaidTraff();
1332             }
1333         break;
1334     case 2:
1335         if (c + credit >= fee)
1336             {
1337             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1338             SetPrepaidTraff();
1339             }
1340         break;
1341     case 3:
1342         if (c >= 0)
1343             {
1344             property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1345             SetPrepaidTraff();
1346             }
1347         break;
1348     }
1349 }
1350 //-----------------------------------------------------------------------------
1351 void USER_IMPL::SetPrepaidTraff()
1352 {
1353 if (tariff != NULL)
1354     property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1355 }
1356 //-----------------------------------------------------------------------------
1357 int USER_IMPL::AddMessage(STG_MSG * msg)
1358 {
1359 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1360
1361 if (SendMessage(*msg))
1362     {
1363     if (store->AddMessage(msg, login))
1364         {
1365         errorStr = store->GetStrError();
1366         WriteServLog("Error adding message: '%s'", errorStr.c_str());
1367         printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1368         return -1;
1369         }
1370     messages.push_back(*msg);
1371     }
1372 else
1373     {
1374     if (msg->header.repeat > 0)
1375         {
1376         msg->header.repeat--;
1377         #ifndef DEBUG
1378         //TODO: gcc v. 4.x generate ICE on x86_64
1379         msg->header.lastSendTime = static_cast<int>(time(NULL));
1380         #else
1381         msg->header.lastSendTime = static_cast<int>(stgTime);
1382         #endif
1383         if (store->AddMessage(msg, login))
1384             {
1385             errorStr = store->GetStrError();
1386             WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1387             printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1388             return -1;
1389             }
1390         messages.push_back(*msg);
1391         }
1392     }
1393 return 0;
1394 }
1395 //-----------------------------------------------------------------------------
1396 int USER_IMPL::SendMessage(STG_MSG & msg) const
1397 {
1398 // No lock `cause we are already locked from caller
1399 int ret = -1;
1400 std::set<const AUTH*>::iterator it(authorizedBy.begin());
1401 while (it != authorizedBy.end())
1402     {
1403     if (!(*it++)->SendMessage(msg, currIP))
1404         ret = 0;
1405     }
1406 if (!ret)
1407     {
1408 #ifndef DEBUG
1409     //TODO: gcc v. 4.x generate ICE on x86_64
1410     msg.header.lastSendTime = static_cast<int>(time(NULL));
1411 #else
1412     msg.header.lastSendTime = static_cast<int>(stgTime);
1413 #endif
1414     msg.header.repeat--;
1415     }
1416 return ret;
1417 }
1418 //-----------------------------------------------------------------------------
1419 void USER_IMPL::ScanMessage()
1420 {
1421 // No lock `cause we are already locked from caller
1422 // We need not check for the authorizedBy `cause it has already checked by caller
1423
1424 std::list<STG_MSG>::iterator it(messages.begin());
1425 while (it != messages.end())
1426     {
1427     if (settings->GetMessageTimeout() > 0 &&
1428         difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1429         {
1430         // Timeout exceeded
1431         if (store->DelMessage(it->header.id, login))
1432             {
1433             WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1434             printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1435             }
1436         messages.erase(it++);
1437         continue;
1438         }
1439     if (it->GetNextSendTime() <= stgTime)
1440         {
1441         if (SendMessage(*it))
1442             {
1443             // We need to check all messages in queue for timeout
1444             ++it;
1445             continue;
1446             }
1447         if (it->header.repeat < 0)
1448             {
1449             if (store->DelMessage(it->header.id, login))
1450                 {
1451                 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1452                 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1453                 }
1454             messages.erase(it++);
1455             }
1456         else
1457             {
1458             if (store->EditMessage(*it, login))
1459                 {
1460                 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1461                 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1462                 }
1463             ++it;
1464             }
1465         }
1466     else
1467         {
1468         ++it;
1469         }
1470     }
1471 }
1472 //-----------------------------------------------------------------------------
1473 std::string USER_IMPL::GetParamValue(const std::string & name) const
1474 {
1475 if (name == "freeMb")       return property.freeMb.ToString();
1476 if (name == "passive")      return property.passive.ToString();
1477 if (name == "disabled")     return property.disabled.ToString();
1478 if (name == "alwaysOnline") return property.alwaysOnline.ToString();
1479 if (name == "tariffName")   return property.tariffName;
1480 if (name == "nextTariff")   return property.nextTariff;
1481 if (name == "address")      return property.address;
1482 if (name == "note")         return property.note;
1483 if (name == "group")        return property.group;
1484 if (name == "email")        return property.email;
1485 if (name == "phone")        return property.phone;
1486 if (name == "realName")     return property.realName;
1487 if (name == "credit")       return property.credit.ToString();
1488 if (name == "userdata0")    return property.userdata0;
1489 if (name == "userdata1")    return property.userdata1;
1490 if (name == "userdata2")    return property.userdata2;
1491 if (name == "userdata3")    return property.userdata3;
1492 if (name == "userdata4")    return property.userdata4;
1493 if (name == "userdata5")    return property.userdata5;
1494 if (name == "userdata6")    return property.userdata6;
1495 if (name == "userdata7")    return property.userdata7;
1496 if (name == "userdata8")    return property.userdata8;
1497 if (name == "userdata9")    return property.userdata9;
1498 if (name == "cash")         return property.cash.ToString();
1499 if (name == "id")
1500     {
1501     std::stringstream stream;
1502     stream << id;
1503     return stream.str();;
1504     }
1505 if (name == "login")        return login;
1506 if (name == "ip")           return currIP.ToString();
1507 return "";
1508 }
1509 //-----------------------------------------------------------------------------
1510 //-----------------------------------------------------------------------------
1511 //-----------------------------------------------------------------------------
1512 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1513 {
1514 if (newPassive && !oldPassive && user->tariff != NULL)
1515     user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1516                             user->sysAdmin,
1517                             user->login,
1518                             user->store,
1519                             "Freeze");
1520 }
1521 //-----------------------------------------------------------------------------
1522 void CHG_DISABLED_NOTIFIER::Notify(const int & oldValue, const int & newValue)
1523 {
1524 if (oldValue && !newValue && user->GetConnected())
1525     {
1526     user->Disconnect(false, "disabled");
1527     }
1528 else if (!oldValue && newValue && user->IsInetable())
1529     {
1530     user->Connect(false);
1531     }
1532
1533 }
1534 //-----------------------------------------------------------------------------
1535 void CHG_TARIFF_NOTIFIER::Notify(const std::string &, const std::string & newTariff)
1536 {
1537 if (user->settings->GetReconnectOnTariffChange() && user->connected)
1538     user->Disconnect(false, "Change tariff");
1539 user->tariff = user->tariffs->FindByName(newTariff);
1540 if (user->settings->GetReconnectOnTariffChange() &&
1541     !user->authorizedBy.empty() &&
1542     user->IsInetable())
1543     user->Connect(false);
1544 }
1545 //-----------------------------------------------------------------------------
1546 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1547 {
1548 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1549 user->lastCashAdd = newCash - oldCash;
1550 }
1551 //-----------------------------------------------------------------------------
1552 void CHG_IPS_NOTIFIER::Notify(const USER_IPS & from, const USER_IPS & to)
1553 {
1554     printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.GetIpStr().c_str(), to.GetIpStr().c_str());
1555     if (user->connected)
1556         user->Disconnect(false, "Change IP");
1557     if (!user->authorizedBy.empty() && user->IsInetable())
1558         user->Connect(false);
1559 }
1560 //-----------------------------------------------------------------------------