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