Author: Ghostwolf <foxxe@trms.com>
[ircu2.10.12-pk.git] / ircd / gline.c
1 /*
2  * IRC - Internet Relay Chat, ircd/gline.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Finland
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id$
21  */
22 #include "gline.h"
23 #include "client.h"
24 #include "ircd.h"
25 #include "ircd_alloc.h"
26 #include "ircd_reply.h"
27 #include "ircd_string.h"
28 #include "match.h"
29 #include "numeric.h"
30 #include "s_bsd.h"
31 #include "s_misc.h"
32 #include "send.h"
33 #include "struct.h"
34 #include "support.h"
35 #include "msg.h"
36 #include "numnicks.h"
37 #include "numeric.h"
38 #include "sys.h"    /* FALSE bleah */
39
40 #include <assert.h>
41 #include <string.h>
42
43 struct Gline* GlobalGlineList  = 0;
44 struct Gline* BadChanGlineList = 0;
45
46 static void
47 canon_userhost(char *userhost, char **user_p, char **host_p, char *def_user)
48 {
49   char *tmp;
50
51   if (!(tmp = strchr(userhost, '@'))) {
52     *user_p = def_user;
53     *host_p = userhost;
54   } else {
55     *user_p = userhost;
56     *(tmp++) = '\0';
57     *host_p = tmp;
58   }
59 }
60
61 static struct Gline *
62 make_gline(char *userhost, char *reason, time_t expire, time_t lastmod,
63            unsigned int flags)
64 {
65   struct Gline *gline;
66   char *user, *host;
67
68   gline = (struct Gline *)MyMalloc(sizeof(struct Gline)); /* alloc memory */
69   assert(0 != gline);
70
71   gline->gl_expire = expire; /* initialize gline... */
72   gline->gl_lastmod = lastmod;
73   gline->gl_flags = flags & GLINE_MASK;
74
75   if (flags & GLINE_BADCHAN) { /* set a BADCHAN gline */
76     DupString(gline->gl_user, userhost); /* first, remember channel */
77     gline->gl_host = 0;
78
79     gline->gl_next = BadChanGlineList; /* then link it into list */
80     gline->gl_prev_p = &BadChanGlineList;
81     if (BadChanGlineList)
82       BadChanGlineList->gl_prev_p = &gline->gl_next;
83     BadChanGlineList = gline;
84   } else {
85     canon_userhost(userhost, &user, &host, "*"); /* find user and host */
86
87     DupString(gline->gl_user, user); /* remember them... */
88     DupString(gline->gl_host, host);
89
90     if (check_if_ipmask(host)) /* mark if it's an IP mask */
91       gline->gl_flags |= GLINE_IPMASK;
92
93     gline->gl_next = GlobalGlineList; /* then link it into list */
94     gline->gl_prev_p = &GlobalGlineList;
95     if (GlobalGlineList)
96       GlobalGlineList->gl_prev_p = &gline->gl_next;
97     GlobalGlineList = gline;
98   }
99
100   return gline;
101 }
102
103 static int
104 do_gline(struct Client *cptr, struct Client *sptr, struct Gline *gline)
105 {
106   struct Client *acptr;
107   int fd, retval = 0, tval;
108
109   if (!GlineIsActive(gline)) /* no action taken on inactive glines */
110     return 0;
111
112   for (fd = HighestFd; fd >= 0; --fd) {
113     /*
114      * get the users!
115      */
116     if ((acptr = LocalClientArray[fd])) {
117       if (!acptr->user)
118         continue;
119
120       if ((GlineIsIpMask(gline) ? match(gline->gl_host, acptr->sock_ip) :
121            match(gline->gl_host, acptr->sockhost)) == 0 &&
122           (!acptr->user->username ||
123            match(gline->gl_user, acptr->user->username) == 0)) {
124         /* ok, here's one that got G-lined */
125         sendto_one(acptr, ":%s %d %s :*** %s.", me.name, ERR_YOUREBANNEDCREEP,
126                    acptr->name, gline->gl_reason);
127
128         /* let the ops know about it */
129         sendto_op_mask(SNO_GLINE, "G-line active for %s",
130                        get_client_name(acptr, FALSE));
131
132         /* and get rid of him */
133         if ((tval = exit_client_msg(cptr, acptr, &me, "G-lined (%s)",
134                                     gline->gl_reason)))
135           retval = tval; /* retain killed status */
136       }
137     }
138   }
139
140   return retval;
141 }
142
143 static void
144 propagate_gline(struct Client *cptr, struct Client *sptr, struct Gline *gline)
145 {
146   if (GlineIsLocal(gline)) /* don't propagate local glines */
147     return;
148
149   if (IsUser(sptr)) { /* select appropriate source */
150     assert(0 != gline->gl_lastmod);
151     sendto_serv_butone(cptr, "%s%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT " "
152                        TIME_T_FMT " :%s", NumNick(sptr),
153                        GlineIsActive(gline) ? '+' : '-', gline->gl_user,
154                        GlineIsBadChan(gline) ? "" : "@",
155                        GlineIsBadChan(gline) ? "" : gline->gl_host,
156                        gline->gl_expire - TStime(), gline->gl_lastmod,
157                        gline->gl_reason);
158   } else {
159     if (gline->gl_lastmod)
160       sendto_serv_butone(cptr, "%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT " "
161                          TIME_T_FMT " :%s", NumServ(sptr),
162                          GlineIsActive(gline) ? '+' : '-', gline->gl_user,
163                          GlineIsBadChan(gline) ? "" : "@",
164                          GlineIsBadChan(gline) ? "" : gline->gl_host,
165                          gline->gl_expire - TStime(), gline->gl_lastmod,
166                          gline->gl_reason);
167     else
168       sendto_serv_butone(cptr, "%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT
169                          " :%s", NumServ(sptr),
170                          GlineIsActive(gline) ? '+' : '-', gline->gl_user,
171                          GlineIsBadChan(gline) ? "" : "@",
172                          GlineIsBadChan(gline) ? "" : gline->gl_host,
173                          gline->gl_expire - TStime(), gline->gl_reason);
174   }
175 }
176
177 int 
178 gline_add(struct Client *cptr, struct Client *sptr, char *userhost,
179           char *reason, time_t expire, time_t lastmod, unsigned int flags)
180 {
181   struct Gline *agline;
182
183   assert(0 != userhost);
184   assert(0 != reason);
185
186   /*
187    * You cannot set a negative (or zero) expire time, nor can you set an
188    * expiration time for greater than GLINE_MAX_EXPIRE.
189    */
190   if (!(flags & GLINE_FORCE) && (expire <= 0 || expire > GLINE_MAX_EXPIRE)) {
191     if (!IsServer(sptr) && MyConnect(sptr))
192       send_error_to_client(sptr, ERR_BADEXPIRE, expire);
193     return 0;
194   }
195
196   expire += TStime(); /* convert from lifetime to timestamp */
197
198   /* NO_OLD_GLINE allows *@#channel to work correctly */
199 #ifdef BADCHAN
200   if (*userhost == '#' || *userhost == '&' || *userhost == '+'
201 # ifndef NO_OLD_GLINE
202       || userhost[2] == '#' || userhost[2] == '&' || userhost[2] == '+'
203 # endif /* OLD_GLINE */
204       ) {
205 # ifndef LOCAL_BADCHAN
206     if (flags & GLINE_LOCAL)
207       return 0;
208 # endif
209     flags |= GLINE_BADCHAN;
210   }
211 #endif /* BADCHAN */
212
213   /* Inform ops... */
214   sendto_op_mask(SNO_GLINE, "%s adding %s %s for %s, expiring at "
215                  TIME_T_FMT ": %s",
216                  IsServer(sptr) ? sptr->name : sptr->user->server->name,
217                  flags & GLINE_LOCAL ? "local" : "global",
218                  flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", userhost,
219                  expire, reason);
220
221 #ifdef GPATH
222   /* and log it */
223   if (IsServer(sptr))
224     write_log(GPATH, "# " TIME_T_FMT " %s adding %s %s for %s, expiring at "
225               TIME_T_FMT ": %s\n", TStime(), sptr->name,
226               flags & GLINE_LOCAL ? "local" : "global",
227               flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", userhost, expire,
228               reason);
229   else
230     write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s adding %s %s for %s, "
231               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
232               sptr->user->username, sptr->user->host,
233               flags & GLINE_LOCAL ? "local" : "global",
234               flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", userhost, expire,
235               reason);
236 #endif /* GPATH */
237
238   /* make the gline */
239   agline = make_gline(userhost, reason, expire, lastmod, flags);
240
241   propagate_gline(cptr, sptr, agline);
242
243   if (GlineIsBadChan(agline))
244     return 0;
245
246 #ifdef GPATH
247   /* this can be inserted into the conf */
248   write_log(GPATH, "%c:%s:%s:%s\n", GlineIsIpMask(agline) ? 'k' : 'K',
249             GlineHost(agline), GlineReason(agline), GlineUser(agline));
250 #endif /* GPATH */
251
252   return do_gline(cptr, sptr, agline); /* knock off users if necessary */
253 }
254
255 int
256 gline_activate(struct Client *cptr, struct Client *sptr, struct Gline *gline,
257                time_t lastmod)
258 {
259   assert(0 != gline);
260
261   gline->gl_flags |= GLINE_ACTIVE;
262   gline->gl_lastmod = lastmod;
263
264   /* Inform ops and log it */
265   sendto_op_mask(SNO_GLINE, "%s activating %s %s for %s%s%s, expiring at "
266                  TIME_T_FMT ": %s",
267                  IsServer(sptr) ? sptr->name : sptr->user->server->name,
268                  GlineIsLocal(gline) ? "local" : "global",
269                  GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
270                  gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
271                  GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
272                  gline->gl_reason);
273
274 #ifdef GPATH
275   if (IsServer(sptr))
276     write_log(GPATH, "# " TIME_T_FMT " %s activating %s %s for %s%s%s, "
277               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
278               GlineIsLocal(gline) ? "local" : "global",
279               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
280               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
281               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
282               gline->gl_reason);
283   else
284     write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s activating %s %s for "
285               "%s%s%s, expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
286               sptr->user->username, sptr->user->host,
287               GlineIsLocal(gline) ? "local" : "global",
288               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
289               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
290               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
291               gline->gl_reason);
292 #endif /* GPATH */
293
294   propagate_gline(cptr, sptr, gline);
295
296   return GlineIsBadChan(gline) ? 0 : do_gline(cptr, sptr, gline);
297 }
298
299 int
300 gline_deactivate(struct Client *cptr, struct Client *sptr, struct Gline *gline,
301                  time_t lastmod)
302 {
303   assert(0 != gline);
304
305   gline->gl_flags &= ~GLINE_ACTIVE;
306   gline->gl_lastmod = lastmod;
307
308   /* Inform ops and log it */
309   sendto_op_mask(SNO_GLINE, "%s deactivating %s %s for %s%s%s, expiring at "
310                  TIME_T_FMT ": %s",
311                  IsServer(sptr) ? sptr->name : sptr->user->server->name,
312                  GlineIsLocal(gline) ? "local" : "global",
313                  GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
314                  gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
315                  GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
316                  gline->gl_reason);
317
318 #ifdef GPATH
319   if (IsServer(sptr))
320     write_log(GPATH, "# " TIME_T_FMT " %s deactivating %s %s for %s%s%s, "
321               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
322               GlineIsLocal(gline) ? "local" : "global",
323               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
324               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
325               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
326               gline->gl_reason);
327   else
328     write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s deactivating %s %s for "
329               "%s%s%s, expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
330               sptr->user->username, sptr->user->host,
331               GlineIsLocal(gline) ? "local" : "global",
332               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
333               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
334               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
335               gline->gl_reason);
336 #endif /* GPATH */
337
338   propagate_gline(cptr, sptr, gline);
339
340   return 0;
341 }
342
343 struct Gline *
344 gline_find(char *userhost, unsigned int flags)
345 {
346   struct Gline *gline;
347   struct Gline *sgline;
348   char *user, *host, *t_uh;
349
350   if (flags & (GLINE_BADCHAN | GLINE_ANY)) {
351     for (gline = BadChanGlineList; gline; gline = sgline) {
352       sgline = gline->gl_next;
353
354       if (gline->gl_expire <= TStime())
355         gline_free(gline);
356       else if (match(gline->gl_user, userhost) == 0)
357         return gline;
358     }
359   }
360
361   if ((flags & (GLINE_BADCHAN | GLINE_ANY)) == GLINE_BADCHAN)
362     return 0;
363
364   DupString(t_uh, userhost);
365   canon_userhost(t_uh, &user, &host, 0);
366
367   for (gline = GlobalGlineList; gline; gline = sgline) {
368     sgline = gline->gl_next;
369
370     if (gline->gl_expire <= TStime())
371       gline_free(gline);
372     else if (match(gline->gl_host, host) == 0 &&
373              ((!user && ircd_strcmp(gline->gl_user, "*") == 0) ||
374               match(gline->gl_user, user) == 0))
375       break;
376   }
377
378   MyFree(t_uh);
379
380   return gline;
381 }
382
383 struct Gline *
384 gline_lookup(struct Client *cptr)
385 {
386   struct Gline *gline;
387   struct Gline *sgline;
388
389   for (gline = GlobalGlineList; gline; gline = sgline) {
390     sgline = gline->gl_next;
391
392     if (gline->gl_expire <= TStime())
393       gline_free(gline);
394     else if ((GlineIsIpMask(gline) ?
395               match(gline->gl_host, cptr->sock_ip) :
396               match(gline->gl_host, cptr->sockhost)) == 0 &&
397              match(gline->gl_user, cptr->user->username) == 0)
398       return gline;
399   }
400
401   return 0;
402 }
403
404 void
405 gline_free(struct Gline *gline)
406 {
407   assert(0 != gline);
408
409   *gline->gl_prev_p = gline->gl_next; /* squeeze this gline out */
410   if (gline->gl_next)
411     gline->gl_next->gl_prev_p = gline->gl_prev_p;
412
413   MyFree(gline->gl_user); /* free up the memory */
414   if (gline->gl_host)
415     MyFree(gline->gl_host);
416   MyFree(gline->gl_reason);
417   MyFree(gline);
418 }
419
420 void
421 gline_burst(struct Client *cptr)
422 {
423   struct Gline *gline;
424   struct Gline *sgline;
425
426   for (gline = GlobalGlineList; gline; gline = sgline) { /* all glines */
427     sgline = gline->gl_next;
428
429     if (gline->gl_expire <= TStime()) /* expire any that need expiring */
430       gline_free(gline);
431     else if (!GlineIsLocal(gline) && gline->gl_lastmod)
432       sendto_one(cptr, "%s " TOK_GLINE " * %c%s@%s " TIME_T_FMT " " TIME_T_FMT
433                  " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
434                  gline->gl_user, gline->gl_host, gline->gl_expire - TStime(),
435                  gline->gl_lastmod, gline->gl_reason);
436   }
437
438   for (gline = BadChanGlineList; gline; gline = sgline) { /* all glines */
439     sgline = gline->gl_next;
440
441     if (gline->gl_expire <= TStime()) /* expire any that need expiring */
442       gline_free(gline);
443     else if (!GlineIsLocal(gline) && gline->gl_lastmod)
444       sendto_one(cptr, "%s " TOK_GLINE " * %c%s " TIME_T_FMT " " TIME_T_FMT
445                  " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
446                  gline->gl_user, gline->gl_expire - TStime(),
447                  gline->gl_lastmod, gline->gl_reason);
448   }
449 }
450
451 int
452 gline_resend(struct Client *cptr, struct Gline *gline)
453 {
454   if (GlineIsLocal(gline) || !gline->gl_lastmod)
455     return 0;
456
457   sendto_one(cptr, "%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT " " TIME_T_FMT
458              " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
459              gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
460              GlineIsBadChan(gline) ? "" : gline->gl_host,
461              gline->gl_expire - TStime(), gline->gl_lastmod, gline->gl_reason);
462
463   return 0;
464 }
465
466 int
467 gline_list(struct Client *sptr, char *userhost)
468 {
469   struct Gline *gline;
470   struct Gline *sgline;
471
472   if (userhost) {
473     if (!(gline = gline_find(userhost, GLINE_ANY))) { /* no such gline */
474       send_error_to_client(sptr, ERR_NOSUCHGLINE, userhost);
475       return 0;
476     }
477
478     /* send gline information along */
479     sendto_one(sptr, rpl_str(RPL_GLIST), me.name, sptr->name, gline->gl_user,
480                GlineIsBadChan(gline) ? "" : "@",
481                GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
482                GlineIsLocal(gline) ? me.name : "*",
483                GlineIsActive(gline) ? '+' : '-', gline->gl_reason);
484   } else {
485     for (gline = GlobalGlineList; gline; gline = sgline) {
486       sgline = gline->gl_next;
487
488       if (gline->gl_expire <= TStime())
489         gline_free(gline);
490       else
491         sendto_one(sptr, rpl_str(RPL_GLIST), me.name, sptr->name, gline->gl_user,
492                    "@", gline->gl_host, gline->gl_expire,
493                    GlineIsLocal(gline) ? me.name : "*",
494                    GlineIsActive(gline) ? '+' : '-', gline->gl_reason);
495     }
496
497     for (gline = BadChanGlineList; gline; gline = sgline) {
498       sgline = gline->gl_next;
499
500       if (gline->gl_expire <= TStime())
501         gline_free(gline);
502       else
503         sendto_one(sptr, rpl_str(RPL_GLIST), me.name, sptr->name, gline->gl_user,
504                    "", "", gline->gl_expire,
505                    GlineIsLocal(gline) ? me.name : "*",
506                    GlineIsActive(gline) ? '+' : '-', gline->gl_reason);
507     }
508   }
509
510   /* end of gline information */
511   sendto_one(sptr, rpl_str(RPL_ENDOFGLIST), me.name, sptr->name);
512   return 0;
513 }
514
515 void
516 gline_stats(struct Client *sptr)
517 {
518   struct Gline *gline;
519   struct Gline *sgline;
520
521   for (gline = GlobalGlineList; gline; gline = sgline) {
522     sgline = gline->gl_next;
523
524     if (gline->gl_expire <= TStime())
525       gline_free(gline);
526     else
527       sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name, sptr->name, 'G',
528                  gline->gl_user, gline->gl_host, gline->gl_expire,
529                  gline->gl_reason);
530   }
531 }
532
533
534 #if 0 /* forget about it! */
535 struct Gline *make_gline(int is_ipmask, char *host, char *reason,
536                          char *name, time_t expire)
537 {
538   struct Gline *agline;
539
540 #ifdef BADCHAN
541   int gtype = 0;
542   if ('#' == *host || '&' == *host || '+' == *host)
543     gtype = 1; /* BAD CHANNEL GLINE */
544 #endif
545
546   agline = (struct Gline*) MyMalloc(sizeof(struct Gline)); /* alloc memory */
547   assert(0 != agline);
548   DupString(agline->host, host);        /* copy vital information */
549   DupString(agline->reason, reason);
550   DupString(agline->name, name);
551   agline->expire = expire;
552   agline->gflags = GLINE_ACTIVE;        /* gline is active */
553   if (is_ipmask)
554     SetGlineIsIpMask(agline);
555 #ifdef BADCHAN
556   if (gtype)
557   { 
558     agline->next = BadChanGlineList;    /* link it into the list */
559     return (BadChanGlineList = agline);
560   }
561 #endif
562   agline->next = GlobalGlineList;       /* link it into the list */
563   return (GlobalGlineList = agline);
564 }
565
566 struct Gline *find_gline(struct Client *cptr, struct Gline **pgline)
567 {
568   struct Gline* gline = GlobalGlineList;
569   struct Gline* prev = 0;
570
571   while (gline) {
572     /*
573      * look through all glines
574      */
575     if (gline->expire <= TStime()) {
576       /*
577        * handle expired glines
578        */
579       free_gline(gline, prev);
580       gline = prev ? prev->next : GlobalGlineList;
581       if (!gline)
582         break;                  /* gline == NULL means gline == NULL */
583       continue;
584     }
585
586     /* Does gline match? */
587     /* Added a check against the user's IP address as well -Kev */
588     if ((GlineIsIpMask(gline) ?
589         match(gline->host, ircd_ntoa((const char*) &cptr->ip)) :
590         match(gline->host, cptr->sockhost)) == 0 &&
591         match(gline->name, cptr->user->username) == 0) {
592       if (pgline)
593         *pgline = prev; /* If they need it, give them the previous gline
594                                    entry (probably for free_gline, below) */
595       return gline;
596     }
597
598     prev = gline;
599     gline = gline->next;
600   }
601
602   return 0;                  /* found no glines */
603 }
604
605 void free_gline(struct Gline* gline, struct Gline* prev)
606 {
607   assert(0 != gline);
608   if (prev)
609     prev->next = gline->next;   /* squeeze agline out */
610   else { 
611 #ifdef BADCHAN
612     assert(0 != gline->host);
613     if ('#' == *gline->host ||
614         '&' == *gline->host ||
615         '+' == *gline->host) {
616       BadChanGlineList = gline->next;
617     }
618     else
619 #endif
620       GlobalGlineList = gline->next;
621   }
622
623   MyFree(gline->host);  /* and free up the memory */
624   MyFree(gline->reason);
625   MyFree(gline->name);
626   MyFree(gline);
627 }
628
629 void gline_remove_expired(time_t now)
630 {
631   struct Gline* gline;
632   struct Gline* prev = 0;
633   
634   for (gline = GlobalGlineList; gline; gline = gline->next) {
635     if (gline->expire < now) {
636       free_gline(gline, prev);
637       gline = (prev) ? prev : GlobalGlineList;
638       if (!gline)
639         break;
640       continue;
641     }
642     prev = gline;
643   }
644 }
645
646 #ifdef BADCHAN
647 int bad_channel(const char* name)
648
649   struct Gline* agline = BadChanGlineList;
650
651   while (agline)
652   { 
653     if ((agline->gflags & GLINE_ACTIVE) && (agline->expire > TStime()) && 
654          !mmatch(agline->host, name)) { 
655       return 1;
656     }
657     agline = agline->next;
658   }
659   return 0;
660 }
661
662 void bad_channel_remove_expired(time_t now)
663 {
664   struct Gline* gline;
665   struct Gline* prev = 0;
666   
667   for (gline = BadChanGlineList; gline; gline = gline->next) {
668     if (gline->expire < now) {
669       free_gline(gline, prev);
670       gline = (prev) ? prev : BadChanGlineList;
671       if (!gline)
672         break;
673       continue;
674     }
675     prev = gline;
676   }
677 }
678
679 #endif
680
681
682 void add_gline(struct Client *sptr, int ip_mask, char *host, char *comment,
683                char *user, time_t expire, int local)
684 {
685   struct Client *acptr;
686   struct Gline *agline;
687   int fd;
688   int gtype = 0;
689   assert(0 != host);
690
691 #ifdef BADCHAN
692   if ('#' == *host || '&' == *host || '+' == *host)
693     gtype = 1;   /* BAD CHANNEL */
694 #endif
695
696   /* Inform ops */
697   sendto_op_mask(SNO_GLINE,
698       "%s adding %s%s for %s@%s, expiring at " TIME_T_FMT ": %s", sptr->name,
699       local ? "local " : "",
700       gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
701
702 #ifdef GPATH
703   write_log(GPATH,
704       "# " TIME_T_FMT " %s adding %s %s for %s@%s, expiring at " TIME_T_FMT
705       ": %s\n", TStime(), sptr->name, local ? "local" : "global",
706       gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
707
708   /* this can be inserted into the conf */
709   if (!gtype)
710     write_log(GPATH, "%c:%s:%s:%s\n", ip_mask ? 'k' : 'K', host, comment, 
711       user);
712 #endif /* GPATH */
713
714   agline = make_gline(ip_mask, host, comment, user, expire);
715   if (local)
716     SetGlineIsLocal(agline);
717
718 #ifdef BADCHAN
719   if (gtype)
720     return;
721 #endif
722
723   for (fd = HighestFd; fd >= 0; --fd) { 
724     /*
725      * get the users!
726      */ 
727     if ((acptr = LocalClientArray[fd])) {
728       if (!acptr->user)
729         continue;
730 #if 0
731       /*
732        * whee!! :)
733        */
734       if (!acptr->user || strlen(acptr->sockhost) > HOSTLEN ||
735           (acptr->user->username ? strlen(acptr->user->username) : 0) > HOSTLEN)
736         continue;               /* these tests right out of
737                                    find_kill for safety's sake */
738 #endif
739
740       if ((GlineIsIpMask(agline) ?  match(agline->host, acptr->sock_ip) :
741           match(agline->host, acptr->sockhost)) == 0 &&
742           (!acptr->user->username ||
743           match(agline->name, acptr->user->username) == 0))
744       {
745
746         /* ok, he was the one that got G-lined */
747         sendto_one(acptr, ":%s %d %s :*** %s.", me.name,
748             ERR_YOUREBANNEDCREEP, acptr->name, agline->reason);
749
750         /* let the ops know about my first kill */
751         sendto_op_mask(SNO_GLINE, "G-line active for %s",
752             get_client_name(acptr, FALSE));
753
754         /* and get rid of him */
755         if (sptr != acptr)
756           exit_client_msg(sptr->from, acptr, &me, "G-lined (%s)", agline->reason);
757       }
758     }
759   }
760 }
761
762 #endif /* 0 */