Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / m_gline.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_gline.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "client.h"
91 #include "gline.h"
92 #include "hash.h"
93 #include "ircd.h"
94 #include "ircd_reply.h"
95 #include "ircd_string.h"
96 #include "match.h"
97 #include "msg.h"
98 #include "numeric.h"
99 #include "numnicks.h"
100 #include "s_conf.h"
101 #include "s_misc.h"
102 #include "send.h"
103 #include "support.h"
104
105 #include <assert.h>
106 #include <stdlib.h>
107 #include <string.h>
108
109 /*
110  * ms_gline - server message handler
111  *
112  * parv[0] = Send prefix
113  *
114  * From server:
115  *
116  * parv[1] = Target: server numeric
117  * parv[2] = [+|-]<G-line mask>
118  * parv[3] = Expiration offset
119  * parv[4] = Comment
120  *
121  * From client:
122  *
123  * parv[1] = [+|-]<G-line mask>
124  * parv[2] = Expiration offset
125  * parv[3] = Comment
126  *
127  */
128 int ms_gline(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
129 {
130   struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
131   struct Gline*  gline;
132   struct Gline*  prev;
133   char*          user;
134   char*          host;
135   int            active;
136   int            ip_mask;
137   int            gtype = 0;
138   time_t         expire = 0;
139
140   /*
141    * Remove expired G-lines
142    */
143   gline_remove_expired(TStime());
144 #ifdef BADCHAN
145   /*
146    * Remove expired bad channels
147    */
148   bad_channel_remove_expired(TStime());
149 #endif
150
151   if (IsServer(cptr)) {
152     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
153       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
154         return need_more_params(sptr, "GLINE");
155
156       if (*parv[2] == '-') /* add mode or delete mode? */
157         active = 0;
158       else
159         active = 1;
160
161       if (*parv[2] == '+' || *parv[2] == '-')
162         parv[2]++; /* step past mode indicator */
163
164       /*
165        * forward the message appropriately
166        */
167       if (0 == ircd_strcmp(parv[1], "*")) {
168         /*
169          * global!
170          */
171         sendto_serv_butone(cptr,
172                      active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
173                      NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
174       }
175       else if ((
176 #if 1
177           /*
178            * REMOVE THIS after all servers upgraded to 2.10.01 and
179            * Uworld uses a numeric too
180            */
181           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
182           (strlen(parv[1]) == 1 &&
183 #endif
184           !(acptr = FindNServer(parv[1]))))
185         return 0;               /* no such server/user exists; forget it */
186       else
187 #if 1
188 /*
189  * REMOVE THIS after all servers upgraded to 2.10.01 and
190  * Uworld uses a numeric too
191  */
192       if (IsServer(acptr) || !MyConnect(acptr))
193 #endif
194       {
195         /* single destination */
196         sendto_one(acptr,
197                active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
198                NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
199         return 0;               /* only the intended  destination
200                                    should add this gline */
201       }
202
203       if (!(host = strchr(parv[2], '@'))) {
204         /*
205          * convert user@host no @'s; assume username is '*'
206          */
207         user = "*";     
208         host = parv[2];
209       }
210       else {
211         user = parv[2];
212         *(host++) = '\0';       /* break up string at the '@' */
213       }
214       ip_mask = check_if_ipmask(host);  /* Store this boolean */
215 #ifdef BADCHAN
216       if ('#' == *host || '&' == *host || '+' == *host)
217          gtype = 1;                /* BAD CHANNEL GLINE */
218 #endif
219       for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
220            gline = gline->next)
221       {
222         if (0 == ircd_strcmp(gline->name, user) &&
223             0 == ircd_strcmp(gline->host, host))
224           break;
225         prev = gline;
226       }
227
228       if (!active && gline)
229       {
230         /*
231          * removing the gline, notify opers
232          */
233         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
234             gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
235
236 #ifdef GPATH
237        write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
238            TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
239             gline->host);
240 #endif /* GPATH */
241
242         free_gline(gline, prev);        /* remove the gline */
243       }
244       else if (active)
245       {                         /* must be adding a gline */
246         expire = atoi(parv[3]) + TStime();      /* expire time? */
247         if (gline && gline->expire < expire)
248         {                       /* new expire time? */
249           /* yes, notify the opers */
250           sendto_op_mask(SNO_GLINE,
251              "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
252              parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
253              expire);
254 #ifdef GPATH
255           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
256               "on %s for %s@%s to " TIME_T_FMT "\n",
257               TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
258               gline->name, gline->host, expire);
259 #endif /* GPATH */
260
261           gline->expire = expire;       /* reset the expire time */
262         }
263         else if (!gline)
264         {                       /* create gline */
265           for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
266             if (!mmatch(gline->name, user) &&
267                 (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
268                 !mmatch(gline->host, host))
269               return 0;         /* found an existing G-line that matches */
270
271           /* add the line: */
272           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
273         }
274       }
275     }
276   }
277   else if (parc < 2 || *parv[1] == '\0')
278   {
279     /* Not enough args and a user; list glines */
280     for (gline = GlobalGlineList; gline; gline = gline->next)
281       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
282           gline->name, gline->host, gline->expire, gline->reason,
283           GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
284           " (Inactive)");
285     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
286   }
287   else
288   {
289     int priv;
290
291 #ifdef LOCOP_LGLINE
292     priv = IsAnOper(cptr);
293 #else
294     priv = IsOper(cptr);
295 #endif
296
297     if (priv)
298     {                           /* non-oper not permitted to change things */
299       if (*parv[1] == '-')
300       {                         /* oper wants to deactivate the gline */
301         active = 0;
302         parv[1]++;
303       }
304       else if (*parv[1] == '+')
305       {                         /* oper wants to activate inactive gline */
306         active = 1;
307         parv[1]++;
308       }
309       else
310         active = -1;
311
312       if (parc > 2)
313         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
314                                                    expire TS */
315     }
316     else
317       active = -1;
318
319     if (!(host = strchr(parv[1], '@')))
320     {
321       user = "*";               /* no @'s; assume username is '*' */
322       host = parv[1];
323     }
324     else
325     {
326       user = parv[1];
327       *(host++) = '\0';         /* break up string at the '@' */
328     }
329     ip_mask = check_if_ipmask(host);    /* Store this boolean */
330 #ifdef BADCHAN
331     if ('#' == *host || '&' == *host || '+' == *host)
332 #ifndef LOCAL_BADCHAN
333      return 0;
334 #else
335      gtype = 1;  /* BAD CHANNEL */
336 #endif
337 #endif
338
339     for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
340          gline = gline->next)
341     {
342       if (!mmatch(gline->name, user) &&
343           (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
344           !mmatch(gline->host, host))
345         break;
346       prev = gline;
347     }
348
349     if (!gline)
350     {
351 #ifdef OPER_LGLINE
352       if (priv && active && expire > CurrentTime)
353       {
354         /* Add local G-line */
355         if (parc < 4 || !strchr(parv[3], ' '))
356           return need_more_params(sptr, "GLINE");
357
358         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
359       }
360       else
361 #endif
362         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
363             host);
364
365       return 0;
366     }
367
368     if (expire <= gline->expire)
369       expire = 0;
370
371     if ((active == -1 ||
372         (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
373         expire == 0)
374     {
375       /* oper wants a list of one gline only */
376       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
377           gline->host, gline->expire, gline->reason,
378           GlineIsActive(gline) ? "" : " (Inactive)");
379       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
380       return 0;
381     }
382
383     if (active != -1 &&
384         (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
385     {
386       if (active)               /* reset activation on gline */
387         SetActive(gline);
388 #ifdef OPER_LGLINE
389       else if (GlineIsLocal(gline))
390       {
391         /* Remove local G-line */
392         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
393             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
394 #ifdef GPATH
395         write_log(GPATH, "# " TIME_T_FMT
396             " %s!%s@%s removed local %s for %s@%s\n",
397             TStime(), parv[0], cptr->user->username, cptr->user->host,
398             gtype ? "BADCHAN" : "GLINE",
399             gline->name, gline->host);
400 #endif /* GPATH */
401         free_gline(gline, prev);        /* remove the gline */
402         return 0;
403       }
404 #endif
405       else
406         ClearActive(gline);
407     }
408     else
409       active = -1;              /* for later sendto_ops and logging functions */
410
411     if (expire)
412       gline->expire = expire;   /* reset expiration time */
413
414     /* inform the operators what's up */
415     if (active != -1)
416     {                           /* changing the activation */
417        sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
418           "%s %sactivating %s for %s@%s and "
419           "resetting expiration time to " TIME_T_FMT,
420           parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
421           gline->name, gline->host, gline->expire);
422 #ifdef GPATH
423       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
424           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
425           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
426           TStime(), parv[0], cptr->user->username, cptr->user->host,
427           active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
428           gline->host, gline->expire);
429 #endif /* GPATH */
430
431     }
432     else if (expire)
433     {                           /* changing only the expiration */
434       sendto_op_mask(SNO_GLINE,
435           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
436           parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
437           gline->expire);
438 #ifdef GPATH
439       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
440           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
441           cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
442           gline->name, gline->host, gline->expire);
443 #endif /* GPATH */
444     }
445   }
446   return 0;
447 }
448
449 /*
450  * mo_gline - oper message handler
451  *
452  * parv[0] = Send prefix
453  *
454  * From server:
455  *
456  * parv[1] = Target: server numeric
457  * parv[2] = [+|-]<G-line mask>
458  * parv[3] = Expiration offset
459  * parv[4] = Comment
460  *
461  * From client:
462  *
463  * parv[1] = [+|-]<G-line mask>
464  * parv[2] = Expiration offset
465  * parv[3] = Comment
466  *
467  */
468 int mo_gline(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
469 {
470   struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
471   struct Gline*  gline;
472   struct Gline*  prev;
473   char*          user;
474   char*          host;
475   int            active;
476   int            ip_mask;
477   int            gtype = 0;
478   time_t         expire = 0;
479
480   /*
481    * Remove expired G-lines
482    */
483   gline_remove_expired(TStime());
484 #ifdef BADCHAN
485   /*
486    * Remove expired bad channels
487    */
488   bad_channel_remove_expired(TStime());
489 #endif
490
491   if (IsServer(cptr)) {
492     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
493       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
494         return need_more_params(sptr, "GLINE");
495
496       if (*parv[2] == '-') /* add mode or delete mode? */
497         active = 0;
498       else
499         active = 1;
500
501       if (*parv[2] == '+' || *parv[2] == '-')
502         parv[2]++; /* step past mode indicator */
503
504       /*
505        * forward the message appropriately
506        */
507       if (0 == ircd_strcmp(parv[1], "*")) {
508         /*
509          * global!
510          */
511         sendto_serv_butone(cptr,
512                      active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
513                      NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
514       }
515       else if ((
516 #if 1
517           /*
518            * REMOVE THIS after all servers upgraded to 2.10.01 and
519            * Uworld uses a numeric too
520            */
521           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
522           (strlen(parv[1]) == 1 &&
523 #endif
524           !(acptr = FindNServer(parv[1]))))
525         return 0;               /* no such server/user exists; forget it */
526       else
527 #if 1
528 /*
529  * REMOVE THIS after all servers upgraded to 2.10.01 and
530  * Uworld uses a numeric too
531  */
532       if (IsServer(acptr) || !MyConnect(acptr))
533 #endif
534       {
535         /* single destination */
536         sendto_one(acptr,
537                active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
538                NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
539         return 0;               /* only the intended  destination
540                                    should add this gline */
541       }
542
543       if (!(host = strchr(parv[2], '@'))) {
544         /*
545          * convert user@host no @'s; assume username is '*'
546          */
547         user = "*";     
548         host = parv[2];
549       }
550       else {
551         user = parv[2];
552         *(host++) = '\0';       /* break up string at the '@' */
553       }
554       ip_mask = check_if_ipmask(host);  /* Store this boolean */
555 #ifdef BADCHAN
556       if ('#' == *host || '&' == *host || '+' == *host)
557          gtype = 1;                /* BAD CHANNEL GLINE */
558 #endif
559       for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
560            gline = gline->next)
561       {
562         if (0 == ircd_strcmp(gline->name, user) &&
563             0 == ircd_strcmp(gline->host, host))
564           break;
565         prev = gline;
566       }
567
568       if (!active && gline)
569       {
570         /*
571          * removing the gline, notify opers
572          */
573         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
574             gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
575
576 #ifdef GPATH
577        write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
578            TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
579             gline->host);
580 #endif /* GPATH */
581
582         free_gline(gline, prev);        /* remove the gline */
583       }
584       else if (active)
585       {                         /* must be adding a gline */
586         expire = atoi(parv[3]) + TStime();      /* expire time? */
587         if (gline && gline->expire < expire)
588         {                       /* new expire time? */
589           /* yes, notify the opers */
590           sendto_op_mask(SNO_GLINE,
591              "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
592              parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
593              expire);
594 #ifdef GPATH
595           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
596               "on %s for %s@%s to " TIME_T_FMT "\n",
597               TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
598               gline->name, gline->host, expire);
599 #endif /* GPATH */
600
601           gline->expire = expire;       /* reset the expire time */
602         }
603         else if (!gline)
604         {                       /* create gline */
605           for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
606             if (!mmatch(gline->name, user) &&
607                 (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
608                 !mmatch(gline->host, host))
609               return 0;         /* found an existing G-line that matches */
610
611           /* add the line: */
612           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
613         }
614       }
615     }
616   }
617   else if (parc < 2 || *parv[1] == '\0')
618   {
619     /* Not enough args and a user; list glines */
620     for (gline = GlobalGlineList; gline; gline = gline->next)
621       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
622           gline->name, gline->host, gline->expire, gline->reason,
623           GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
624           " (Inactive)");
625     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
626   }
627   else
628   {
629     int priv;
630
631 #ifdef LOCOP_LGLINE
632     priv = IsAnOper(cptr);
633 #else
634     priv = IsOper(cptr);
635 #endif
636
637     if (priv)
638     {                           /* non-oper not permitted to change things */
639       if (*parv[1] == '-')
640       {                         /* oper wants to deactivate the gline */
641         active = 0;
642         parv[1]++;
643       }
644       else if (*parv[1] == '+')
645       {                         /* oper wants to activate inactive gline */
646         active = 1;
647         parv[1]++;
648       }
649       else
650         active = -1;
651
652       if (parc > 2)
653         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
654                                                    expire TS */
655     }
656     else
657       active = -1;
658
659     if (!(host = strchr(parv[1], '@')))
660     {
661       user = "*";               /* no @'s; assume username is '*' */
662       host = parv[1];
663     }
664     else
665     {
666       user = parv[1];
667       *(host++) = '\0';         /* break up string at the '@' */
668     }
669     ip_mask = check_if_ipmask(host);    /* Store this boolean */
670 #ifdef BADCHAN
671     if ('#' == *host || '&' == *host || '+' == *host)
672 #ifndef LOCAL_BADCHAN
673      return 0;
674 #else
675      gtype = 1;  /* BAD CHANNEL */
676 #endif
677 #endif
678
679     for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
680          gline = gline->next)
681     {
682       if (!mmatch(gline->name, user) &&
683           (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
684           !mmatch(gline->host, host))
685         break;
686       prev = gline;
687     }
688
689     if (!gline)
690     {
691 #ifdef OPER_LGLINE
692       if (priv && active && expire > CurrentTime)
693       {
694         /* Add local G-line */
695         if (parc < 4 || !strchr(parv[3], ' '))
696           return need_more_params(sptr, "GLINE");
697
698         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
699       }
700       else
701 #endif
702         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
703             host);
704
705       return 0;
706     }
707
708     if (expire <= gline->expire)
709       expire = 0;
710
711     if ((active == -1 ||
712         (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
713         expire == 0)
714     {
715       /* oper wants a list of one gline only */
716       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
717           gline->host, gline->expire, gline->reason,
718           GlineIsActive(gline) ? "" : " (Inactive)");
719       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
720       return 0;
721     }
722
723     if (active != -1 &&
724         (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
725     {
726       if (active)               /* reset activation on gline */
727         SetActive(gline);
728 #ifdef OPER_LGLINE
729       else if (GlineIsLocal(gline))
730       {
731         /* Remove local G-line */
732         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
733             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
734 #ifdef GPATH
735         write_log(GPATH, "# " TIME_T_FMT
736             " %s!%s@%s removed local %s for %s@%s\n",
737             TStime(), parv[0], cptr->user->username, cptr->user->host,
738             gtype ? "BADCHAN" : "GLINE",
739             gline->name, gline->host);
740 #endif /* GPATH */
741         free_gline(gline, prev);        /* remove the gline */
742         return 0;
743       }
744 #endif
745       else
746         ClearActive(gline);
747     }
748     else
749       active = -1;              /* for later sendto_ops and logging functions */
750
751     if (expire)
752       gline->expire = expire;   /* reset expiration time */
753
754     /* inform the operators what's up */
755     if (active != -1)
756     {                           /* changing the activation */
757        sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
758           "%s %sactivating %s for %s@%s and "
759           "resetting expiration time to " TIME_T_FMT,
760           parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
761           gline->name, gline->host, gline->expire);
762 #ifdef GPATH
763       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
764           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
765           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
766           TStime(), parv[0], cptr->user->username, cptr->user->host,
767           active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
768           gline->host, gline->expire);
769 #endif /* GPATH */
770
771     }
772     else if (expire)
773     {                           /* changing only the expiration */
774       sendto_op_mask(SNO_GLINE,
775           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
776           parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
777           gline->expire);
778 #ifdef GPATH
779       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
780           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
781           cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
782           gline->name, gline->host, gline->expire);
783 #endif /* GPATH */
784     }
785   }
786   return 0;
787 }
788
789
790 #if 0
791 /*
792  * m_gline
793  *
794  * parv[0] = Send prefix
795  *
796  * From server:
797  *
798  * parv[1] = Target: server numeric
799  * parv[2] = [+|-]<G-line mask>
800  * parv[3] = Expiration offset
801  * parv[4] = Comment
802  *
803  * From client:
804  *
805  * parv[1] = [+|-]<G-line mask>
806  * parv[2] = Expiration offset
807  * parv[3] = Comment
808  *
809  */
810 int m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
811 {
812   struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
813   struct Gline*  gline;
814   struct Gline*  prev;
815   char*          user;
816   char*          host;
817   int            active;
818   int            ip_mask;
819   int            gtype = 0;
820   time_t         expire = 0;
821
822   /*
823    * Remove expired G-lines
824    */
825   gline_remove_expired(TStime());
826 #ifdef BADCHAN
827   /*
828    * Remove expired bad channels
829    */
830   bad_channel_remove_expired(TStime());
831 #endif
832
833   if (IsServer(cptr)) {
834     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
835       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
836         return need_more_params(sptr, "GLINE");
837
838       if (*parv[2] == '-') /* add mode or delete mode? */
839         active = 0;
840       else
841         active = 1;
842
843       if (*parv[2] == '+' || *parv[2] == '-')
844         parv[2]++; /* step past mode indicator */
845
846       /*
847        * forward the message appropriately
848        */
849       if (0 == ircd_strcmp(parv[1], "*")) {
850         /*
851          * global!
852          */
853         sendto_serv_butone(cptr,
854                      active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
855                      NumServ(cptr), parv[1], parv[2], parv[3], parv[4]);
856       }
857       else if ((
858 #if 1
859           /*
860            * REMOVE THIS after all servers upgraded to 2.10.01 and
861            * Uworld uses a numeric too
862            */
863           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
864           (strlen(parv[1]) == 1 &&
865 #endif
866           !(acptr = FindNServer(parv[1]))))
867         return 0;               /* no such server/user exists; forget it */
868       else
869 #if 1
870 /*
871  * REMOVE THIS after all servers upgraded to 2.10.01 and
872  * Uworld uses a numeric too
873  */
874       if (IsServer(acptr) || !MyConnect(acptr))
875 #endif
876       {
877         /* single destination */
878         sendto_one(acptr,
879                active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
880                NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
881         return 0;               /* only the intended  destination
882                                    should add this gline */
883       }
884
885       if (!(host = strchr(parv[2], '@'))) {
886         /*
887          * convert user@host no @'s; assume username is '*'
888          */
889         user = "*";     
890         host = parv[2];
891       }
892       else {
893         user = parv[2];
894         *(host++) = '\0';       /* break up string at the '@' */
895       }
896       ip_mask = check_if_ipmask(host);  /* Store this boolean */
897 #ifdef BADCHAN
898       if ('#' == *host || '&' == *host || '+' == *host)
899          gtype = 1;                /* BAD CHANNEL GLINE */
900 #endif
901       for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
902            gline = gline->next)
903       {
904         if (0 == ircd_strcmp(gline->name, user) &&
905             0 == ircd_strcmp(gline->host, host))
906           break;
907         prev = gline;
908       }
909
910       if (!active && gline)
911       {
912         /*
913          * removing the gline, notify opers
914          */
915         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
916             gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
917
918 #ifdef GPATH
919        write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
920            TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
921             gline->host);
922 #endif /* GPATH */
923
924         free_gline(gline, prev);        /* remove the gline */
925       }
926       else if (active)
927       {                         /* must be adding a gline */
928         expire = atoi(parv[3]) + TStime();      /* expire time? */
929         if (gline && gline->expire < expire)
930         {                       /* new expire time? */
931           /* yes, notify the opers */
932           sendto_op_mask(SNO_GLINE,
933              "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
934              parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
935              expire);
936 #ifdef GPATH
937           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
938               "on %s for %s@%s to " TIME_T_FMT "\n",
939               TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
940               gline->name, gline->host, expire);
941 #endif /* GPATH */
942
943           gline->expire = expire;       /* reset the expire time */
944         }
945         else if (!gline)
946         {                       /* create gline */
947           for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
948             if (!mmatch(gline->name, user) &&
949                 (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
950                 !mmatch(gline->host, host))
951               return 0;         /* found an existing G-line that matches */
952
953           /* add the line: */
954           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
955         }
956       }
957     }
958   }
959   else if (parc < 2 || *parv[1] == '\0')
960   {
961     /* Not enough args and a user; list glines */
962     for (gline = GlobalGlineList; gline; gline = gline->next)
963       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
964           gline->name, gline->host, gline->expire, gline->reason,
965           GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
966           " (Inactive)");
967     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
968   }
969   else
970   {
971     int priv;
972
973 #ifdef LOCOP_LGLINE
974     priv = IsAnOper(cptr);
975 #else
976     priv = IsOper(cptr);
977 #endif
978
979     if (priv)
980     {                           /* non-oper not permitted to change things */
981       if (*parv[1] == '-')
982       {                         /* oper wants to deactivate the gline */
983         active = 0;
984         parv[1]++;
985       }
986       else if (*parv[1] == '+')
987       {                         /* oper wants to activate inactive gline */
988         active = 1;
989         parv[1]++;
990       }
991       else
992         active = -1;
993
994       if (parc > 2)
995         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
996                                                    expire TS */
997     }
998     else
999       active = -1;
1000
1001     if (!(host = strchr(parv[1], '@')))
1002     {
1003       user = "*";               /* no @'s; assume username is '*' */
1004       host = parv[1];
1005     }
1006     else
1007     {
1008       user = parv[1];
1009       *(host++) = '\0';         /* break up string at the '@' */
1010     }
1011     ip_mask = check_if_ipmask(host);    /* Store this boolean */
1012 #ifdef BADCHAN
1013     if ('#' == *host || '&' == *host || '+' == *host)
1014 #ifndef LOCAL_BADCHAN
1015      return 0;
1016 #else
1017      gtype = 1;  /* BAD CHANNEL */
1018 #endif
1019 #endif
1020
1021     for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
1022          gline = gline->next)
1023     {
1024       if (!mmatch(gline->name, user) &&
1025           (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
1026           !mmatch(gline->host, host))
1027         break;
1028       prev = gline;
1029     }
1030
1031     if (!gline)
1032     {
1033 #ifdef OPER_LGLINE
1034       if (priv && active && expire > CurrentTime)
1035       {
1036         /* Add local G-line */
1037         if (parc < 4 || !strchr(parv[3], ' '))
1038           return need_more_params(sptr, "GLINE");
1039
1040         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
1041       }
1042       else
1043 #endif
1044         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
1045             host);
1046
1047       return 0;
1048     }
1049
1050     if (expire <= gline->expire)
1051       expire = 0;
1052
1053     if ((active == -1 ||
1054         (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
1055         expire == 0)
1056     {
1057       /* oper wants a list of one gline only */
1058       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
1059           gline->host, gline->expire, gline->reason,
1060           GlineIsActive(gline) ? "" : " (Inactive)");
1061       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1062       return 0;
1063     }
1064
1065     if (active != -1 &&
1066         (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
1067     {
1068       if (active)               /* reset activation on gline */
1069         SetActive(gline);
1070 #ifdef OPER_LGLINE
1071       else if (GlineIsLocal(gline))
1072       {
1073         /* Remove local G-line */
1074         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
1075             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
1076 #ifdef GPATH
1077         write_log(GPATH, "# " TIME_T_FMT
1078             " %s!%s@%s removed local %s for %s@%s\n",
1079             TStime(), parv[0], cptr->user->username, cptr->user->host,
1080             gtype ? "BADCHAN" : "GLINE",
1081             gline->name, gline->host);
1082 #endif /* GPATH */
1083         free_gline(gline, prev);        /* remove the gline */
1084         return 0;
1085       }
1086 #endif
1087       else
1088         ClearActive(gline);
1089     }
1090     else
1091       active = -1;              /* for later sendto_ops and logging functions */
1092
1093     if (expire)
1094       gline->expire = expire;   /* reset expiration time */
1095
1096     /* inform the operators what's up */
1097     if (active != -1)
1098     {                           /* changing the activation */
1099        sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
1100           "%s %sactivating %s for %s@%s and "
1101           "resetting expiration time to " TIME_T_FMT,
1102           parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
1103           gline->name, gline->host, gline->expire);
1104 #ifdef GPATH
1105       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
1106           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
1107           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
1108           TStime(), parv[0], cptr->user->username, cptr->user->host,
1109           active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
1110           gline->host, gline->expire);
1111 #endif /* GPATH */
1112
1113     }
1114     else if (expire)
1115     {                           /* changing only the expiration */
1116       sendto_op_mask(SNO_GLINE,
1117           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1118           parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
1119           gline->expire);
1120 #ifdef GPATH
1121       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
1122           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
1123           cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
1124           gline->name, gline->host, gline->expire);
1125 #endif /* GPATH */
1126     }
1127   }
1128   return 0;
1129 }
1130
1131 #endif /* 0 */
1132