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