]> git.stg.codes - stg.git/blob - projects/stargazer/users_impl.cpp
Produce debug output only if SMUX_DEBUG is defined
[stg.git] / projects / stargazer / users_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.61 $
27  $Date: 2010/09/13 05:56:42 $
28  $Author: faust $
29  */
30
31 #ifndef _GNU_SOURCE
32 #define _GNU_SOURCE
33 #endif
34
35 #include <pthread.h>
36 #include <csignal>
37 #include <cassert>
38 #include <algorithm>
39 #include <utility>
40 #include <string>
41 #include <vector>
42
43 #include "stg/settings.h"
44 #include "stg/common.h"
45 #include "users_impl.h"
46 #include "stg_timer.h"
47
48 using namespace std;
49
50 extern const volatile time_t stgTime;
51
52 //#define USERS_DEBUG 1
53
54 //-----------------------------------------------------------------------------
55 USERS_IMPL::USERS_IMPL(SETTINGS_IMPL * s, STORE * st, TARIFFS * t, const ADMIN * sa)
56     : USERS(),
57       users(),
58       usersToDelete(),
59       userIPNotifiersBefore(),
60       userIPNotifiersAfter(),
61       ipIndex(),
62       loginIndex(),
63       settings(s),
64       tariffs(t),
65       store(st),
66       sysAdmin(sa),
67       WriteServLog(GetStgLogger()),
68       nonstop(false),
69       isRunning(false),
70       mutex(),
71       thread(),
72       handle(0),
73       searchDescriptors(),
74       onAddNotifiers(),
75       onDelNotifiers(),
76       onAddNotifiersImpl(),
77       onDelNotifiersImpl()
78 {
79 pthread_mutexattr_t attr;
80 pthread_mutexattr_init(&attr);
81 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
82 pthread_mutex_init(&mutex, &attr);
83 }
84 //-----------------------------------------------------------------------------
85 USERS_IMPL::~USERS_IMPL()
86 {
87 pthread_mutex_destroy(&mutex);
88 }
89 //-----------------------------------------------------------------------------
90 int USERS_IMPL::FindByNameNonLock(const string & login, user_iter * user)
91 {
92 map<string, user_iter>::iterator iter;
93 iter = loginIndex.find(login);
94 if (iter != loginIndex.end())
95     {
96     if (user)
97         *user = iter->second;
98     return 0;
99     }
100 return -1;
101 }
102 //-----------------------------------------------------------------------------
103 int USERS_IMPL::FindByName(const string & login, USER_PTR * user)
104 {
105 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
106 user_iter u;
107 int res = FindByNameNonLock(login, &u);
108 if (res)
109     return -1;
110 *user = &(*u);
111 return 0;
112 }
113 //-----------------------------------------------------------------------------
114 bool USERS_IMPL::TariffInUse(const string & tariffName) const
115 {
116 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
117 list<USER_IMPL>::const_iterator iter;
118 iter = users.begin();
119 while (iter != users.end())
120     {
121     if (iter->GetProperty().tariffName.Get() == tariffName)
122         return true;
123     ++iter;
124     }
125 return false;
126 }
127 //-----------------------------------------------------------------------------
128 int USERS_IMPL::Add(const string & login, const ADMIN * admin)
129 {
130 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
131 const PRIV * priv = admin->GetPriv();
132
133 if (!priv->userAddDel)
134     {
135     WriteServLog("%s tried to add user \'%s\'. Access denied.",
136          admin->GetLogStr().c_str(), login.c_str());
137     /*errorStr = "Admin \'" + admin->GetLogin() +
138                "\': tried to add user \'" + ud->login + "\'. Access denied.";*/
139     return -1;
140     }
141
142 //////
143 if (store->AddUser(login))
144     {
145     //TODO
146     //WriteServLog("Admin \'%s\': tried to add user \'%s\'. Access denied.",
147     //     admin->GetLogin().c_str(), ud->login.c_str());
148     return -1;
149     }
150 //////
151
152 USER_IMPL u(settings, store, tariffs, sysAdmin, this);
153
154 /*struct tm * tms;
155 time_t t = stgTime;
156
157 tms = localtime(&t);
158
159 tms->tm_hour = 0;
160 tms->tm_min = 0;
161 tms->tm_sec = 0;
162
163 if (settings->GetDayResetTraff() > tms->tm_mday)
164     tms->tm_mon -= 1;
165
166 tms->tm_mday = settings->GetDayResetTraff();*/
167
168 u.SetLogin(login);
169
170 u.SetPassiveTimeAsNewUser();
171
172 u.WriteConf();
173 u.WriteStat();
174
175 WriteServLog("%s User \'%s\' added.",
176          admin->GetLogStr().c_str(), login.c_str());
177
178 u.OnAdd();
179
180 users.push_front(u);
181
182 AddUserIntoIndexes(users.begin());
183 SetUserNotifiers(users.begin());
184
185     {
186     // Fire all "on add" notifiers
187     set<NOTIFIER_BASE<USER_PTR> *>::iterator ni = onAddNotifiers.begin();
188     while (ni != onAddNotifiers.end())
189         {
190         (*ni)->Notify(&users.front());
191         ++ni;
192         }
193     }
194
195     {
196     // Fire all "on add" implementation notifiers
197     set<NOTIFIER_BASE<USER_IMPL_PTR> *>::iterator ni = onAddNotifiersImpl.begin();
198     while (ni != onAddNotifiersImpl.end())
199         {
200         (*ni)->Notify(&users.front());
201         ++ni;
202         }
203     }
204
205 return 0;
206 }
207 //-----------------------------------------------------------------------------
208 void USERS_IMPL::Del(const string & login, const ADMIN * admin)
209 {
210 const PRIV * priv = admin->GetPriv();
211 user_iter u;
212
213 if (!priv->userAddDel)
214     {
215     WriteServLog("%s tried to remove user \'%s\'. Access denied.",
216          admin->GetLogStr().c_str(), login.c_str());
217     return;
218     }
219
220
221     {
222     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
223
224     if (FindByNameNonLock(login, &u))
225         {
226         WriteServLog("%s tried to delete user \'%s\': not found.",
227                      admin->GetLogStr().c_str(),
228                      login.c_str());
229         return;
230         }
231
232     u->SetDeleted();
233     }
234
235     {
236     set<NOTIFIER_BASE<USER_PTR> *>::iterator ni = onDelNotifiers.begin();
237     while (ni != onDelNotifiers.end())
238         {
239         (*ni)->Notify(&(*u));
240         ++ni;
241         }
242     }
243
244     {
245     set<NOTIFIER_BASE<USER_IMPL_PTR> *>::iterator ni = onDelNotifiersImpl.begin();
246     while (ni != onDelNotifiersImpl.end())
247         {
248         (*ni)->Notify(&(*u));
249         ++ni;
250         }
251     }
252
253     {
254     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
255
256     u->OnDelete();
257
258     USER_TO_DEL utd;
259     utd.iter = u;
260     utd.delTime = stgTime;
261     usersToDelete.push_back(utd);
262
263     UnSetUserNotifiers(u);
264     DelUserFromIndexes(u);
265
266     WriteServLog("%s User \'%s\' deleted.",
267              admin->GetLogStr().c_str(), login.c_str());
268
269     }
270 }
271 //-----------------------------------------------------------------------------
272 int USERS_IMPL::ReadUsers()
273 {
274 vector<string> usersList;
275 usersList.clear();
276 if (store->GetUsersList(&usersList) < 0)
277     {
278     WriteServLog(store->GetStrError().c_str());
279     return -1;
280     }
281
282 user_iter ui;
283
284 for (unsigned int i = 0; i < usersList.size(); i++)
285     {
286     USER_IMPL u(settings, store, tariffs, sysAdmin, this);
287
288     u.SetLogin(usersList[i]);
289     users.push_front(u);
290     ui = users.begin();
291
292     AddUserIntoIndexes(ui);
293     SetUserNotifiers(ui);
294
295     if (ui->ReadConf() < 0)
296         return -1;
297
298     if (ui->ReadStat() < 0)
299         return -1;
300     }
301
302 return 0;
303 }
304 //-----------------------------------------------------------------------------
305 void * USERS_IMPL::Run(void * d)
306 {
307 printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
308 USERS_IMPL * us = (USERS_IMPL*) d;
309
310 struct tm t;
311 time_t tt = stgTime;
312 localtime_r(&tt, &t);
313
314 int min = t.tm_min;
315 int day = t.tm_mday;
316
317 printfd(__FILE__,"Day = %d Min = %d\n", day, min);
318
319 time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
320 string monFile = us->settings->GetMonitorDir() + "/users_r";
321 printfd(__FILE__, "Monitor=%d file USERS %s\n", us->settings->GetMonitoring(), monFile.c_str());
322
323 us->isRunning = true;
324 while (us->nonstop)
325     {
326     //printfd(__FILE__,"New Minute. old = %02d current = %02d\n", min, t->tm_min);
327     //printfd(__FILE__,"New Day.    old = %2d current = %2d\n", day, t->tm_mday);
328
329     for_each(us->users.begin(), us->users.end(), mem_fun_ref(&USER_IMPL::Run));
330
331     tt = stgTime;
332     localtime_r(&tt, &t);
333
334     if (min != t.tm_min)
335         {
336         printfd(__FILE__,"Sec = %d\n", stgTime);
337         printfd(__FILE__,"New Minute. old = %d current = %d\n", min, t.tm_min);
338         min = t.tm_min;
339
340         us->NewMinute(t);
341         }
342
343     if (day != t.tm_mday)
344         {
345         printfd(__FILE__,"Sec = %d\n", stgTime);
346         printfd(__FILE__,"New Day. old = %d current = %d\n", day, t.tm_mday);
347         day = t.tm_mday;
348         us->NewDay(t);
349         }
350
351     if (us->settings->GetMonitoring() && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
352         {
353         //printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", tc->monitoring, monFile.c_str());
354         touchTime = stgTime;
355         TouchFile(monFile.c_str());
356         }
357
358     stgUsleep(100000);
359     } //while (us->nonstop)
360
361 user_iter ui = us->users.begin();
362 while (ui != us->users.end())
363     {
364     us->UnSetUserNotifiers(ui);
365     us->DelUserFromIndexes(ui);
366     ++ui;
367     }
368
369 list<USER_TO_DEL>::iterator iter;
370 iter = us->usersToDelete.begin();
371 while (iter != us->usersToDelete.end())
372     {
373     iter->delTime -= 2 * userDeleteDelayTime;
374     ++iter;
375     }
376 us->RealDelUser();
377
378 us->isRunning = false;
379
380 return NULL;
381 }
382 //-----------------------------------------------------------------------------
383 void USERS_IMPL::NewMinute(const struct tm & t)
384 {
385 //Write traff, reset session traff. Fake disconnect-connect
386 if (t.tm_hour == 23 && t.tm_min == 59)
387     {
388     printfd(__FILE__,"MidnightResetSessionStat\n");
389     for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::MidnightResetSessionStat));
390     }
391
392 if (TimeToWriteDetailStat(t))
393     {
394     //printfd(__FILE__, "USER::WriteInetStat\n");
395     int usersCnt = 0;
396
397     // ðÉÛÅÍ ÀÚÅÒÏ× ÞÁÓÔÑÍÉ. ÷ ÐÅÒÅÒÙ×ÁÈ ×ÙÚÙ×ÁÅÍ USER::Run
398     list<USER_IMPL>::iterator usr = users.begin();
399     while (usr != users.end())
400         {
401         usersCnt++;
402         usr->WriteDetailStat();
403         ++usr;
404         if (usersCnt % 10 == 0)
405             for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::Run));
406         }
407     }
408
409 RealDelUser();
410 }
411 //-----------------------------------------------------------------------------
412 void USERS_IMPL::NewDay(const struct tm & t)
413 {
414 struct tm t1;
415 time_t tt = stgTime;
416 localtime_r(&tt, &t1);
417 int dayFee = settings->GetDayFee();
418
419 if (dayFee == 0)
420     dayFee = DaysInCurrentMonth();
421
422 printfd(__FILE__, "DayFee = %d\n", dayFee);
423 printfd(__FILE__, "Today = %d DayResetTraff = %d\n", t1.tm_mday, settings->GetDayResetTraff());
424 printfd(__FILE__, "DayFeeIsLastDay = %d\n", settings->GetDayFeeIsLastDay());
425
426 if (!settings->GetDayFeeIsLastDay())
427     {
428     printfd(__FILE__, "DayResetTraff - 1 -\n");
429     DayResetTraff(t1);
430     //printfd(__FILE__, "DayResetTraff - 1 - 1 -\n");
431     }
432
433 if (settings->GetSpreadFee())
434     {
435     printfd(__FILE__, "Spread DayFee\n");
436     for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::ProcessDayFeeSpread));
437     }
438 else
439     {
440     if (t.tm_mday == dayFee)
441         {
442         printfd(__FILE__, "DayFee\n");
443         for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::ProcessDayFee));
444         }
445     }
446
447 if (settings->GetDayFeeIsLastDay())
448     {
449     printfd(__FILE__, "DayResetTraff - 2 -\n");
450     DayResetTraff(t1);
451     }
452 }
453 //-----------------------------------------------------------------------------
454 void USERS_IMPL::DayResetTraff(const struct tm & t1)
455 {
456 int dayResetTraff = settings->GetDayResetTraff();
457 if (dayResetTraff == 0)
458     dayResetTraff = DaysInCurrentMonth();
459 if (t1.tm_mday == dayResetTraff)
460     {
461     printfd(__FILE__, "ResetTraff\n");
462     for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::ProcessNewMonth));
463     //for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::SetPrepaidTraff));
464     }
465 }
466 //-----------------------------------------------------------------------------
467 int USERS_IMPL::Start()
468 {
469 if (ReadUsers())
470     {
471     WriteServLog("USERS: Error: Cannot read users!");
472     return -1;
473     }
474
475 nonstop = true;
476 if (pthread_create(&thread, NULL, Run, this))
477     {
478     WriteServLog("USERS: Error: Cannot start thread!");
479     return -1;
480     }
481 return 0;
482 }
483 //-----------------------------------------------------------------------------
484 int USERS_IMPL::Stop()
485 {
486 printfd(__FILE__, "USERS::Stop()\n");
487
488 if (!isRunning)
489     {
490     //printfd(__FILE__, "Alredy stopped\n");
491     return 0;
492     }
493
494 nonstop = false;
495
496 //5 seconds to thread stops itself
497 struct timespec ts = {0, 200000000};
498 for (size_t i = 0; i < 25 * (users.size() / 50 + 1); i++)
499     {
500     if (!isRunning)
501         break;
502
503     nanosleep(&ts, NULL);
504     }
505
506 //after 5 seconds waiting thread still running. now kill it
507 if (isRunning)
508     {
509     printfd(__FILE__, "kill USERS thread.\n");
510     //TODO pthread_cancel()
511     if (pthread_kill(thread, SIGINT))
512         {
513         //errorStr = "Cannot kill USERS thread.";
514         //printfd(__FILE__, "Cannot kill USERS thread.\n");
515         //return 0;
516         }
517     printfd(__FILE__, "USERS killed\n");
518     }
519
520 printfd(__FILE__, "Before USERS::Run()\n");
521 for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::Run));
522
523 // 'cause bind2st accepts only constant first param
524 for (list<USER_IMPL>::iterator it = users.begin();
525      it != users.end();
526      ++it)
527     it->WriteDetailStat(true);
528
529 for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::WriteStat));
530 //for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::WriteConf));
531
532 printfd(__FILE__, "USERS::Stop()\n");
533 return 0;
534 }
535 //-----------------------------------------------------------------------------
536 void USERS_IMPL::RealDelUser()
537 {
538 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
539
540 printfd(__FILE__, "RealDelUser() users to del: %d\n", usersToDelete.size());
541
542 list<USER_TO_DEL>::iterator iter;
543 iter = usersToDelete.begin();
544 while (iter != usersToDelete.end())
545     {
546     printfd(__FILE__, "RealDelUser() user=%s\n", iter->iter->GetLogin().c_str());
547     if (iter->delTime + userDeleteDelayTime < stgTime)
548         {
549         printfd(__FILE__, "RealDelUser() user=%s removed from DB\n", iter->iter->GetLogin().c_str());
550         if (store->DelUser(iter->iter->GetLogin()))
551             {
552             WriteServLog("Error removing user \'%s\' from database.", iter->iter->GetLogin().c_str());
553             }
554         users.erase(iter->iter);
555         usersToDelete.erase(iter++);
556         }
557     else
558         {
559         ++iter;
560         }
561     }
562 return;
563 }
564 //-----------------------------------------------------------------------------
565 void USERS_IMPL::AddToIPIdx(user_iter user)
566 {
567 printfd(__FILE__, "USERS: Add IP Idx\n");
568 uint32_t ip = user->GetCurrIP();
569 //assert(ip && "User has non-null ip");
570 if (!ip)
571     return; // User has disconnected
572
573 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
574
575 const map<uint32_t, user_iter>::iterator it(
576         ipIndex.lower_bound(ip)
577 );
578
579 assert((it == ipIndex.end() || it->first != ip) && "User is not in index");
580
581 ipIndex.insert(it, std::make_pair(ip, user));
582 }
583 //-----------------------------------------------------------------------------
584 void USERS_IMPL::DelFromIPIdx(uint32_t ip)
585 {
586 printfd(__FILE__, "USERS: Del IP Idx\n");
587 assert(ip && "User has non-null ip");
588
589 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
590
591 const map<uint32_t, user_iter>::iterator it(
592         ipIndex.find(ip)
593 );
594
595 //assert(it != ipIndex.end() && "User is in index");
596 if (it == ipIndex.end())
597     return; // User has not been added
598
599 ipIndex.erase(it);
600 }
601 //-----------------------------------------------------------------------------
602 int USERS_IMPL::FindByIPIdx(uint32_t ip, USER_PTR * usr) const
603 {
604     USER_IMPL * ptr = NULL;
605     if (FindByIPIdx(ip, &ptr))
606         return -1;
607     *usr = ptr;
608     return 0;
609 }
610 //-----------------------------------------------------------------------------
611 int USERS_IMPL::FindByIPIdx(uint32_t ip, USER_IMPL ** usr) const
612 {
613 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
614
615 map<uint32_t, user_iter>::const_iterator it;
616 it = ipIndex.find(ip);
617
618 if (it == ipIndex.end())
619     {
620     //printfd(__FILE__, "User NOT found in IP_Index!!!\n");
621     return -1;
622     }
623 *usr = &(*it->second);
624 //printfd(__FILE__, "User found in IP_Index\n");
625 return 0;
626 }
627 //-----------------------------------------------------------------------------
628 bool USERS_IMPL::IsIPInIndex(uint32_t ip) const
629 {
630 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
631
632 map<uint32_t, user_iter>::const_iterator it;
633 it = ipIndex.find(ip);
634
635 return it != ipIndex.end();
636 }
637 //-----------------------------------------------------------------------------
638 void USERS_IMPL::AddNotifierUserAdd(NOTIFIER_BASE<USER_PTR> * n)
639 {
640 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
641 onAddNotifiers.insert(n);
642 }
643 //-----------------------------------------------------------------------------
644 void USERS_IMPL::DelNotifierUserAdd(NOTIFIER_BASE<USER_PTR> * n)
645 {
646 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
647 onAddNotifiers.erase(n);
648 }
649 //-----------------------------------------------------------------------------
650 void USERS_IMPL::AddNotifierUserDel(NOTIFIER_BASE<USER_PTR> * n)
651 {
652 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
653 onDelNotifiers.insert(n);
654 }
655 //-----------------------------------------------------------------------------
656 void USERS_IMPL::DelNotifierUserDel(NOTIFIER_BASE<USER_PTR> * n)
657 {
658 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
659 onDelNotifiers.erase(n);
660 }
661 //-----------------------------------------------------------------------------
662 void USERS_IMPL::AddNotifierUserAdd(NOTIFIER_BASE<USER_IMPL_PTR> * n)
663 {
664 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
665 onAddNotifiersImpl.insert(n);
666 }
667 //-----------------------------------------------------------------------------
668 void USERS_IMPL::DelNotifierUserAdd(NOTIFIER_BASE<USER_IMPL_PTR> * n)
669 {
670 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
671 onAddNotifiersImpl.erase(n);
672 }
673 //-----------------------------------------------------------------------------
674 void USERS_IMPL::AddNotifierUserDel(NOTIFIER_BASE<USER_IMPL_PTR> * n)
675 {
676 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
677 onDelNotifiersImpl.insert(n);
678 }
679 //-----------------------------------------------------------------------------
680 void USERS_IMPL::DelNotifierUserDel(NOTIFIER_BASE<USER_IMPL_PTR> * n)
681 {
682 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
683 onDelNotifiersImpl.erase(n);
684 }
685 //-----------------------------------------------------------------------------
686 int USERS_IMPL::OpenSearch()
687 {
688 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
689 handle++;
690 searchDescriptors[handle] = users.begin();
691 return handle;
692 }
693 //-----------------------------------------------------------------------------
694 int USERS_IMPL::SearchNext(int h, USER_PTR * user)
695 {
696     USER_IMPL * ptr = NULL;
697     if (SearchNext(h, &ptr))
698         return -1;
699     *user = ptr;
700     return 0;
701 }
702 //-----------------------------------------------------------------------------
703 int USERS_IMPL::SearchNext(int h, USER_IMPL ** user)
704 {
705 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
706
707 if (searchDescriptors.find(h) == searchDescriptors.end())
708     {
709     WriteServLog("USERS. Incorrect search handle.");
710     return -1;
711     }
712
713 if (searchDescriptors[h] == users.end())
714     return -1;
715
716 while (searchDescriptors[h]->GetDeleted())
717     {
718     ++searchDescriptors[h];
719     if (searchDescriptors[h] == users.end())
720         {
721         return -1;
722         }
723     }
724
725 *user = &(*searchDescriptors[h]);
726
727 ++searchDescriptors[h];
728
729 return 0;
730 }
731 //-----------------------------------------------------------------------------
732 int USERS_IMPL::CloseSearch(int h)
733 {
734 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
735 if (searchDescriptors.find(h) != searchDescriptors.end())
736     {
737     searchDescriptors.erase(searchDescriptors.find(h));
738     return 0;
739     }
740
741 WriteServLog("USERS. Incorrect search handle.");
742 return -1;
743 }
744 //-----------------------------------------------------------------------------
745 void USERS_IMPL::SetUserNotifiers(user_iter user)
746 {
747 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
748
749 PROPERTY_NOTIFER_IP_BEFORE nb(*this, user);
750 PROPERTY_NOTIFER_IP_AFTER  na(*this, user);
751
752 userIPNotifiersBefore.push_front(nb);
753 userIPNotifiersAfter.push_front(na);
754
755 user->AddCurrIPBeforeNotifier(&(*userIPNotifiersBefore.begin()));
756 user->AddCurrIPAfterNotifier(&(*userIPNotifiersAfter.begin()));
757 }
758 //-----------------------------------------------------------------------------
759 void USERS_IMPL::UnSetUserNotifiers(user_iter user)
760 {
761 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
762
763 list<PROPERTY_NOTIFER_IP_BEFORE>::iterator  bi;
764 list<PROPERTY_NOTIFER_IP_AFTER>::iterator   ai;
765
766 bi = userIPNotifiersBefore.begin();
767 while (bi != userIPNotifiersBefore.end())
768     {
769     if (bi->GetUser() == user)
770         {
771         bi->GetUser()->DelCurrIPBeforeNotifier(&(*bi));
772         userIPNotifiersBefore.erase(bi);
773         //printfd(__FILE__, "Notifier Before removed. User %s\n", bi->GetUser()->GetLogin().c_str());
774         break;
775         }
776     ++bi;
777     }
778
779 ai = userIPNotifiersAfter.begin();
780 while (ai != userIPNotifiersAfter.end())
781     {
782     if (ai->GetUser() == user)
783         {
784         ai->GetUser()->DelCurrIPAfterNotifier(&(*ai));
785         userIPNotifiersAfter.erase(ai);
786         //printfd(__FILE__, "Notifier After removed. User %s\n", ai->GetUser()->GetLogin().c_str());
787         break;
788         }
789     ++ai;
790     }
791 }
792 //-----------------------------------------------------------------------------
793 void USERS_IMPL::AddUserIntoIndexes(user_iter user)
794 {
795 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
796 loginIndex.insert(make_pair(user->GetLogin(), user));
797 }
798 //-----------------------------------------------------------------------------
799 void USERS_IMPL::DelUserFromIndexes(user_iter user)
800 {
801 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
802 loginIndex.erase(user->GetLogin());
803 }
804 //-----------------------------------------------------------------------------
805 bool USERS_IMPL::TimeToWriteDetailStat(const struct tm & t)
806 {
807 int statTime = settings->GetDetailStatWritePeriod();
808
809 switch (statTime)
810     {
811     case dsPeriod_1:
812         if (t.tm_min == 0)
813             return true;
814         break;
815     case dsPeriod_1_2:
816         if (t.tm_min % 30 == 0)
817             return true;
818         break;
819     case dsPeriod_1_4:
820         if (t.tm_min % 15 == 0)
821             return true;
822         break;
823     case dsPeriod_1_6:
824         if (t.tm_min % 10 == 0)
825             return true;
826         break;
827     }
828 return false;
829 }