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