]> git.stg.codes - stg.git/blob - projects/stargazer/user.cpp
Добавляем XML-конфигуратор (уж много желающих, пусть будет, мне не жалко)
[stg.git] / projects / stargazer / user.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 <pthread.h>
36 #include <unistd.h> // access
37
38 #include <cassert>
39
40 #include "user.h"
41 #include "common.h"
42 #include "settings.h"
43 #include "script_executer.h"
44 #include "tariff.h"
45 #include "tariffs.h"
46 #include "admin.h"
47
48 USER::USER(const SETTINGS * s,
49            const BASE_STORE * st,
50            const TARIFFS * t,
51            const ADMIN & a,
52            const map<uint32_t, user_iter> * ipIdx)
53     : property(s),
54       WriteServLog(GetStgLogger()),
55       login(),
56       id(0),
57       __connected(0),
58       connected(__connected),
59       userIDGenerator(),
60       __currIP(0),
61       currIP(__currIP),
62       lastIPForDisconnect(0),
63       pingTime(0),
64       sysAdmin(a),
65       store(st),
66       tariffs(t),
67       tariff(tariffs->GetNoTariff()),
68       cash(property.cash),
69       up(property.up),
70       down(property.down),
71       lastCashAdd(property.lastCashAdd),
72       passiveTime(property.passiveTime),
73       lastCashAddTime(property.lastCashAddTime),
74       freeMb(property.freeMb),
75       lastActivityTime(property.lastActivityTime),
76       password(property.password),
77       passive(property.passive),
78       disabled(property.disabled),
79       disabledDetailStat(property.disabledDetailStat),
80       alwaysOnline(property.alwaysOnline),
81       tariffName(property.tariffName),
82       nextTariff(property.nextTariff),
83       address(property.address),
84       note(property.note),
85       group(property.group),
86       email(property.email),
87       phone(property.phone),
88       realName(property.realName),
89       credit(property.credit),
90       creditExpire(property.creditExpire),
91       ips(property.ips),
92       userdata0(property.userdata0),
93       userdata1(property.userdata1),
94       userdata2(property.userdata2),
95       userdata3(property.userdata3),
96       userdata4(property.userdata4),
97       userdata5(property.userdata5),
98       userdata6(property.userdata6),
99       userdata7(property.userdata7),
100       userdata8(property.userdata8),
101       userdata9(property.userdata9),
102       passiveNotifier(this),
103       tariffNotifier(this),
104       cashNotifier(this),
105       ipNotifier(this)
106 {
107 settings = s;
108 ipIndex = ipIdx;
109
110 password = "*_EMPTY_PASSWORD_*";
111 tariffName = NO_TARIFF_NAME;
112 connected = 0;
113 traffStatInUse = 0;
114 traffStat = &traffStatInternal[0];
115 tariff = tariffs->GetNoTariff();
116 ips = StrToIPS("*");
117 deleted = false;
118 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
119 lastWriteDeatiledStat = stgTime;
120 lastSwapDeatiledStat = stgTime;
121
122 property.tariffName.AddBeforeNotifier(&tariffNotifier);
123 property.passive.AddBeforeNotifier(&passiveNotifier);
124 property.cash.AddBeforeNotifier(&cashNotifier);
125 currIP.AddAfterNotifier(&ipNotifier);
126
127 lastScanMessages = 0;
128
129 writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
130
131 pthread_mutexattr_t attr;
132 pthread_mutexattr_init(&attr);
133 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
134 pthread_mutex_init(&mutex, &attr);
135 }
136 //-----------------------------------------------------------------------------
137 USER::USER(const USER & u)
138     : property(u.settings),
139       WriteServLog(GetStgLogger()),
140       login(u.login),
141       id(u.id),
142       __connected(u.__connected),
143       connected(__connected),
144       __currIP(u.__currIP),
145       currIP(__currIP),
146       lastIPForDisconnect(0),
147       pingTime(u.pingTime),
148       sysAdmin(u.sysAdmin),
149       store(u.store),
150       tariffs(u.tariffs),
151       tariff(u.tariff),
152       cash(property.cash),
153       up(property.up),
154       down(property.down),
155       lastCashAdd(property.lastCashAdd),
156       passiveTime(property.passiveTime),
157       lastCashAddTime(property.lastCashAddTime),
158       freeMb(property.freeMb),
159       lastActivityTime(property.lastActivityTime),
160       password(property.password),
161       passive(property.passive),
162       disabled(property.disabled),
163       disabledDetailStat(property.disabledDetailStat),
164       alwaysOnline(property.alwaysOnline),
165       tariffName(property.tariffName),
166       nextTariff(property.nextTariff),
167       address(property.address),
168       note(property.note),
169       group(property.group),
170       email(property.email),
171       phone(property.phone),
172       realName(property.realName),
173       credit(property.credit),
174       creditExpire(property.creditExpire),
175       ips(property.ips),
176       userdata0(property.userdata0),
177       userdata1(property.userdata1),
178       userdata2(property.userdata2),
179       userdata3(property.userdata3),
180       userdata4(property.userdata4),
181       userdata5(property.userdata5),
182       userdata6(property.userdata6),
183       userdata7(property.userdata7),
184       userdata8(property.userdata8),
185       userdata9(property.userdata9),
186       passiveNotifier(this),
187       tariffNotifier(this),
188       cashNotifier(this),
189       ipNotifier(this)
190 {
191 if (&u == this)
192     return;
193
194 connected = 0;
195 traffStatInUse = 0;
196
197 ipIndex = u.ipIndex;
198
199 deleted = u.deleted;
200 traffStat = &traffStatInternal[traffStatInUse % 2];
201 traffStatToWrite = &traffStatInternal[(traffStatInUse +1) % 2];
202
203 lastWriteStat = u.lastWriteStat;
204 lastWriteDeatiledStat = u.lastWriteDeatiledStat;
205 lastSwapDeatiledStat = u.lastSwapDeatiledStat;
206
207 settings = u.settings;
208
209 property.tariffName.AddBeforeNotifier(&tariffNotifier);
210 property.passive.AddBeforeNotifier(&passiveNotifier);
211 property.cash.AddBeforeNotifier(&cashNotifier);
212 currIP.AddAfterNotifier(&ipNotifier);
213
214 lastScanMessages = 0;
215
216 writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
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 //-----------------------------------------------------------------------------
224 USER::~USER()
225 {
226 property.passive.DelBeforeNotifier(&passiveNotifier);
227 property.tariffName.DelBeforeNotifier(&tariffNotifier);
228 pthread_mutex_destroy(&mutex);
229 }
230 //-----------------------------------------------------------------------------
231 void USER::SetLogin(string const & l)
232 {
233 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
234 assert(login.empty() && "Login is already set");
235 login = l;
236 id = userIDGenerator.GetNextID();
237 }
238 //-----------------------------------------------------------------------------
239 int USER::ReadConf()
240 {
241 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
242 USER_CONF uc;
243
244 if (store->RestoreUserConf(&uc, login))
245     {
246     WriteServLog("Cannot read conf for user %s.", login.c_str());
247     WriteServLog("%s", store->GetStrError().c_str());
248     printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
249     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
250     return -1;
251     }
252
253 password = uc.password;
254 passive = uc.passive;
255 disabled = uc.disabled;
256 disabledDetailStat = uc.disabledDetailStat;
257 alwaysOnline = uc.alwaysOnline;
258 tariffName = uc.tariffName;
259 address = uc.address;
260 phone = uc.phone;
261 email = uc.email;
262 note = uc.note;
263 realName = uc.realName;
264 group = uc.group;
265 credit = uc.credit;
266 nextTariff = uc.nextTariff;
267 userdata0 = uc.userdata[0];
268 userdata1 = uc.userdata[1];
269 userdata2 = uc.userdata[2];
270 userdata3 = uc.userdata[3];
271 userdata4 = uc.userdata[4];
272 userdata5 = uc.userdata[5];
273 userdata6 = uc.userdata[6];
274 userdata7 = uc.userdata[7];
275 userdata8 = uc.userdata[8];
276 userdata9 = uc.userdata[9];
277
278 creditExpire = uc.creditExpire;
279 ips = uc.ips;
280
281 tariff = tariffs->FindByName(tariffName);
282 if (tariff == NULL)
283     {
284     WriteServLog("Cannot read user %s. Tariff %s not exist.",
285                  login.c_str(), property.tariffName.Get().c_str());
286     return -1;
287     }
288
289 return 0;
290 }
291 //-----------------------------------------------------------------------------
292 int USER::ReadStat()
293 {
294 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
295 USER_STAT us;
296
297 if (store->RestoreUserStat(&us, login))
298     {
299     WriteServLog("Cannot read stat for user %s.", login.c_str());
300     WriteServLog("%s", store->GetStrError().c_str());
301     printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
302     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
303     return -1;
304     }
305
306 up = us.up;
307 down = us.down;
308 cash = us.cash;
309 freeMb = us.freeMb;
310 lastCashAdd = us.lastCashAdd;
311 lastCashAddTime = us.lastCashAddTime;
312 passiveTime = us.passiveTime;
313 lastActivityTime = us.lastActivityTime;
314
315 return 0;
316 }
317 //-----------------------------------------------------------------------------
318 int USER::WriteConf()
319 {
320 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
321 USER_CONF uc;
322
323 uc.password = password;
324 uc.passive = passive;
325 uc.disabled = disabled;
326 uc.disabledDetailStat = disabledDetailStat;
327 uc.alwaysOnline = alwaysOnline;
328 uc.tariffName = tariffName;
329 uc.address = address;
330 uc.phone = phone;
331 uc.email = email;
332 uc.note = note;
333 uc.realName = realName;
334 uc.group = group;
335 uc.credit = credit;
336 uc.nextTariff = nextTariff;
337 uc.userdata[0] = userdata0;
338 uc.userdata[1] = userdata1;
339 uc.userdata[2] = userdata2;
340 uc.userdata[3] = userdata3;
341 uc.userdata[4] = userdata4;
342 uc.userdata[5] = userdata5;
343 uc.userdata[6] = userdata6;
344 uc.userdata[7] = userdata7;
345 uc.userdata[8] = userdata8;
346 uc.userdata[9] = userdata9;
347
348 uc.creditExpire = creditExpire;
349 uc.ips = ips;
350
351 printfd(__FILE__, "USER::WriteConf()\n");
352
353 if (store->SaveUserConf(uc, login))
354     {
355     WriteServLog("Cannot write conf for user %s.", login.c_str());
356     WriteServLog("%s", store->GetStrError().c_str());
357     printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
358     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
359     return -1;
360     }
361
362 return 0;
363 }
364 //-----------------------------------------------------------------------------
365 int USER::WriteStat()
366 {
367 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
368 USER_STAT us;
369
370 us.up = up;
371 us.down = down;
372 us.cash = cash;
373 us.freeMb = freeMb;
374 us.lastCashAdd = lastCashAdd;
375 us.lastCashAddTime = lastCashAddTime;
376 us.passiveTime = passiveTime;
377 us.lastActivityTime = lastActivityTime;
378
379 printfd(__FILE__, "USER::WriteStat()\n");
380
381 if (store->SaveUserStat(us, login))
382     {
383     WriteServLog("Cannot write stat for user %s.", login.c_str());
384     WriteServLog("%s", store->GetStrError().c_str());
385     printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
386     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
387     return -1;
388     }
389
390 lastWriteStat = stgTime;
391
392 return 0;
393 }
394 //-----------------------------------------------------------------------------
395 int USER::WriteMonthStat()
396 {
397 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
398 USER_STAT us;
399 struct tm * t1;
400 time_t tt = stgTime - 3600;
401 t1 = localtime(&tt);
402
403 us.up = up;
404 us.down = down;
405 us.cash = cash;
406 us.freeMb = freeMb;
407 us.lastCashAdd = lastCashAdd;
408 us.lastCashAddTime = lastCashAddTime;
409 us.passiveTime = passiveTime;
410 us.lastActivityTime = lastActivityTime;
411
412 if (store->SaveMonthStat(us, t1->tm_mon, t1->tm_year, login))
413     {
414     WriteServLog("Cannot write month stat for user %s.", login.c_str());
415     WriteServLog("%s", store->GetStrError().c_str());
416     printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
417     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
418     return -1;
419     }
420
421 return 0;
422 }
423 //-----------------------------------------------------------------------------
424 int USER::Authorize(uint32_t ip, const string &, uint32_t dirs, const BASE_AUTH * auth)
425 {
426 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
427 /*
428  *  Authorize user. It only means that user will be authorized. Nothing more.
429  *  User can be connected or disconnected while authorized.
430  *  Example: user is authorized but disconnected due to 0 money or blocking
431  */
432
433 /*
434  * Prevent double authorization by identical authorizers
435  */
436 if (authorizedBy.find(auth) != authorizedBy.end())
437     return 0;
438
439 if (!ip)
440     return -1;
441
442 for (int i = 0; i < DIR_NUM; i++)
443     {
444     enabledDirs[i] = dirs & (1 << i);
445     }
446
447 if (authorizedBy.size())
448     {
449     if (currIP != ip)
450         {
451         //  We are already authorized, but with different IP address
452         errorStr = "User " + login + " alredy authorized with IP address " + inet_ntostring(ip);
453         return -1;
454         }
455
456     map<uint32_t, user_iter>::const_iterator ci = ipIndex->find(ip);
457     if (ci != ipIndex->end())
458         {
459         //  Address is already present in IP-index
460         //  If it's not our IP - throw an error
461         if (&(*ci->second) != this)
462             {
463             errorStr = "IP address " + inet_ntostring(ip) + " alredy in use";
464             return -1;
465             }
466         }
467     }
468 else
469     {
470     if (ipIndex->find(ip) != ipIndex->end())
471         {
472         //  Address is already present in IP-index
473         errorStr = "IP address " + inet_ntostring(ip) + " alredy in use";
474         return -1;
475         }
476
477     if (ips.ConstData().IsIPInIPS(ip))
478         {
479         currIP = ip;
480         lastIPForDisconnect = currIP;
481         }
482     else
483         {
484         printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
485         errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
486         return -1;
487         }
488     }
489
490 authorizedBy.insert(auth);
491
492 ScanMessage();
493
494 return 0;
495 }
496 //-----------------------------------------------------------------------------
497 void USER::Unauthorize(const BASE_AUTH * auth)
498 {
499 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
500 /*
501  *  Authorizer tries to unauthorize user, that was not authorized by it
502  */
503 if (!authorizedBy.erase(auth))
504     return;
505
506 if (authorizedBy.empty())
507     {
508     lastIPForDisconnect = currIP;
509     currIP = 0; // DelUser in traffcounter
510     return;
511     }
512 }
513 //-----------------------------------------------------------------------------
514 bool USER::IsAuthorizedBy(const BASE_AUTH * auth) const
515 {
516 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
517 //  Is this user authorized by specified authorizer?
518 return authorizedBy.find(auth) != authorizedBy.end();
519 }
520 //-----------------------------------------------------------------------------
521 void USER::Connect(bool fakeConnect)
522 {
523 /*
524  *  Connect user to Internet. This function is differ from Authorize() !!!
525  */
526
527 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
528
529 if (!fakeConnect)
530     {
531     string scriptOnConnect = settings->GetScriptDir() + "/OnConnect";
532
533     if (access(scriptOnConnect.c_str(), X_OK) == 0)
534         {
535         char dirsStr[DIR_NUM + 1];
536         dirsStr[DIR_NUM] = 0;
537         for (int i = 0; i < DIR_NUM; i++)
538             {
539             dirsStr[i] = enabledDirs[i] ? '1' : '0';
540             }
541
542         string scriptOnConnectParams;
543         strprintf(&scriptOnConnectParams,
544                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
545                 scriptOnConnect.c_str(),
546                 login.c_str(),
547                 inet_ntostring(currIP).c_str(),
548                 (double)cash,
549                 id,
550                 dirsStr);
551
552         ScriptExec(scriptOnConnectParams);
553         }
554     else
555         {
556         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
557         }
558
559     connected = true;
560     }
561
562 if (store->WriteUserConnect(login, currIP))
563     {
564     WriteServLog("Cannot write connect for user %s.", login.c_str());
565     WriteServLog("%s", store->GetStrError().c_str());
566     }
567
568 if (!fakeConnect)
569     lastIPForDisconnect = currIP;
570
571 //printfd(__FILE__, "Connect. user name \'%s\' ip=%s\n", login.c_str(), inet_ntostring(currIP).c_str());
572 /*if (settings->GetLogUserConnectDisconnect())
573     WriteServLog("User \'%s\', %s: Connect.", login.c_str(), inet_ntostring(currIP).c_str());*/
574 }
575 //-----------------------------------------------------------------------------
576 void USER::Disconnect(bool fakeDisconnect, const std::string & reason)
577 {
578 /*
579  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
580  */
581
582 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
583
584 if (!lastIPForDisconnect)
585     {
586     printfd(__FILE__, "lastIPForDisconnect\n");
587     return;
588     }
589
590 if (!fakeDisconnect)
591     {
592     string scriptOnDisonnect = settings->GetScriptDir() + "/OnDisconnect";
593
594     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
595         {
596         char dirsStr[DIR_NUM + 1];
597         dirsStr[DIR_NUM] = 0;
598         for (int i = 0; i < DIR_NUM; i++)
599             {
600             dirsStr[i] = enabledDirs[i] ? '1' : '0';
601             }
602
603         string scriptOnDisonnectParams;
604         strprintf(&scriptOnDisonnectParams,
605                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
606                 scriptOnDisonnect.c_str(),
607                 login.c_str(),
608                 inet_ntostring(lastIPForDisconnect).c_str(),
609                 (double)cash,
610                 id,
611                 dirsStr);
612
613         ScriptExec(scriptOnDisonnectParams);
614         }
615     else
616         {
617         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
618         }
619
620     connected = false;
621     }
622
623 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, cash, freeMb, reason))
624     {
625     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
626     WriteServLog("%s", store->GetStrError().c_str());
627     }
628
629 //printfd(__FILE__, "Disconnect. User name \'%s\' ip=%s reason: '%s'\n", login.c_str(), inet_ntostring(lastIPForDisconnect).c_str(), reason.c_str());
630 /*if (settings->GetLogUserConnectDisconnect())
631     WriteServLog("User \'%s\', %s: Disconnect.", login.c_str(), inet_ntostring(lastIPForDisconnect).c_str());*/
632
633 if (!fakeDisconnect)
634     lastIPForDisconnect = 0;
635
636 DIR_TRAFF zeroSesssion;
637
638 sessionUpload = zeroSesssion;
639 sessionDownload = zeroSesssion;
640 }
641 //-----------------------------------------------------------------------------
642 void USER::PrintUser() const
643 {
644 //return;
645 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
646 cout << "============================================================" << endl;
647 cout << "id=" << id << endl;
648 cout << "login=" << login << endl;
649 cout << "password=" << password << endl;
650 cout << "passive=" << passive << endl;
651 cout << "disabled=" << disabled << endl;
652 cout << "disabledDetailStat=" << disabledDetailStat << endl;
653 cout << "alwaysOnline=" << alwaysOnline << endl;
654 cout << "tariffName=" << tariffName << endl;
655 cout << "address=" << address << endl;
656 cout << "phone=" << phone << endl;
657 cout << "email=" << email << endl;
658 cout << "note=" << note << endl;
659 cout << "realName=" <<realName << endl;
660 cout << "group=" << group << endl;
661 cout << "credit=" << credit << endl;
662 cout << "nextTariff=" << nextTariff << endl;
663 cout << "userdata0" << userdata0 << endl;
664 cout << "userdata1" << userdata1 << endl;
665 cout << "creditExpire=" << creditExpire << endl;
666 cout << "ips=" << ips << endl;
667 cout << "------------------------" << endl;
668 cout << "up=" << up << endl;
669 cout << "down=" << down << endl;
670 cout << "cash=" << cash << endl;
671 cout << "freeMb=" << freeMb << endl;
672 cout << "lastCashAdd=" << lastCashAdd << endl;
673 cout << "lastCashAddTime=" << lastCashAddTime << endl;
674 cout << "passiveTime=" << passiveTime << endl;
675 cout << "lastActivityTime=" << lastActivityTime << endl;
676 cout << "============================================================" << endl;
677 }
678 //-----------------------------------------------------------------------------
679 void USER::Run()
680 {
681 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
682
683 if (stgTime - lastWriteStat > settings->GetStatWritePeriod())
684     {
685     printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
686     WriteStat();
687     }
688 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
689     {
690     WriteServLog("User: %s. Credit expired.", login.c_str());
691     credit = 0;
692     creditExpire = 0;
693     WriteConf();
694     }
695
696 if (passive.ConstData()
697     && (stgTime % 30 == 0)
698     && (passiveTime.ModificationTime() != stgTime))
699     {
700     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
701     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
702     }
703
704 if (!authorizedBy.empty())
705     {
706     if (connected)
707         {
708         lastActivityTime = *const_cast<time_t *>(&stgTime);
709         }
710     if (!connected && IsInetable())
711         {
712         Connect();
713         }
714     if (connected && !IsInetable())
715         {
716         if (disabled)
717             Disconnect(false, "disabled");
718         else if (passive)
719             Disconnect(false, "passive");
720         else
721             Disconnect(false, "no cash");
722         }
723
724     if (stgTime - lastScanMessages > 10)
725         {
726         ScanMessage();
727         lastScanMessages = stgTime;
728         }
729     }
730 else
731     {
732     if (connected)
733         {
734         Disconnect(false, "not authorized");
735         }
736     }
737
738 }
739 //-----------------------------------------------------------------------------
740 void USER::UpdatePingTime(time_t t)
741 {
742 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
743 //printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
744 if (t)
745     pingTime = t;
746 else
747     pingTime = stgTime;
748 }
749 //-----------------------------------------------------------------------------
750 bool USER::IsInetable()
751 {
752 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
753
754 if (disabled || passive)
755     return false;
756
757 if (settings->GetFreeMbAllowInet())
758     {
759     if (freeMb >= 0)
760         return true;
761     }
762
763 if (settings->GetShowFeeInCash())
764     {
765     return (cash >= -credit);
766     }
767
768 return (cash - tariff->GetFee() >= -credit);
769 }
770 //-----------------------------------------------------------------------------
771 string USER::GetEnabledDirs()
772 {
773 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
774
775 string dirs = "";
776 for(int i = 0; i < DIR_NUM; i++)
777     dirs += enabledDirs[i] ? "1" : "0";
778 return dirs;
779 }
780 //-----------------------------------------------------------------------------
781 #ifdef TRAFF_STAT_WITH_PORTS
782 void USER::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
783 #else
784 void USER::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
785 #endif
786 {
787 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
788
789 if (!connected)
790     return;
791
792 double cost = 0;
793 DIR_TRAFF dt(up);
794
795 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
796 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
797
798 dt[dir] += len;
799
800 int tt = tariff->GetTraffType();
801 if (tt == TRAFF_UP ||
802     tt == TRAFF_UP_DOWN ||
803     // Check NEW traff data
804     (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
805     {
806     double dc = 0;
807     if (traff < threshold &&
808         traff + len >= threshold)
809         {
810         // cash = partBeforeThreshold * priceBeforeThreshold +
811         //        partAfterThreshold * priceAfterThreshold
812         int64_t before = threshold - traff; // Chunk part before threshold
813         int64_t after = len - before; // Chunk part after threshold
814         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
815                                            down.ConstData()[dir],
816                                            dir,
817                                            stgTime) * before +
818              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
819                                            down.ConstData()[dir],
820                                            dir,
821                                            stgTime) * after;
822         }
823     else
824         {
825         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
826                                            down.ConstData()[dir],
827                                            dir,
828                                            stgTime) * len;
829         }
830
831     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
832         cost = dc;
833     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
834         cost = dc - freeMb.ConstData();
835
836     // Direct access to internal data structures via friend-specifier
837     property.stat.freeMb -= dc;
838     property.stat.cash -= cost;
839     cash.ModifyTime();
840     freeMb.ModifyTime();
841     }
842
843 up = dt;
844 sessionUpload[dir] += len;
845
846 //Add detailed stat
847
848 if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
849     cost = 0;
850
851 #ifdef TRAFF_STAT_WITH_PORTS
852 IP_DIR_PAIR idp(ip, dir, port);
853 #else
854 IP_DIR_PAIR idp(ip, dir);
855 #endif
856
857 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
858 lb = traffStat->lower_bound(idp);
859 if (lb == traffStat->end())
860     {
861     traffStat->insert(lb,
862                       pair<IP_DIR_PAIR, STAT_NODE>(idp,
863                                                    STAT_NODE(len, 0, cost)));
864     }
865 else
866     if (lb->first.dir == dir && lb->first.ip == ip)
867         {
868         lb->second.cash += cost;
869         lb->second.up += len;
870         }
871     else
872         {
873         traffStat->insert(lb,
874                           pair<IP_DIR_PAIR, STAT_NODE>(idp,
875                                                        STAT_NODE(len, 0, cost)));
876         }
877 }
878 //-----------------------------------------------------------------------------
879 #ifdef TRAFF_STAT_WITH_PORTS
880 void USER::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
881 #else
882 void USER::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
883 #endif
884 {
885 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
886
887 if (!connected)
888     return;
889
890 double cost = 0;
891 DIR_TRAFF dt(down);
892
893 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
894 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
895
896 dt[dir] += len;
897
898 int tt = tariff->GetTraffType();
899 if (tt == TRAFF_DOWN ||
900     tt == TRAFF_UP_DOWN ||
901     // Check NEW traff data
902     (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
903     {
904     double dc = 0;
905     if (traff < threshold &&
906         traff + len >= threshold)
907         {
908         // cash = partBeforeThreshold * priceBeforeThreshold +
909         //        partAfterThreshold * priceAfterThreshold
910         int64_t before = threshold - traff; // Chunk part before threshold
911         int64_t after = len - before; // Chunk part after threshold
912         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
913                                            down.ConstData()[dir], // Traff before chunk
914                                            dir,
915                                            stgTime) * before +
916              tariff->GetPriceWithTraffType(up.ConstData()[dir],
917                                            dt[dir], // Traff after chunk
918                                            dir,
919                                            stgTime) * after;
920         }
921     else
922         {
923         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
924                                            down.ConstData()[dir],
925                                            dir,
926                                            stgTime) * len;
927         }
928
929     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
930         cost = dc;
931     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
932         cost = dc - freeMb.ConstData();
933
934     property.stat.freeMb -= dc;
935     property.stat.cash -= cost;
936     cash.ModifyTime();
937     freeMb.ModifyTime();
938     }
939
940 down = dt;
941 sessionDownload[dir] += len;
942
943 //Add detailed stat
944
945 if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
946     cost = 0;
947
948 #ifdef TRAFF_STAT_WITH_PORTS
949 IP_DIR_PAIR idp(ip, dir, port);
950 #else
951 IP_DIR_PAIR idp(ip, dir);
952 #endif
953
954 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
955 lb = traffStat->lower_bound(idp);
956 if (lb == traffStat->end())
957     {
958     traffStat->insert(lb,
959                       pair<IP_DIR_PAIR, STAT_NODE>(idp,
960                                                    STAT_NODE(0, len, cost)));
961     }
962 else
963     if (lb->first.dir == dir && lb->first.ip == ip)
964         {
965         lb->second.cash += cost;
966         lb->second.down += len;
967         }
968     else
969         {
970         traffStat->insert(lb,
971                           pair<IP_DIR_PAIR, STAT_NODE>(idp,
972                                                        STAT_NODE(0, len, cost)));
973         }
974 }
975 //-----------------------------------------------------------------------------
976 void USER::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
977 {
978 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
979 currIP.AddBeforeNotifier(n);
980 }
981 //-----------------------------------------------------------------------------
982 void USER::DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
983 {
984 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
985 currIP.DelBeforeNotifier(n);
986 }
987 //-----------------------------------------------------------------------------
988 void USER::AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
989 {
990 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
991 currIP.AddAfterNotifier(n);
992 }
993 //-----------------------------------------------------------------------------
994 void USER::DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
995 {
996 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
997 currIP.DelAfterNotifier(n);
998 }
999 //-----------------------------------------------------------------------------
1000 void USER::OnAdd()
1001 {
1002 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1003
1004 string scriptOnAdd = settings->GetScriptDir() + "/OnUserAdd";
1005
1006 if (access(scriptOnAdd.c_str(), X_OK) == 0)
1007     {
1008     string scriptOnAddParams;
1009     strprintf(&scriptOnAddParams,
1010             "%s \"%s\"",
1011             scriptOnAdd.c_str(),
1012             login.c_str());
1013
1014     ScriptExec(scriptOnAddParams);
1015     }
1016 else
1017     {
1018     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
1019     }
1020 }
1021 //-----------------------------------------------------------------------------
1022 void USER::OnDelete()
1023 {
1024 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1025
1026 string scriptOnDel = settings->GetScriptDir() + "/OnUserDel";
1027
1028 if (access(scriptOnDel.c_str(), X_OK) == 0)
1029     {
1030     string scriptOnDelParams;
1031     strprintf(&scriptOnDelParams,
1032             "%s \"%s\"",
1033             scriptOnDel.c_str(),
1034             login.c_str());
1035
1036     ScriptExec(scriptOnDelParams);
1037     }
1038 else
1039     {
1040     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
1041     }
1042
1043 Run();
1044 }
1045 //-----------------------------------------------------------------------------
1046 void USER::ResetDetailStat()
1047 {
1048 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1049
1050 traffStatToWrite->erase(traffStatToWrite->begin(), traffStatToWrite->end());
1051 }
1052 //-----------------------------------------------------------------------------
1053 int USER::WriteDetailStat()
1054 {
1055 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1056
1057 printfd(__FILE__, "USER::WriteDetailedStat(): size = %d\n", traffStatToWrite->size());
1058
1059 if (traffStatToWrite->size() && !disabledDetailStat)
1060     {
1061     if (store->WriteDetailedStat(traffStatToWrite, lastWriteDeatiledStat, login))
1062         {
1063         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
1064         WriteServLog("%s", store->GetStrError().c_str());
1065         }
1066     }
1067 lastWriteDeatiledStat = lastSwapDeatiledStat;
1068 return 0;
1069 }
1070 //-----------------------------------------------------------------------------
1071 int USER::SwapDetailStat()
1072 {
1073 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1074
1075 lastSwapDeatiledStat = stgTime;
1076 traffStatToWrite = &traffStatInternal[traffStatInUse % 2];
1077 traffStat = &traffStatInternal[++traffStatInUse % 2];
1078
1079 return 0;
1080 }
1081 //-----------------------------------------------------------------------------
1082 double USER::GetPassiveTimePart() const
1083 {
1084 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1085
1086 static int daysInMonth[12] =
1087 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1088
1089 struct tm * tms;
1090 time_t t = stgTime;
1091 tms = localtime(&t);
1092
1093 time_t secMonth = daysInMonth[(tms->tm_mon + 11) % 12] * 24 * 3600; // Previous month
1094
1095 if (tms->tm_year % 4 == 0 && tms->tm_mon == 1)
1096     {
1097     // Leap year
1098     secMonth += 24 * 3600;
1099     }
1100
1101 int dt = secMonth - passiveTime;
1102
1103 if (dt < 0)
1104     dt = 0;
1105
1106 return double(dt) / (secMonth);
1107 }
1108 //-----------------------------------------------------------------------------
1109 void USER::SetPassiveTimeAsNewUser()
1110 {
1111 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1112
1113 time_t t;
1114 struct tm * tm;
1115 t = stgTime;
1116 tm = localtime(&t);
1117 int daysCurrMon = DaysInCurrentMonth();
1118 double pt = (tm->tm_mday - 1) / (double)daysCurrMon;
1119
1120 passiveTime = (time_t)(pt * 24 * 3600 * daysCurrMon);
1121 }
1122 //-----------------------------------------------------------------------------
1123 void USER::MidnightResetSessionStat()
1124 {
1125 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1126
1127 if (connected)
1128     {
1129     Disconnect(true, "fake");
1130     Connect(true);
1131     }
1132 }
1133 //-----------------------------------------------------------------------------
1134 void USER::ProcessNewMonth()
1135 {
1136 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1137 //  Reset traff
1138 if (connected)
1139     {
1140     Disconnect(true, "fake");
1141     }
1142 DIR_TRAFF zeroTarff;
1143
1144 WriteMonthStat();
1145
1146 up = zeroTarff;
1147 down = zeroTarff;
1148
1149 if (connected)
1150     {
1151     Connect(true);
1152     }
1153
1154 //  Set new tariff
1155 if (nextTariff.ConstData() != "")
1156     {
1157     const TARIFF * nt;
1158     nt = tariffs->FindByName(nextTariff);
1159     if (nt == NULL)
1160         {
1161         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1162                      login.c_str(), property.tariffName.Get().c_str());
1163         }
1164     else
1165         {
1166         property.tariffName.Set(nextTariff, sysAdmin, login, store);
1167         tariff = nt;
1168         }
1169     ResetNextTariff();
1170     WriteConf();
1171     }
1172 }
1173 //-----------------------------------------------------------------------------
1174 void USER::ProcessDayFeeSpread()
1175 {
1176 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1177
1178 if (passive.ConstData())
1179     return;
1180
1181 double f = tariff->GetFee() / DaysInCurrentMonth();
1182
1183 if (f == 0.0)
1184     return;
1185
1186 double c = cash;
1187 property.cash.Set(c - f, sysAdmin, login, store, "Subscriber fee charge");
1188 ResetPassiveTime();
1189 }
1190 //-----------------------------------------------------------------------------
1191 void USER::ProcessDayFee()
1192 {
1193 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1194
1195 double passiveTimePart = 1.0;
1196 if (!settings->GetFullFee())
1197     {
1198     passiveTimePart = GetPassiveTimePart();
1199     }
1200 else
1201     {
1202     if (passive.ConstData())
1203         {
1204         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1205         return;
1206         }
1207     }
1208 double f = tariff->GetFee() * passiveTimePart;
1209
1210 ResetPassiveTime();
1211
1212 if (f == 0.0)
1213     return;
1214
1215 double c = cash;
1216 printfd(__FILE__, "login: %8s   Fee=%f PassiveTimePart=%f fee=%f\n",
1217         login.c_str(),
1218         tariff->GetFee(),
1219         passiveTimePart,
1220         f);
1221 property.cash.Set(c - f, sysAdmin, login, store, "Subscriber fee charge");
1222 }
1223 //-----------------------------------------------------------------------------
1224 void USER::SetPrepaidTraff()
1225 {
1226 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1227
1228 property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1229 }
1230 //-----------------------------------------------------------------------------
1231 int USER::AddMessage(STG_MSG * msg)
1232 {
1233 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1234
1235 if (SendMessage(*msg) == 0)
1236     {
1237     if (msg->header.repeat > 0)
1238         {
1239         msg->header.repeat--;
1240         #ifndef DEBUG
1241         //TODO: gcc v. 4.x generate ICE on x86_64
1242         msg->header.lastSendTime = time(NULL);
1243         #else
1244         msg->header.lastSendTime = stgTime;
1245         #endif
1246         if (store->AddMessage(msg, login))
1247             {
1248             errorStr = store->GetStrError();
1249             STG_LOGGER & WriteServLog = GetStgLogger();
1250             WriteServLog("Error adding message %s", errorStr.c_str());
1251             WriteServLog("%s", store->GetStrError().c_str());
1252             return -1;
1253             }
1254         }
1255     }
1256 else
1257     {
1258     if (store->AddMessage(msg, login))
1259         {
1260         errorStr = store->GetStrError();
1261         STG_LOGGER & WriteServLog = GetStgLogger();
1262         WriteServLog("Error adding message %s", errorStr.c_str());
1263         WriteServLog("%s", store->GetStrError().c_str());
1264         return -1;
1265         }
1266     }
1267 return 0;
1268 }
1269 //-----------------------------------------------------------------------------
1270 int USER::SendMessage(const STG_MSG & msg)
1271 {
1272 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1273
1274 if (authorizedBy.empty())
1275     {
1276     return -1;
1277     }
1278
1279 int ret = -1;
1280 set<const BASE_AUTH*>::iterator it;
1281
1282 it = authorizedBy.begin();
1283 while (it != authorizedBy.end())
1284     {
1285     if ((*it)->SendMessage(msg, currIP) == 0)
1286         ret = 0;
1287     ++it;
1288     }
1289 return ret;
1290 }
1291 //-----------------------------------------------------------------------------
1292 int USER::ScanMessage()
1293 {
1294 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1295
1296 vector<STG_MSG_HDR> hdrsList;
1297
1298 if (store->GetMessageHdrs(&hdrsList, login))
1299     {
1300     printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
1301     return -1;
1302     }
1303
1304 for (unsigned i = 0; i < hdrsList.size(); i++)
1305     {
1306
1307     if (hdrsList[i].lastSendTime + hdrsList[i].repeatPeriod * 60 < (unsigned)stgTime)
1308         {
1309         STG_MSG msg;
1310         if (store->GetMessage(hdrsList[i].id, &msg, login) == 0)
1311             {
1312             if (SendMessage(msg) == 0)
1313                 {
1314                 msg.header.repeat--;
1315                 if (msg.header.repeat < 0)
1316                     {
1317                     printfd(__FILE__, "DelMessage\n");
1318                     store->DelMessage(hdrsList[i].id, login);
1319                     }
1320                 else
1321                     {
1322                     #ifndef DEBUG
1323                     //TODO: gcc v. 4.x generate ICE on x86_64
1324                     msg.header.lastSendTime = time(NULL);
1325                     #else
1326                     msg.header.lastSendTime = stgTime;
1327                     #endif
1328                     if (store->EditMessage(msg, login))
1329                         {
1330                         printfd(__FILE__, "EditMessage Error %s\n", store->GetStrError().c_str());
1331                         }
1332                     }
1333                 }
1334             }
1335         else
1336             {
1337             WriteServLog("Cannot get message for user %s.", login.c_str());
1338             WriteServLog("%s", store->GetStrError().c_str());
1339             }
1340         }
1341     }
1342 return 0;
1343 }
1344 //-----------------------------------------------------------------------------
1345 //-----------------------------------------------------------------------------
1346 //-----------------------------------------------------------------------------
1347 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1348 {
1349 if (newPassive && !oldPassive)
1350     user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1351                             user->sysAdmin,
1352                             user->login,
1353                             user->store,
1354                             "Freeze");
1355 }
1356 //-----------------------------------------------------------------------------
1357 void CHG_TARIFF_NOTIFIER::Notify(const string &, const string & newTariff)
1358 {
1359 user->tariff = user->tariffs->FindByName(newTariff);
1360 }
1361 //-----------------------------------------------------------------------------
1362 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1363 {
1364 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1365 user->lastCashAdd = newCash - oldCash;
1366 }
1367 //-----------------------------------------------------------------------------
1368 void CHG_IP_NOTIFIER::Notify(const uint32_t & from, const uint32_t & to)
1369 {
1370     printfd(__FILE__, "Change IP from %s to %s\n", inet_ntostring(from).c_str(), inet_ntostring(to).c_str());
1371     if (from != 0)
1372         user->Disconnect(false, "Change IP");
1373     if (to != 0)
1374         user->Connect(false);
1375 }
1376 //-----------------------------------------------------------------------------