]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
In the grand tradition of huge fucking commits:
[user/henk/code/inspircd.git] / src / xline.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "wildcard.h"
16 #include "xline.h"
17
18 /* Version two, now with optimized expiry!
19  *
20  * Because the old way was horrendously slow, the new way of expiring xlines is very
21  * very efficient. I have improved the efficiency of the algorithm in two ways:
22  *
23  * (1) There are now two lists of items for each linetype. One list holds temporary
24  *     items, and the other list holds permanent items (ones which will expire).
25  *     Items which are on the permanent list are NEVER checked at all by the
26  *     expire_lines() function.
27  * (2) The temporary xline lists are always kept in strict numerical order, keyed by
28  *     current time + duration. This means that the line which is due to expire the
29  *     soonest is always pointed at by vector::begin(), so a simple while loop can
30  *     very efficiently, very quickly and above all SAFELY pick off the first few
31  *     items in the vector which need zapping.
32  *
33  *     -- Brain
34  */
35
36 bool InitXLine(ServerConfig* conf, const char* tag)
37 {
38         return true;
39 }
40
41 bool DoneZLine(ServerConfig* conf, const char* tag)
42 {
43         conf->GetInstance()->XLines->apply_lines(APPLY_ZLINES|APPLY_PERM_ONLY);
44         return true;
45 }
46
47 bool DoneQLine(ServerConfig* conf, const char* tag)
48 {
49         conf->GetInstance()->XLines->apply_lines(APPLY_QLINES|APPLY_PERM_ONLY);
50         return true;
51 }
52
53 bool DoneKLine(ServerConfig* conf, const char* tag)
54 {
55         conf->GetInstance()->XLines->apply_lines(APPLY_KLINES|APPLY_PERM_ONLY);
56         return true;
57 }
58
59 bool DoneELine(ServerConfig* conf, const char* tag)
60 {
61         /* Yes, this is supposed to do nothing, we dont 'apply' these */
62         return true;
63 }
64
65 bool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
66 {
67         const char* reason = values[0].GetString();
68         const char* ipmask = values[1].GetString();
69
70         conf->GetInstance()->XLines->add_zline(0,"<Config>",reason,ipmask);
71         return true;
72 }
73
74 bool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
75 {
76         const char* reason = values[0].GetString();
77         const char* nick = values[1].GetString();
78
79         conf->GetInstance()->XLines->add_qline(0,"<Config>",reason,nick);
80         return true;
81 }
82
83 bool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
84 {
85         const char* reason = values[0].GetString();
86         const char* host = values[1].GetString();
87
88         conf->GetInstance()->XLines->add_kline(0,"<Config>",reason,host);
89         return true;
90 }
91
92 bool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
93 {
94         const char* reason = values[0].GetString();
95         const char* host = values[1].GetString();
96
97         conf->GetInstance()->XLines->add_eline(0,"<Config>",reason,host);
98         return true;
99 }
100
101 IdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host)
102 {
103         IdentHostPair n = std::make_pair<std::string,std::string>("*","*");
104         std::string::size_type x = ident_and_host.find('@');
105         if (x != std::string::npos)
106         {
107                 n.second = ident_and_host.substr(x + 1,ident_and_host.length());
108                 n.first = ident_and_host.substr(0, x);
109                 if (!n.first.length())
110                         n.first.assign("*");
111                 if (!n.second.length())
112                         n.second.assign("*");
113         }
114         else
115         {
116                 n.second = ident_and_host;
117         }
118
119         return n;
120 }
121
122 // adds a g:line
123
124 bool XLineManager::add_gline(long duration, const char* source,const char* reason,const char* hostmask)
125 {
126         IdentHostPair ih = IdentSplit(hostmask);
127
128         if (del_gline(hostmask, true))
129                 return false;
130
131         GLine* item = new GLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
132
133         if (duration)
134         {
135                 glines.push_back(item);
136                 sort(glines.begin(), glines.end(),XLineManager::GSortComparison);
137         }
138         else
139         {
140                 pglines.push_back(item);
141         }
142
143         return true;
144 }
145
146 // adds an e:line (exception to bans)
147
148 bool XLineManager::add_eline(long duration, const char* source, const char* reason, const char* hostmask)
149 {
150         IdentHostPair ih = IdentSplit(hostmask);
151
152         if (del_eline(hostmask, true))
153                 return false;
154
155         ELine* item = new ELine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
156
157         if (duration)
158         {
159                 elines.push_back(item);
160                 sort(elines.begin(), elines.end(),XLineManager::ESortComparison);
161         }
162         else
163         {
164                 pelines.push_back(item);
165         }
166         return true;
167 }
168
169 // adds a q:line
170
171 bool XLineManager::add_qline(long duration, const char* source, const char* reason, const char* nickname)
172 {
173         if (del_qline(nickname, true))
174                 return false;
175
176         QLine* item = new QLine(ServerInstance->Time(), duration, source, reason, nickname);
177
178         if (duration)
179         {
180                 qlines.push_back(item);
181                 sort(qlines.begin(), qlines.end(),XLineManager::QSortComparison);
182         }
183         else
184         {
185                 pqlines.push_back(item);
186         }
187         return true;
188 }
189
190 // adds a z:line
191
192 bool XLineManager::add_zline(long duration, const char* source, const char* reason, const char* ipaddr)
193 {
194         if (strchr(ipaddr,'@'))
195         {
196                 while (*ipaddr != '@')
197                         ipaddr++;
198                 ipaddr++;
199         }
200
201         if (del_zline(ipaddr, true))
202                 return false;
203
204         ZLine* item = new ZLine(ServerInstance->Time(), duration, source, reason, ipaddr);
205
206         if (duration)
207         {
208                 zlines.push_back(item);
209                 sort(zlines.begin(), zlines.end(),XLineManager::ZSortComparison);
210         }
211         else
212         {
213                 pzlines.push_back(item);
214         }
215         return true;
216 }
217
218 // adds a k:line
219
220 bool XLineManager::add_kline(long duration, const char* source, const char* reason, const char* hostmask)
221 {
222         IdentHostPair ih = IdentSplit(hostmask);
223
224         if (del_kline(hostmask, true))
225                 return false;
226
227         KLine* item = new KLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
228
229         if (duration)
230         {
231                 klines.push_back(item);
232                 sort(klines.begin(), klines.end(),XLineManager::KSortComparison);
233         }
234         else
235         {
236                 pklines.push_back(item);
237         }
238         return true;
239 }
240
241 // deletes a g:line, returns true if the line existed and was removed
242
243 bool XLineManager::del_gline(const char* hostmask, bool simulate)
244 {
245         IdentHostPair ih = IdentSplit(hostmask);
246         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
247         {
248                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
249                 {
250                         if (!simulate)
251                         {
252                                 delete *i;
253                                 glines.erase(i);
254                         }
255                         return true;
256                 }
257         }
258         for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
259         {
260                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
261                 {
262                         if (!simulate)
263                         {
264                                 delete *i;
265                                 pglines.erase(i);
266                         }
267                         return true;
268                 }
269         }
270         return false;
271 }
272
273 // deletes a e:line, returns true if the line existed and was removed
274
275 bool XLineManager::del_eline(const char* hostmask, bool simulate)
276 {
277         IdentHostPair ih = IdentSplit(hostmask);
278         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
279         {
280                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
281                 {
282                         if (!simulate)
283                         {
284                                 delete *i;
285                                 elines.erase(i);
286                         }
287                         return true;
288                 }
289         }
290         for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
291         {
292                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
293                 {
294                         if (!simulate)
295                         {
296                                 delete *i;
297                                 pelines.erase(i);
298                         }
299                         return true;
300                 }
301         }
302         return false;
303 }
304
305 // deletes a q:line, returns true if the line existed and was removed
306
307 bool XLineManager::del_qline(const char* nickname, bool simulate)
308 {
309         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
310         {
311                 if (!strcasecmp(nickname,(*i)->nick))
312                 {
313                         if (!simulate)
314                         {
315                                 delete *i;
316                                 qlines.erase(i);
317                         }
318                         return true;
319                 }
320         }
321         for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
322         {
323                 if (!strcasecmp(nickname,(*i)->nick))
324                 {
325                         if (!simulate)
326                         {
327                                 delete *i;
328                                 pqlines.erase(i);
329                         }
330                         return true;
331                 }
332         }
333         return false;
334 }
335
336 // deletes a z:line, returns true if the line existed and was removed
337
338 bool XLineManager::del_zline(const char* ipaddr, bool simulate)
339 {
340         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
341         {
342                 if (!strcasecmp(ipaddr,(*i)->ipaddr))
343                 {
344                         if (!simulate)
345                         {
346                                 delete *i;
347                                 zlines.erase(i);
348                         }
349                         return true;
350                 }
351         }
352         for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
353         {
354                 if (!strcasecmp(ipaddr,(*i)->ipaddr))
355                 {
356                         if (!simulate)
357                         {
358                                 delete *i;
359                                 pzlines.erase(i);
360                         }
361                         return true;
362                 }
363         }
364         return false;
365 }
366
367 // deletes a k:line, returns true if the line existed and was removed
368
369 bool XLineManager::del_kline(const char* hostmask, bool simulate)
370 {
371         IdentHostPair ih = IdentSplit(hostmask);
372         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
373         {
374                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
375                 {
376                         if (!simulate)
377                         {
378                                 delete *i;
379                                 klines.erase(i);
380                         }
381                         return true;
382                 }
383         }
384         for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)
385         {
386                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
387                 {
388                         if (!simulate)
389                         {
390                                 delete *i;
391                                 pklines.erase(i);
392                         }
393                         return true;
394                 }
395         }
396         return false;
397 }
398
399 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
400
401 QLine* XLineManager::matches_qline(const char* nick, bool permonly)
402 {
403         if ((qlines.empty()) && (pqlines.empty()))
404                 return NULL;
405         if (!permonly)
406         {
407                 for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
408                         if (match(nick,(*i)->nick))
409                                 return (*i);
410         }
411         for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
412                 if (match(nick,(*i)->nick))
413                         return (*i);
414         return NULL;
415 }
416
417 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
418
419 GLine* XLineManager::matches_gline(User* user, bool permonly)
420 {
421         if ((glines.empty()) && (pglines.empty()))
422                 return NULL;
423         if (!permonly)
424         {
425                 for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
426                 {
427                         if ((match(user->ident,(*i)->identmask)))
428                         {
429                                 if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
430                                 {
431                                         return (*i);
432                                 }
433                         }
434                 }
435         }
436         for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
437         {
438                 if ((match(user->ident,(*i)->identmask)))
439                 {
440                         if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
441                         {
442                                 return (*i);
443                         }
444                 }
445         }
446         return NULL;
447 }
448
449 ELine* XLineManager::matches_exception(User* user, bool permonly)
450 {
451         if ((elines.empty()) && (pelines.empty()))
452                 return NULL;
453         char host2[MAXBUF];
454         snprintf(host2,MAXBUF,"*@%s",user->host);
455         if (!permonly)
456         {
457                 for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
458                 {
459                         if ((match(user->ident,(*i)->identmask)))
460                         {
461                                 if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
462                                 {
463                                         return (*i);
464                                 }
465                         }
466                 }
467         }
468         for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
469         {
470                 if ((match(user->ident,(*i)->identmask)))
471                 {
472                         if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
473                         {
474                                 return (*i);
475                         }
476                 }
477         }
478         return NULL;
479 }
480
481
482 void XLineManager::gline_set_creation_time(const char* host, time_t create_time)
483 {
484         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
485         {
486                 if (!strcasecmp(host,(*i)->hostmask))
487                 {
488                         (*i)->set_time = create_time;
489                         (*i)->expiry = create_time + (*i)->duration;
490                         return;
491                 }
492         }
493         for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
494         {
495                 if (!strcasecmp(host,(*i)->hostmask))
496                 {
497                         (*i)->set_time = create_time;
498                         return;
499                 }
500         }
501         return ;
502 }
503
504 void XLineManager::eline_set_creation_time(const char* host, time_t create_time)
505 {
506         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
507         {
508                 if (!strcasecmp(host,(*i)->hostmask))
509                 {
510                         (*i)->set_time = create_time;
511                         (*i)->expiry = create_time + (*i)->duration;
512                         return;
513                 }
514         }
515         for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
516         {
517                 if (!strcasecmp(host,(*i)->hostmask))
518                 {
519                         (*i)->set_time = create_time;
520                         return;
521                 }
522         }
523         return;
524 }
525
526 void XLineManager::qline_set_creation_time(const char* nick, time_t create_time)
527 {
528         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
529         {
530                 if (!strcasecmp(nick,(*i)->nick))
531                 {
532                         (*i)->set_time = create_time;
533                         (*i)->expiry = create_time + (*i)->duration;
534                         return;
535                 }
536         }
537         for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
538         {
539                 if (!strcasecmp(nick,(*i)->nick))
540                 {
541                         (*i)->set_time = create_time;
542                         return;
543                 }
544         }
545         return;
546 }
547
548 void XLineManager::zline_set_creation_time(const char* ip, time_t create_time)
549 {
550         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
551         {
552                 if (!strcasecmp(ip,(*i)->ipaddr))
553                 {
554                         (*i)->set_time = create_time;
555                         (*i)->expiry = create_time + (*i)->duration;
556                         return;
557                 }
558         }
559         for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
560         {
561                 if (!strcasecmp(ip,(*i)->ipaddr))
562                 {
563                         (*i)->set_time = create_time;
564                         return;
565                 }
566         }
567         return;
568 }
569
570 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
571
572 ZLine* XLineManager::matches_zline(const char* ipaddr, bool permonly)
573 {
574         if ((zlines.empty()) && (pzlines.empty()))
575                 return NULL;
576         if (!permonly)
577         {
578                 for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
579                         if (match(ipaddr,(*i)->ipaddr, true))
580                                 return (*i);
581         }
582         for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
583                 if (match(ipaddr,(*i)->ipaddr, true))
584                         return (*i);
585         return NULL;
586 }
587
588 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
589
590 KLine* XLineManager::matches_kline(User* user, bool permonly)
591 {
592         if ((klines.empty()) && (pklines.empty()))
593                 return NULL;
594         if (!permonly)
595         {
596                 for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
597                 {
598                         if ((match(user->ident,(*i)->identmask)))
599                         {
600                                 if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
601                                 {
602                                         return (*i);
603                                 }
604                         }
605                 }
606         }
607         for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)
608         {
609                 if ((match(user->ident,(*i)->identmask)))
610                 {
611                         if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
612                         {
613                                 return (*i);
614                         }
615                 }
616         }
617         return NULL;
618 }
619
620 bool XLineManager::GSortComparison ( const GLine* one, const GLine* two )
621 {
622         return (one->expiry) < (two->expiry);
623 }
624
625 bool XLineManager::ESortComparison ( const ELine* one, const ELine* two )
626 {
627         return (one->expiry) < (two->expiry);
628 }
629
630 bool XLineManager::ZSortComparison ( const ZLine* one, const ZLine* two )
631 {
632         return (one->expiry) < (two->expiry);
633 }
634
635 bool XLineManager::KSortComparison ( const KLine* one, const KLine* two )
636 {
637         return (one->expiry) < (two->expiry);
638 }
639
640 bool XLineManager::QSortComparison ( const QLine* one, const QLine* two )
641 {
642         return (one->expiry) < (two->expiry);
643 }
644
645 // removes lines that have expired
646
647 void XLineManager::expire_lines()
648 {
649         time_t current = ServerInstance->Time();
650
651         /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this
652          * means that to expire the XLines we just need to do a while, picking off the top few until there are
653          * none left at the head of the queue that are after the current time.
654          */
655
656         while ((glines.size()) && (current > (*glines.begin())->expiry))
657         {
658                 std::vector<GLine*>::iterator i = glines.begin();
659                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
660                 glines.erase(i);
661         }
662
663         while ((elines.size()) && (current > (*elines.begin())->expiry))
664         {
665                 std::vector<ELine*>::iterator i = elines.begin();
666                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
667                 elines.erase(i);
668         }
669
670         while ((zlines.size()) && (current > (*zlines.begin())->expiry))
671         {
672                 std::vector<ZLine*>::iterator i = zlines.begin();
673                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",(*i)->ipaddr,(*i)->source,(*i)->duration);
674                 zlines.erase(i);
675         }
676
677         while ((klines.size()) && (current > (*klines.begin())->expiry))
678         {
679                 std::vector<KLine*>::iterator i = klines.begin();
680                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
681                 klines.erase(i);
682         }
683
684         while ((qlines.size()) && (current > (*qlines.begin())->expiry))
685         {
686                 std::vector<QLine*>::iterator i = qlines.begin();
687                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",(*i)->nick,(*i)->source,(*i)->duration);
688                 qlines.erase(i);
689         }
690
691 }
692
693 // applies lines, removing clients and changing nicks etc as applicable
694
695 void XLineManager::apply_lines(const int What)
696 {
697         if (!What)
698                 return;
699
700         if (What & APPLY_PERM_ONLY)
701         {
702                 char reason[MAXBUF];
703
704                 if ((!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size()))
705                         return;
706
707                 XLine* check = NULL;
708                 for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
709                 {
710                         User* u = (User*)(*u2);
711
712                         if (elines.size() || pelines.size())
713                                 if (matches_exception(u))
714                                         continue;
715
716                         if ((What & APPLY_GLINES) && pglines.size())
717                         {
718                                 if ((check = matches_gline(u,true)))
719                                 {
720                                         snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);
721                                         if (*ServerInstance->Config->MoronBanner)
722                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
723                                         if (ServerInstance->Config->HideBans)
724                                                 User::QuitUser(ServerInstance, u, "G-Lined", reason);
725                                         else
726                                                 User::QuitUser(ServerInstance, u, reason);
727                                 }
728                         }
729
730                         if ((What & APPLY_KLINES) && pklines.size())
731                         {
732                                 if ((check = matches_kline(u,true)))
733                                 {
734                                         snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);
735                                         if (*ServerInstance->Config->MoronBanner)
736                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
737                                         if (ServerInstance->Config->HideBans)
738                                                 User::QuitUser(ServerInstance, u, "K-Lined", reason);
739                                         else
740                                                 User::QuitUser(ServerInstance, u, reason);
741                                 }
742                         }
743
744                         if ((What & APPLY_QLINES) && pqlines.size())
745                         {
746                                 if ((check = matches_qline(u->nick,true)))
747                                 {
748                                         snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);
749                                         if (*ServerInstance->Config->MoronBanner)
750                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
751                                         if (ServerInstance->Config->HideBans)
752                                                 User::QuitUser(ServerInstance, u, "Q-Lined", reason);
753                                         else
754                                                 User::QuitUser(ServerInstance, u, reason);
755                                 }
756                         }
757
758                         if ((What & APPLY_ZLINES) && pzlines.size())
759                         {
760                                 if ((check = matches_zline(u->GetIPString(),true)))
761                                 {
762                                         snprintf(reason,MAXBUF,"Z-Lined: %s",check->reason);
763                                         if (*ServerInstance->Config->MoronBanner)
764                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
765                                         if (ServerInstance->Config->HideBans)
766                                                 User::QuitUser(ServerInstance, u, "Z-Lined", reason);
767                                         else
768                                                 User::QuitUser(ServerInstance, u, reason);
769                                 }
770                         }
771                 }
772         }
773         else
774         {
775                 char reason[MAXBUF];
776
777                 if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()) &&
778                 (!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size()))
779                         return;
780
781                 XLine* check = NULL;
782                 for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
783                 {
784                         User* u = (User*)(*u2);
785
786                         if (elines.size() || pelines.size())
787                         {
788                                 // ignore people matching exempts
789                                 if (matches_exception(u))
790                                         continue;
791                         }
792                         if ((What & APPLY_GLINES) && (glines.size() || pglines.size()))
793                         {
794                                 if ((check = matches_gline(u)))
795                                 {
796                                         snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);
797                                         if (*ServerInstance->Config->MoronBanner)
798                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
799                                         if (ServerInstance->Config->HideBans)
800                                                 User::QuitUser(ServerInstance, u, "G-Lined", reason);
801                                         else
802                                                 User::QuitUser(ServerInstance, u, reason);
803                                 }
804                         }
805                         if ((What & APPLY_KLINES) && (klines.size() || pklines.size()))
806                         {
807                                 if ((check = matches_kline(u)))
808                                 {
809                                         snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);
810                                         if (*ServerInstance->Config->MoronBanner)
811                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
812                                         if (ServerInstance->Config->HideBans)
813                                                 User::QuitUser(ServerInstance, u, "K-Lined", reason);
814                                         else
815                                                 User::QuitUser(ServerInstance, u, reason);
816                                 }
817                         }
818                         if ((What & APPLY_QLINES) && (qlines.size() || pqlines.size()))
819                         {
820                                 if ((check = matches_qline(u->nick)))
821                                 {
822                                         snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);
823                                         if (*ServerInstance->Config->MoronBanner)
824                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
825                                         if (ServerInstance->Config->HideBans)
826                                                 User::QuitUser(ServerInstance, u, "Q-Lined", reason);
827                                         else
828                                                 User::QuitUser(ServerInstance, u, reason);
829                                 }
830                         }
831                         if ((What & APPLY_ZLINES) && (zlines.size() || pzlines.size()))
832                         {
833                                 if ((check = matches_zline(u->GetIPString())))
834                                 {
835                                         snprintf(reason,MAXBUF,"Z-Lined: %s", check->reason);
836                                         if (*ServerInstance->Config->MoronBanner)
837                                                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
838                                         if (ServerInstance->Config->HideBans)
839                                                 User::QuitUser(ServerInstance, u, "Z-Lined", reason);
840                                         else
841                                                 User::QuitUser(ServerInstance, u, reason);
842                                 }
843                         }
844                 }
845         }
846 }
847
848 void XLineManager::stats_k(User* user, string_list &results)
849 {
850         std::string sn = ServerInstance->Config->ServerName;
851         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
852                 results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
853         for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)
854                 results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
855 }
856
857 void XLineManager::stats_g(User* user, string_list &results)
858 {
859         std::string sn = ServerInstance->Config->ServerName;
860         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
861                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
862         for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
863                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
864 }
865
866 void XLineManager::stats_q(User* user, string_list &results)
867 {
868         std::string sn = ServerInstance->Config->ServerName;
869         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
870                 results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
871         for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
872                 results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
873 }
874
875 void XLineManager::stats_z(User* user, string_list &results)
876 {
877         std::string sn = ServerInstance->Config->ServerName;
878         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
879                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
880         for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
881                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
882 }
883
884 void XLineManager::stats_e(User* user, string_list &results)
885 {
886         std::string sn = ServerInstance->Config->ServerName;
887         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
888                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
889         for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
890                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
891 }
892
893 XLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)
894 {
895 }