]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
a6ed0e6059f780c019216662a1d3066e13144d13
[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 ((*i)->Matches(user))
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 ((*i)->Matches(user))
375                         return (*i);
376         }
377
378         return NULL;
379 }
380
381 ELine* XLineManager::matches_exception(User* user)
382 {
383         if (elines.empty())
384                 return NULL;
385
386         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
387         {
388                 if ((*i)->Matches(user))
389                         return (*i);
390         }
391         return NULL;
392 }
393
394
395 void XLineManager::gline_set_creation_time(const char* host, time_t create_time)
396 {
397         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
398         {
399                 if (!strcasecmp(host,(*i)->hostmask))
400                 {
401                         (*i)->set_time = create_time;
402                         (*i)->expiry = create_time + (*i)->duration;
403                         return;
404                 }
405         }
406
407         return ;
408 }
409
410 void XLineManager::eline_set_creation_time(const char* host, time_t create_time)
411 {
412         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
413         {
414                 if (!strcasecmp(host,(*i)->hostmask))
415                 {
416                         (*i)->set_time = create_time;
417                         (*i)->expiry = create_time + (*i)->duration;
418                         return;
419                 }
420         }
421
422         return;
423 }
424
425 void XLineManager::qline_set_creation_time(const char* nick, time_t create_time)
426 {
427         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
428         {
429                 if (!strcasecmp(nick,(*i)->nick))
430                 {
431                         (*i)->set_time = create_time;
432                         (*i)->expiry = create_time + (*i)->duration;
433                         return;
434                 }
435         }
436
437         return;
438 }
439
440 void XLineManager::zline_set_creation_time(const char* ip, time_t create_time)
441 {
442         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
443         {
444                 if (!strcasecmp(ip,(*i)->ipaddr))
445                 {
446                         (*i)->set_time = create_time;
447                         (*i)->expiry = create_time + (*i)->duration;
448                         return;
449                 }
450         }
451
452         return;
453 }
454
455 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
456
457 ZLine* XLineManager::matches_zline(User *u)
458 {
459         if (zlines.empty())
460                 return NULL;
461
462         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
463                 if ((*i)->Matches(u))
464                         return (*i);
465         return NULL;
466 }
467
468 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
469
470 KLine* XLineManager::matches_kline(User* user)
471 {
472         if (klines.empty())
473                 return NULL;
474
475         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
476         {
477                 if ((*i)->Matches(user))
478                         return (*i);
479         }
480
481         return NULL;
482 }
483
484 bool XLineManager::XSortComparison(const XLine *one, const XLine *two)
485 {
486         // account for permanent lines
487         if (one->expiry == 0)
488         {
489                 return false;
490         }
491         return (one->expiry) < (two->expiry);
492 }
493
494 // removes lines that have expired
495 void XLineManager::expire_lines()
496 {
497         time_t current = ServerInstance->Time();
498
499         /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this
500          * means that to expire the XLines we just need to do a while, picking off the top few until there are
501          * none left at the head of the queue that are after the current time.
502          */
503
504         while ((glines.size()) && (current > (*glines.begin())->expiry) && ((*glines.begin())->duration != 0))
505         {
506                 std::vector<GLine*>::iterator i = glines.begin();
507                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
508                 glines.erase(i);
509         }
510
511         while ((elines.size()) && (current > (*elines.begin())->expiry) && ((*elines.begin())->duration != 0))
512         {
513                 std::vector<ELine*>::iterator i = elines.begin();
514                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
515                 elines.erase(i);
516         }
517
518         while ((zlines.size()) && (current > (*zlines.begin())->expiry) && ((*zlines.begin())->duration != 0))
519         {
520                 std::vector<ZLine*>::iterator i = zlines.begin();
521                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",(*i)->ipaddr,(*i)->source,(*i)->duration);
522                 zlines.erase(i);
523         }
524
525         while ((klines.size()) && (current > (*klines.begin())->expiry) && ((*klines.begin())->duration != 0))
526         {
527                 std::vector<KLine*>::iterator i = klines.begin();
528                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
529                 klines.erase(i);
530         }
531
532         while ((qlines.size()) && (current > (*qlines.begin())->expiry) && ((*qlines.begin())->duration != 0))
533         {
534                 std::vector<QLine*>::iterator i = qlines.begin();
535                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",(*i)->nick,(*i)->source,(*i)->duration);
536                 qlines.erase(i);
537         }
538
539 }
540
541 // applies lines, removing clients and changing nicks etc as applicable
542
543 void XLineManager::ApplyLines()
544 {
545         int What = 0; // XXX remove me
546         char reason[MAXBUF];
547
548         XLine* check = NULL;
549         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
550         {
551                 User* u = (User*)(*u2);
552
553                 if (elines.size())
554                 {
555                         // ignore people matching exempts
556                         if (matches_exception(u))
557                                 continue;
558                 }
559                 if ((What & APPLY_GLINES) && (glines.size()))
560                 {
561                         if ((check = matches_gline(u)))
562                         {
563                                 snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);
564                                 if (*ServerInstance->Config->MoronBanner)
565                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
566                                 if (ServerInstance->Config->HideBans)
567                                         User::QuitUser(ServerInstance, u, "G-Lined", reason);
568                                 else
569                                         User::QuitUser(ServerInstance, u, reason);
570                         }
571                 }
572                 if ((What & APPLY_KLINES) && (klines.size()))
573                 {
574                         if ((check = matches_kline(u)))
575                         {
576                                 snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);
577                                 if (*ServerInstance->Config->MoronBanner)
578                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
579                                 if (ServerInstance->Config->HideBans)
580                                         User::QuitUser(ServerInstance, u, "K-Lined", reason);
581                                 else
582                                         User::QuitUser(ServerInstance, u, reason);
583                         }
584                 }
585                 if ((What & APPLY_QLINES) && (qlines.size()))
586                 {
587                         if ((check = matches_qline(u->nick)))
588                         {
589                                 snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);
590                                 if (*ServerInstance->Config->MoronBanner)
591                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
592                                 if (ServerInstance->Config->HideBans)
593                                         User::QuitUser(ServerInstance, u, "Q-Lined", reason);
594                                 else
595                                         User::QuitUser(ServerInstance, u, reason);
596                         }
597                 }
598                 if ((What & APPLY_ZLINES) && (zlines.size()))
599                 {
600                         if ((check = matches_zline(u)))
601                         {
602                                 snprintf(reason,MAXBUF,"Z-Lined: %s", check->reason);
603                                 if (*ServerInstance->Config->MoronBanner)
604                                         u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
605                                 if (ServerInstance->Config->HideBans)
606                                         User::QuitUser(ServerInstance, u, "Z-Lined", reason);
607                                 else
608                                         User::QuitUser(ServerInstance, u, reason);
609                         }
610                 }
611         }
612 }
613
614 void XLineManager::stats_k(User* user, string_list &results)
615 {
616         std::string sn = ServerInstance->Config->ServerName;
617         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
618                 results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
619 }
620
621 void XLineManager::stats_g(User* user, string_list &results)
622 {
623         std::string sn = ServerInstance->Config->ServerName;
624         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
625                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
626 }
627
628 void XLineManager::stats_q(User* user, string_list &results)
629 {
630         std::string sn = ServerInstance->Config->ServerName;
631         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
632                 results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
633 }
634
635 void XLineManager::stats_z(User* user, string_list &results)
636 {
637         std::string sn = ServerInstance->Config->ServerName;
638         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
639                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
640 }
641
642 void XLineManager::stats_e(User* user, string_list &results)
643 {
644         std::string sn = ServerInstance->Config->ServerName;
645         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
646                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
647 }
648
649 XLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)
650 {
651 }
652
653
654
655 bool KLine::Matches(User *u)
656 {
657         if ((match(u->ident, this->identmask)))
658         {
659                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
660                 {
661                         return true;
662                 }
663         }
664
665         return false;
666 }
667
668 bool GLine::Matches(User *u)
669 {
670         if ((match(u->ident, this->identmask)))
671         {
672                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
673                 {
674                         return true;
675                 }
676         }
677
678         return false;
679 }
680
681 bool ELine::Matches(User *u)
682 {
683         if ((match(u->ident, this->identmask)))
684         {
685                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
686                 {
687                         return true;
688                 }
689         }
690
691         return false;
692 }
693
694 bool ZLine::Matches(User *u)
695 {
696         if (match(u->GetIPString(), this->ipaddr, true))
697                 return true;
698         else
699                 return false;
700 }
701
702 bool QLine::Matches(User *u)
703 {
704         if (match(user->nick, this->nick))
705                 return true;
706
707         return false;
708 }