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