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