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