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