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