]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
857c540690a673f887245f9a4536df921580de5a
[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 /* $Core: libIRCDxline */
15
16 #include "inspircd.h"
17 #include "wildcard.h"
18 #include "xline.h"
19
20 /*
21  * This is now version 3 of the XLine subsystem, let's see if we can get it as nice and 
22  * efficient as we can this time so we can close this file and never ever touch it again ..
23  *
24  * Background:
25  *  Version 1 stored all line types in one list (one for g, one for z, etc). This was fine,
26  *  but both version 1 and 2 suck at applying lines efficiently. That is, every time a new line
27  *  was added, it iterated every existing line for every existing user. Ow. Expiry was also
28  *  expensive, as the lists were NOT sorted.
29  *
30  *  Version 2 moved permanent lines into a seperate list from non-permanent to help optimize
31  *  matching speed, but matched in the same way.
32  *  Expiry was also sped up by sorting the list by expiry (meaning just remove the items at the
33  *  head of the list that are outdated.)
34  *
35  * This was fine and good, but it looked less than ideal in code, and matching was still slower
36  * than it could have been, something which we address here.
37  *
38  * VERSION 3:
39  *  All lines are (as in v1) stored together -- no seperation of perm and non-perm. Expiry will
40  *  still use a sorted list, and we'll just ignore anything permanent.
41  *
42  *  Application will be by a list of lines 'pending' application, meaning only the newly added lines
43  *  will be gone over. Much faster.
44  *
45  * More of course is to come.
46  */
47
48 /* Version two, now with optimized expiry!
49  *
50  * Because the old way was horrendously slow, the new way of expiring xlines is very
51  * very efficient. I have improved the efficiency of the algorithm in two ways:
52  *
53  * (1) There are now two lists of items for each linetype. One list holds temporary
54  *     items, and the other list holds permanent items (ones which will expire).
55  *     Items which are on the permanent list are NEVER checked at all by the
56  *     expire_lines() function.
57  * (2) The temporary xline lists are always kept in strict numerical order, keyed by
58  *     current time + duration. This means that the line which is due to expire the
59  *     soonest is always pointed at by vector::begin(), so a simple while loop can
60  *     very efficiently, very quickly and above all SAFELY pick off the first few
61  *     items in the vector which need zapping.
62  *
63  *     -- Brain
64  */
65
66 bool InitXLine(ServerConfig* conf, const char* tag)
67 {
68         return true;
69 }
70
71 bool DoneZLine(ServerConfig* conf, const char* tag)
72 {
73         // XXX we should really only call this once - after we've finished processing configuration all together
74         conf->GetInstance()->XLines->ApplyLines();
75         return true;
76 }
77
78 bool DoneQLine(ServerConfig* conf, const char* tag)
79 {
80         // XXX we should really only call this once - after we've finished processing configuration all together
81         conf->GetInstance()->XLines->ApplyLines();
82         return true;
83 }
84
85 bool DoneKLine(ServerConfig* conf, const char* tag)
86 {
87         // XXX we should really only call this once - after we've finished processing configuration all together
88         conf->GetInstance()->XLines->ApplyLines();
89         return true;
90 }
91
92 bool DoneELine(ServerConfig* conf, const char* tag)
93 {
94         // XXX we should really only call this once - after we've finished processing configuration all together
95         conf->GetInstance()->XLines->ApplyLines();
96         return true;
97 }
98
99 bool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
100 {
101         const char* reason = values[0].GetString();
102         const char* ipmask = values[1].GetString();
103
104         conf->GetInstance()->XLines->AddZLine(0,"<Config>",reason,ipmask);
105         return true;
106 }
107
108 bool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
109 {
110         const char* reason = values[0].GetString();
111         const char* nick = values[1].GetString();
112
113         conf->GetInstance()->XLines->AddQLine(0,"<Config>",reason,nick);
114         return true;
115 }
116
117 bool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
118 {
119         const char* reason = values[0].GetString();
120         const char* host = values[1].GetString();
121
122         conf->GetInstance()->XLines->AddKLine(0,"<Config>",reason,host);
123         return true;
124 }
125
126 bool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
127 {
128         const char* reason = values[0].GetString();
129         const char* host = values[1].GetString();
130
131         conf->GetInstance()->XLines->AddELine(0,"<Config>",reason,host);
132         return true;
133 }
134
135 bool XLine::Matches(User *u)
136 {
137         return false;
138 }
139
140 IdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host)
141 {
142         IdentHostPair n = std::make_pair<std::string,std::string>("*","*");
143         std::string::size_type x = ident_and_host.find('@');
144         if (x != std::string::npos)
145         {
146                 n.second = ident_and_host.substr(x + 1,ident_and_host.length());
147                 n.first = ident_and_host.substr(0, x);
148                 if (!n.first.length())
149                         n.first.assign("*");
150                 if (!n.second.length())
151                         n.second.assign("*");
152         }
153         else
154         {
155                 n.second = ident_and_host;
156         }
157
158         return n;
159 }
160
161 // adds a g:line
162
163 bool XLineManager::AddGLine(long duration, const char* source,const char* reason,const char* hostmask)
164 {
165         IdentHostPair ih = IdentSplit(hostmask);
166
167         if (DelGLine(hostmask, true))
168                 return false;
169
170         GLine* item = new GLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
171
172         glines.push_back(item);
173         sort(glines.begin(), glines.end(),XLineManager::XSortComparison);
174
175         return true;
176 }
177
178 // adds an e:line (exception to bans)
179
180 bool XLineManager::AddELine(long duration, const char* source, const char* reason, const char* hostmask)
181 {
182         IdentHostPair ih = IdentSplit(hostmask);
183
184         if (DelELine(hostmask, true))
185                 return false;
186
187         ELine* item = new ELine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
188
189         elines.push_back(item);
190         sort(elines.begin(), elines.end(),XLineManager::XSortComparison);
191
192         return true;
193 }
194
195 // adds a q:line
196
197 bool XLineManager::AddQLine(long duration, const char* source, const char* reason, const char* nickname)
198 {
199         if (DelQLine(nickname, true))
200                 return false;
201
202         QLine* item = new QLine(ServerInstance->Time(), duration, source, reason, nickname);
203
204         qlines.push_back(item);
205         sort(qlines.begin(), qlines.end(),XLineManager::XSortComparison);
206
207         return true;
208 }
209
210 // adds a z:line
211
212 bool XLineManager::AddZLine(long duration, const char* source, const char* reason, const char* ipaddr)
213 {
214         if (strchr(ipaddr,'@'))
215         {
216                 while (*ipaddr != '@')
217                         ipaddr++;
218                 ipaddr++;
219         }
220
221         if (DelZLine(ipaddr, true))
222                 return false;
223
224         ZLine* item = new ZLine(ServerInstance->Time(), duration, source, reason, ipaddr);
225
226         zlines.push_back(item);
227         sort(zlines.begin(), zlines.end(),XLineManager::XSortComparison);
228
229         return true;
230 }
231
232 // adds a k:line
233
234 bool XLineManager::AddKLine(long duration, const char* source, const char* reason, const char* hostmask)
235 {
236         IdentHostPair ih = IdentSplit(hostmask);
237
238         if (DelKLine(hostmask, true))
239                 return false;
240
241         KLine* item = new KLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
242
243         klines.push_back(item);
244         sort(klines.begin(), klines.end(),XLineManager::XSortComparison);
245
246         return true;
247 }
248
249 // deletes a g:line, returns true if the line existed and was removed
250
251 bool XLineManager::DelGLine(const char* hostmask, bool simulate)
252 {
253         IdentHostPair ih = IdentSplit(hostmask);
254         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
255         {
256                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
257                 {
258                         if (!simulate)
259                         {
260                                 delete *i;
261                                 glines.erase(i);
262                         }
263                         return true;
264                 }
265         }
266
267         return false;
268 }
269
270 // deletes a e:line, returns true if the line existed and was removed
271
272 bool XLineManager::DelELine(const char* hostmask, bool simulate)
273 {
274         IdentHostPair ih = IdentSplit(hostmask);
275         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
276         {
277                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
278                 {
279                         if (!simulate)
280                         {
281                                 delete *i;
282                                 elines.erase(i);
283                         }
284                         return true;
285                 }
286         }
287
288         return false;
289 }
290
291 // deletes a q:line, returns true if the line existed and was removed
292
293 bool XLineManager::DelQLine(const char* nickname, bool simulate)
294 {
295         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
296         {
297                 if (!strcasecmp(nickname,(*i)->nick))
298                 {
299                         if (!simulate)
300                         {
301                                 delete *i;
302                                 qlines.erase(i);
303                         }
304                         return true;
305                 }
306         }
307
308         return false;
309 }
310
311 // deletes a z:line, returns true if the line existed and was removed
312
313 bool XLineManager::DelZLine(const char* ipaddr, bool simulate)
314 {
315         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
316         {
317                 if (!strcasecmp(ipaddr,(*i)->ipaddr))
318                 {
319                         if (!simulate)
320                         {
321                                 delete *i;
322                                 zlines.erase(i);
323                         }
324                         return true;
325                 }
326         }
327
328         return false;
329 }
330
331 // deletes a k:line, returns true if the line existed and was removed
332
333 bool XLineManager::DelKLine(const char* hostmask, bool simulate)
334 {
335         IdentHostPair ih = IdentSplit(hostmask);
336         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
337         {
338                 if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
339                 {
340                         if (!simulate)
341                         {
342                                 delete *i;
343                                 klines.erase(i);
344                         }
345                         return true;
346                 }
347         }
348
349         return false;
350 }
351
352 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
353
354 QLine* XLineManager::matches_qline(const char* nick)
355 {
356         if (qlines.empty())
357                 return NULL;
358
359         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
360                 if (match(nick,(*i)->nick))
361                         return (*i);
362         return NULL;
363 }
364
365 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
366
367 GLine* XLineManager::matches_gline(User* user)
368 {
369         if (glines.empty())
370                 return NULL;
371
372         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
373         {
374                 if ((match(user->ident,(*i)->identmask)))
375                 {
376                         if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
377                         {
378                                 return (*i);
379                         }
380                 }
381         }
382
383         return NULL;
384 }
385
386 ELine* XLineManager::matches_exception(User* user)
387 {
388         if (elines.empty())
389                 return NULL;
390         char host2[MAXBUF];
391
392         snprintf(host2,MAXBUF,"*@%s",user->host);
393         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
394         {
395                 if ((match(user->ident,(*i)->identmask)))
396                 {
397                         if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
398                         {
399                                 return (*i);
400                         }
401                 }
402         }
403         return NULL;
404 }
405
406
407 void XLineManager::gline_set_creation_time(const char* host, time_t create_time)
408 {
409         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
410         {
411                 if (!strcasecmp(host,(*i)->hostmask))
412                 {
413                         (*i)->set_time = create_time;
414                         (*i)->expiry = create_time + (*i)->duration;
415                         return;
416                 }
417         }
418
419         return ;
420 }
421
422 void XLineManager::eline_set_creation_time(const char* host, time_t create_time)
423 {
424         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
425         {
426                 if (!strcasecmp(host,(*i)->hostmask))
427                 {
428                         (*i)->set_time = create_time;
429                         (*i)->expiry = create_time + (*i)->duration;
430                         return;
431                 }
432         }
433
434         return;
435 }
436
437 void XLineManager::qline_set_creation_time(const char* nick, time_t create_time)
438 {
439         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
440         {
441                 if (!strcasecmp(nick,(*i)->nick))
442                 {
443                         (*i)->set_time = create_time;
444                         (*i)->expiry = create_time + (*i)->duration;
445                         return;
446                 }
447         }
448
449         return;
450 }
451
452 void XLineManager::zline_set_creation_time(const char* ip, time_t create_time)
453 {
454         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
455         {
456                 if (!strcasecmp(ip,(*i)->ipaddr))
457                 {
458                         (*i)->set_time = create_time;
459                         (*i)->expiry = create_time + (*i)->duration;
460                         return;
461                 }
462         }
463
464         return;
465 }
466
467 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
468
469 ZLine* XLineManager::matches_zline(User *u)
470 {
471         if (zlines.empty())
472                 return NULL;
473
474         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
475                 if ((*i)->Matches(u))
476                         return (*i);
477         return NULL;
478 }
479
480 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
481
482 KLine* XLineManager::matches_kline(User* user)
483 {
484         if (klines.empty())
485                 return NULL;
486
487         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
488         {
489                 if ((*i)->Matches(user))
490                         return (*i);
491         }
492
493         return NULL;
494 }
495
496 bool XLineManager::XSortComparison(const XLine *one, const XLine *two)
497 {
498         // account for permanent lines
499         if (one->expiry == 0)
500         {
501                 return false;
502         }
503         return (one->expiry) < (two->expiry);
504 }
505
506 // removes lines that have expired
507 void XLineManager::expire_lines()
508 {
509         time_t current = ServerInstance->Time();
510
511         /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this
512          * means that to expire the XLines we just need to do a while, picking off the top few until there are
513          * none left at the head of the queue that are after the current time.
514          */
515
516         while ((glines.size()) && (current > (*glines.begin())->expiry) && ((*glines.begin())->duration != 0))
517         {
518                 std::vector<GLine*>::iterator i = glines.begin();
519                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
520                 glines.erase(i);
521         }
522
523         while ((elines.size()) && (current > (*elines.begin())->expiry) && ((*elines.begin())->duration != 0))
524         {
525                 std::vector<ELine*>::iterator i = elines.begin();
526                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
527                 elines.erase(i);
528         }
529
530         while ((zlines.size()) && (current > (*zlines.begin())->expiry) && ((*zlines.begin())->duration != 0))
531         {
532                 std::vector<ZLine*>::iterator i = zlines.begin();
533                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",(*i)->ipaddr,(*i)->source,(*i)->duration);
534                 zlines.erase(i);
535         }
536
537         while ((klines.size()) && (current > (*klines.begin())->expiry) && ((*klines.begin())->duration != 0))
538         {
539                 std::vector<KLine*>::iterator i = klines.begin();
540                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
541                 klines.erase(i);
542         }
543
544         while ((qlines.size()) && (current > (*qlines.begin())->expiry) && ((*qlines.begin())->duration != 0))
545         {
546                 std::vector<QLine*>::iterator i = qlines.begin();
547                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",(*i)->nick,(*i)->source,(*i)->duration);
548                 qlines.erase(i);
549         }
550
551 }
552
553 // applies lines, removing clients and changing nicks etc as applicable
554
555 void XLineManager::ApplyLines()
556 {
557         int What = 0; // XXX remove me
558         char reason[MAXBUF];
559
560         XLine* check = NULL;
561         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
562         {
563                 User* u = (User*)(*u2);
564
565                 if (elines.size())
566                 {
567                         // ignore people matching exempts
568                         if (matches_exception(u))
569                                 continue;
570                 }
571                 if ((What & APPLY_GLINES) && (glines.size()))
572                 {
573                         if ((check = matches_gline(u)))
574                         {
575                                 snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);
576                                 if (*ServerInstance->Config->MoronBanner)
577                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
578                                 if (ServerInstance->Config->HideBans)
579                                         User::QuitUser(ServerInstance, u, "G-Lined", reason);
580                                 else
581                                         User::QuitUser(ServerInstance, u, reason);
582                         }
583                 }
584                 if ((What & APPLY_KLINES) && (klines.size()))
585                 {
586                         if ((check = matches_kline(u)))
587                         {
588                                 snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);
589                                 if (*ServerInstance->Config->MoronBanner)
590                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
591                                 if (ServerInstance->Config->HideBans)
592                                         User::QuitUser(ServerInstance, u, "K-Lined", reason);
593                                 else
594                                         User::QuitUser(ServerInstance, u, reason);
595                         }
596                 }
597                 if ((What & APPLY_QLINES) && (qlines.size()))
598                 {
599                         if ((check = matches_qline(u->nick)))
600                         {
601                                 snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);
602                                 if (*ServerInstance->Config->MoronBanner)
603                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
604                                 if (ServerInstance->Config->HideBans)
605                                         User::QuitUser(ServerInstance, u, "Q-Lined", reason);
606                                 else
607                                         User::QuitUser(ServerInstance, u, reason);
608                         }
609                 }
610                 if ((What & APPLY_ZLINES) && (zlines.size()))
611                 {
612                         if ((check = matches_zline(u)))
613                         {
614                                 snprintf(reason,MAXBUF,"Z-Lined: %s", check->reason);
615                                 if (*ServerInstance->Config->MoronBanner)
616                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
617                                 if (ServerInstance->Config->HideBans)
618                                         User::QuitUser(ServerInstance, u, "Z-Lined", reason);
619                                 else
620                                         User::QuitUser(ServerInstance, u, reason);
621                         }
622                 }
623         }
624 }
625
626 void XLineManager::stats_k(User* user, string_list &results)
627 {
628         std::string sn = ServerInstance->Config->ServerName;
629         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
630                 results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
631 }
632
633 void XLineManager::stats_g(User* user, string_list &results)
634 {
635         std::string sn = ServerInstance->Config->ServerName;
636         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
637                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
638 }
639
640 void XLineManager::stats_q(User* user, string_list &results)
641 {
642         std::string sn = ServerInstance->Config->ServerName;
643         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
644                 results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
645 }
646
647 void XLineManager::stats_z(User* user, string_list &results)
648 {
649         std::string sn = ServerInstance->Config->ServerName;
650         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
651                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
652 }
653
654 void XLineManager::stats_e(User* user, string_list &results)
655 {
656         std::string sn = ServerInstance->Config->ServerName;
657         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
658                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
659 }
660
661 XLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)
662 {
663 }
664
665
666
667 bool KLine::Matches(User *u)
668 {
669         if ((match(u->ident, this->identmask)))
670         {
671                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
672                 {
673                         return true;
674                 }
675         }
676
677         return false;
678 }
679
680 bool GLine::Matches(User *u)
681 {
682         return false;
683 }
684
685 bool ELine::Matches(User *u)
686 {
687         return false;
688 }
689
690 bool ZLine::Matches(User *u)
691 {
692         if (match(u->GetIPString(), this->ipaddr, true))
693                 return true;
694         else
695                 return false;
696 }
697
698 bool QLine::Matches(User *u)
699 {
700         return false;
701 }