Author: Kev <klmitch@mit.edu>
[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] = Sender prefix
113  * parv[1] = Target: server numeric
114  * parv[2] = (+|-)<G-line mask>
115  * parv[3] = G-line lifetime
116  *
117  * From Uworld:
118  *
119  * parv[4] = Comment
120  *
121  * From somewhere else:
122  *
123  * parv[4] = Last modification time
124  * parv[5] = Comment
125  *
126  */
127 int
128 ms_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
129 {
130   struct Client *acptr = 0;
131   struct Gline *agline;
132   unsigned int flags = 0;
133   time_t expire_off, lastmod = 0;
134   char *mask = parv[2], *target = parv[1], *reason;
135
136   if (parc == 5) {
137     if (!find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
138       return need_more_params(sptr, "GLINE");
139
140     reason = parv[4];
141     flags |= GLINE_FORCE;
142   } else if (parc > 5) {
143     lastmod = atoi(parv[4]);
144     reason = parv[5];
145   } else
146     return need_more_params(sptr, "GLINE");
147
148   if (!(target[0] == '*' && target[1] == '\0')) {
149     if (!(acptr = FindNServer(target)))
150       return 0; /* no such server */
151
152     if (!IsMe(acptr)) { /* manually propagate */
153       if (IsServer(sptr)) {
154         if (!lastmod)
155           sendto_one(acptr, "%s " TOK_GLINE " %s %s %s :%s", NumServ(sptr),
156                      target, mask, parv[3], reason);
157         else
158           sendto_one(acptr, "%s " TOK_GLINE " %s %s %s %s :%s", NumServ(sptr),
159                      target, mask, parv[3], parv[4], reason);
160       } else
161         sendto_one(acptr, "%s%s " TOK_GLINE " %s %s %s %s :%s", NumNick(sptr),
162                    target, mask, parv[3], parv[4], reason);
163
164       return 0;
165     }
166
167     flags |= GLINE_LOCAL;
168   }
169
170   if (*mask == '-')
171     mask++;
172   else if (*mask == '+') {
173     flags |= GLINE_ACTIVE;
174     mask++;
175   } else
176     flags |= GLINE_ACTIVE;
177
178   expire_off = atoi(parv[3]);
179
180   agline = gline_find(mask, GLINE_ANY | GLINE_EXACT);
181
182   if (agline) {
183     if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */
184       gline_free(agline);
185     else if (!lastmod || GlineLastMod(agline) < lastmod) { /* new mod */
186       if (flags & GLINE_ACTIVE)
187         return gline_activate(cptr, sptr, agline, lastmod);
188       else
189         return gline_deactivate(cptr, sptr, agline, lastmod);
190     } else if (GlineLastMod(agline) == lastmod)
191       return 0;
192     else
193       return gline_resend(cptr, agline); /* other server desynched WRT gline */
194   }
195
196   return gline_add(cptr, sptr, mask, reason, expire_off, lastmod, flags);
197 }
198
199 /*
200  * mo_gline - oper message handler
201  *
202  * parv[0] = Sender prefix
203  * parv[1] = [[+|-]<G-line mask>]
204  *
205  * Old style:
206  *
207  * parv[2] = [Expiration offset]
208  * parv[3] = [Comment]
209  *
210  * New style:
211  *
212  * parv[2] = [target]
213  * parv[3] = [Expiration offset]
214  * parv[4] = [Comment]
215  *
216  */
217 int
218 mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
219 {
220   struct Client *acptr = 0;
221   struct Gline *agline;
222   unsigned int flags = 0;
223   time_t expire_off;
224   char *mask = parv[1], *target = 0, *reason;
225
226   if (parc < 2)
227     return gline_list(sptr, 0);
228
229   if (*mask == '+') {
230     flags |= GLINE_ACTIVE;
231     mask++;
232   } else if (*mask == '-')
233     mask++;
234   else
235     return gline_list(sptr, mask);
236
237 #ifndef LOCOP_LGLINE
238   if (!IsOper(sptr)) {
239     send_error_to_client(sptr, ERR_NOPRIVILEGES);
240     return 0;
241   }
242 #endif
243
244   if (parc == 4) {
245     expire_off = atoi(parv[2]);
246     reason = parv[3];
247     flags |= GLINE_LOCAL;
248   } else if (parc > 4) {
249     target = parv[2];
250     expire_off = atoi(parv[3]);
251     reason = parv[4];
252   } else
253     return need_more_params(sptr, "GLINE");
254
255   if (target) {
256     if (!(target[0] == '*' && target[1] == '\0')) {
257       if (!(acptr = find_match_server(target))) {
258         send_error_to_client(sptr, ERR_NOSUCHSERVER, target);
259         return 0;
260       }
261
262       if (!IsMe(acptr)) { /* manually propagate, since we don't set it */
263         if (!IsOper(sptr)) {
264           send_error_to_client(sptr, ERR_NOPRIVILEGES);
265           return 0;
266         }
267
268         sendto_one(acptr, "%s%s " TOK_GLINE " %s %c%s %s " TIME_T_FMT " :%s",
269                    NumNick(sptr), NumServ(acptr),
270                    flags & GLINE_ACTIVE ? '?' : '-', mask, parv[3], TStime(),
271                    reason);
272         return 0;
273       }
274
275       flags |= GLINE_LOCAL;
276     } else if (!IsOper(sptr)) {
277       send_error_to_client(sptr, ERR_NOPRIVILEGES);
278       return 0;
279     }
280   }
281
282   agline = gline_find(mask, GLINE_ANY | GLINE_EXACT);
283
284   if (agline) {
285     if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */
286       gline_free(agline);
287     else {
288       if (flags & GLINE_ACTIVE)
289         return gline_activate(cptr, sptr, agline,
290                               GlineLastMod(agline) ? TStime() : 0);
291       else
292         return gline_deactivate(cptr, sptr, agline,
293                                 GlineLastMod(agline) ? TStime() : 0);
294     }
295   }
296
297   return gline_add(cptr, sptr, mask, reason, expire_off, TStime(), flags);
298 }
299
300 /*
301  * m_gline - user message handler
302  *
303  * parv[0] = Sender prefix
304  * parv[1] = [<server name>]
305  *
306  */
307 int
308 m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
309 {
310   if (parc < 2)
311     return gline_list(sptr, 0);
312
313   return gline_list(sptr, parv[1]);
314 }
315
316 #if 0
317 /*
318  * ms_gline - server message handler
319  *
320  * parv[0] = Send prefix
321  *
322  * From server:
323  *
324  * parv[1] = Target: server numeric
325  * parv[2] = [+|-]<G-line mask>
326  * parv[3] = Expiration offset
327  * parv[4] = Comment
328  *
329  * From client:
330  *
331  * parv[1] = [+|-]<G-line mask>
332  * parv[2] = Expiration offset
333  * parv[3] = Comment
334  *
335  */
336 int ms_gline(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
337 {
338   struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
339   struct Gline*  gline;
340   struct Gline*  prev;
341   char*          user;
342   char*          host;
343   int            active;
344   int            ip_mask;
345   int            gtype = 0;
346   time_t         expire = 0;
347
348   /*
349    * Remove expired G-lines
350    */
351   gline_remove_expired(TStime());
352 #ifdef BADCHAN
353   /*
354    * Remove expired bad channels
355    */
356   bad_channel_remove_expired(TStime());
357 #endif
358
359   if (IsServer(cptr)) {
360     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
361       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
362         return need_more_params(sptr, "GLINE");
363
364       if (*parv[2] == '-') /* add mode or delete mode? */
365         active = 0;
366       else
367         active = 1;
368
369       if (*parv[2] == '+' || *parv[2] == '-')
370         parv[2]++; /* step past mode indicator */
371
372       /*
373        * forward the message appropriately
374        */
375       if (0 == ircd_strcmp(parv[1], "*")) {
376         /*
377          * global!
378          */
379         sendto_serv_butone(cptr,
380                      active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
381                      NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
382       }
383       else if ((
384 #if 1
385           /*
386            * REMOVE THIS after all servers upgraded to 2.10.01 and
387            * Uworld uses a numeric too
388            */
389           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
390           (strlen(parv[1]) == 1 &&
391 #endif
392           !(acptr = FindNServer(parv[1]))))
393         return 0;               /* no such server/user exists; forget it */
394       else
395 #if 1
396 /*
397  * REMOVE THIS after all servers upgraded to 2.10.01 and
398  * Uworld uses a numeric too
399  */
400       if (IsServer(acptr) || !MyConnect(acptr))
401 #endif
402       {
403         /* single destination */
404         sendto_one(acptr,
405                active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
406                NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
407         return 0;               /* only the intended  destination
408                                    should add this gline */
409       }
410
411       if (!(host = strchr(parv[2], '@'))) {
412         /*
413          * convert user@host no @'s; assume username is '*'
414          */
415         user = "*";     
416         host = parv[2];
417       }
418       else {
419         user = parv[2];
420         *(host++) = '\0';       /* break up string at the '@' */
421       }
422       ip_mask = check_if_ipmask(host);  /* Store this boolean */
423 #ifdef BADCHAN
424       if ('#' == *host || '&' == *host || '+' == *host)
425          gtype = 1;                /* BAD CHANNEL GLINE */
426 #endif
427       for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
428            gline = gline->next)
429       {
430         if (0 == ircd_strcmp(gline->name, user) &&
431             0 == ircd_strcmp(gline->host, host))
432           break;
433         prev = gline;
434       }
435
436       if (!active && gline)
437       {
438         /*
439          * removing the gline, notify opers
440          */
441         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
442             gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
443
444 #ifdef GPATH
445        write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
446            TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
447             gline->host);
448 #endif /* GPATH */
449
450         free_gline(gline, prev);        /* remove the gline */
451       }
452       else if (active)
453       {                         /* must be adding a gline */
454         expire = atoi(parv[3]) + TStime();      /* expire time? */
455         if (gline && gline->expire < expire)
456         {                       /* new expire time? */
457           /* yes, notify the opers */
458           sendto_op_mask(SNO_GLINE,
459              "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
460              parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
461              expire);
462 #ifdef GPATH
463           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
464               "on %s for %s@%s to " TIME_T_FMT "\n",
465               TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
466               gline->name, gline->host, expire);
467 #endif /* GPATH */
468
469           gline->expire = expire;       /* reset the expire time */
470         }
471         else if (!gline)
472         {                       /* create gline */
473           for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
474             if (!mmatch(gline->name, user) &&
475                 (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
476                 !mmatch(gline->host, host))
477               return 0;         /* found an existing G-line that matches */
478
479           /* add the line: */
480           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
481         }
482       }
483     }
484   }
485   else if (parc < 2 || *parv[1] == '\0')
486   {
487     /* Not enough args and a user; list glines */
488     for (gline = GlobalGlineList; gline; gline = gline->next)
489       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
490           gline->name, gline->host, gline->expire, gline->reason,
491           GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
492           " (Inactive)");
493     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
494   }
495   else
496   {
497     int priv;
498
499 #ifdef LOCOP_LGLINE
500     priv = IsAnOper(cptr);
501 #else
502     priv = IsOper(cptr);
503 #endif
504
505     if (priv)
506     {                           /* non-oper not permitted to change things */
507       if (*parv[1] == '-')
508       {                         /* oper wants to deactivate the gline */
509         active = 0;
510         parv[1]++;
511       }
512       else if (*parv[1] == '+')
513       {                         /* oper wants to activate inactive gline */
514         active = 1;
515         parv[1]++;
516       }
517       else
518         active = -1;
519
520       if (parc > 2)
521         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
522                                                    expire TS */
523     }
524     else
525       active = -1;
526
527     if (!(host = strchr(parv[1], '@')))
528     {
529       user = "*";               /* no @'s; assume username is '*' */
530       host = parv[1];
531     }
532     else
533     {
534       user = parv[1];
535       *(host++) = '\0';         /* break up string at the '@' */
536     }
537     ip_mask = check_if_ipmask(host);    /* Store this boolean */
538 #ifdef BADCHAN
539     if ('#' == *host || '&' == *host || '+' == *host)
540 #ifndef LOCAL_BADCHAN
541      return 0;
542 #else
543      gtype = 1;  /* BAD CHANNEL */
544 #endif
545 #endif
546
547     for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
548          gline = gline->next)
549     {
550       if (!mmatch(gline->name, user) &&
551           (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
552           !mmatch(gline->host, host))
553         break;
554       prev = gline;
555     }
556
557     if (!gline)
558     {
559 #ifdef OPER_LGLINE
560       if (priv && active && expire > CurrentTime)
561       {
562         /* Add local G-line */
563         if (parc < 4 || !strchr(parv[3], ' '))
564           return need_more_params(sptr, "GLINE");
565
566         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
567       }
568       else
569 #endif
570         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
571             host);
572
573       return 0;
574     }
575
576     if (expire <= gline->expire)
577       expire = 0;
578
579     if ((active == -1 ||
580         (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
581         expire == 0)
582     {
583       /* oper wants a list of one gline only */
584       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
585           gline->host, gline->expire, gline->reason,
586           GlineIsActive(gline) ? "" : " (Inactive)");
587       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
588       return 0;
589     }
590
591     if (active != -1 &&
592         (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
593     {
594       if (active)               /* reset activation on gline */
595         SetActive(gline);
596 #ifdef OPER_LGLINE
597       else if (GlineIsLocal(gline))
598       {
599         /* Remove local G-line */
600         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
601             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
602 #ifdef GPATH
603         write_log(GPATH, "# " TIME_T_FMT
604             " %s!%s@%s removed local %s for %s@%s\n",
605             TStime(), parv[0], cptr->user->username, cptr->user->host,
606             gtype ? "BADCHAN" : "GLINE",
607             gline->name, gline->host);
608 #endif /* GPATH */
609         free_gline(gline, prev);        /* remove the gline */
610         return 0;
611       }
612 #endif
613       else
614         ClearActive(gline);
615     }
616     else
617       active = -1;              /* for later sendto_ops and logging functions */
618
619     if (expire)
620       gline->expire = expire;   /* reset expiration time */
621
622     /* inform the operators what's up */
623     if (active != -1)
624     {                           /* changing the activation */
625        sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
626           "%s %sactivating %s for %s@%s and "
627           "resetting expiration time to " TIME_T_FMT,
628           parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
629           gline->name, gline->host, gline->expire);
630 #ifdef GPATH
631       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
632           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
633           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
634           TStime(), parv[0], cptr->user->username, cptr->user->host,
635           active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
636           gline->host, gline->expire);
637 #endif /* GPATH */
638
639     }
640     else if (expire)
641     {                           /* changing only the expiration */
642       sendto_op_mask(SNO_GLINE,
643           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
644           parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
645           gline->expire);
646 #ifdef GPATH
647       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
648           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
649           cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
650           gline->name, gline->host, gline->expire);
651 #endif /* GPATH */
652     }
653   }
654   return 0;
655 }
656
657 /*
658  * mo_gline - oper message handler
659  *
660  * parv[0] = Send prefix
661  *
662  * From server:
663  *
664  * parv[1] = Target: server numeric
665  * parv[2] = [+|-]<G-line mask>
666  * parv[3] = Expiration offset
667  * parv[4] = Comment
668  *
669  * From client:
670  *
671  * parv[1] = [+|-]<G-line mask>
672  * parv[2] = Expiration offset
673  * parv[3] = Comment
674  *
675  */
676 int mo_gline(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
677 {
678   struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
679   struct Gline*  gline;
680   struct Gline*  prev;
681   char*          user;
682   char*          host;
683   int            active;
684   int            ip_mask;
685   int            gtype = 0;
686   time_t         expire = 0;
687
688   /*
689    * Remove expired G-lines
690    */
691   gline_remove_expired(TStime());
692 #ifdef BADCHAN
693   /*
694    * Remove expired bad channels
695    */
696   bad_channel_remove_expired(TStime());
697 #endif
698
699   if (IsServer(cptr)) {
700     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
701       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
702         return need_more_params(sptr, "GLINE");
703
704       if (*parv[2] == '-') /* add mode or delete mode? */
705         active = 0;
706       else
707         active = 1;
708
709       if (*parv[2] == '+' || *parv[2] == '-')
710         parv[2]++; /* step past mode indicator */
711
712       /*
713        * forward the message appropriately
714        */
715       if (0 == ircd_strcmp(parv[1], "*")) {
716         /*
717          * global!
718          */
719         sendto_serv_butone(cptr,
720                      active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
721                      NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
722       }
723       else if ((
724 #if 1
725           /*
726            * REMOVE THIS after all servers upgraded to 2.10.01 and
727            * Uworld uses a numeric too
728            */
729           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
730           (strlen(parv[1]) == 1 &&
731 #endif
732           !(acptr = FindNServer(parv[1]))))
733         return 0;               /* no such server/user exists; forget it */
734       else
735 #if 1
736 /*
737  * REMOVE THIS after all servers upgraded to 2.10.01 and
738  * Uworld uses a numeric too
739  */
740       if (IsServer(acptr) || !MyConnect(acptr))
741 #endif
742       {
743         /* single destination */
744         sendto_one(acptr,
745                active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
746                NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
747         return 0;               /* only the intended  destination
748                                    should add this gline */
749       }
750
751       if (!(host = strchr(parv[2], '@'))) {
752         /*
753          * convert user@host no @'s; assume username is '*'
754          */
755         user = "*";     
756         host = parv[2];
757       }
758       else {
759         user = parv[2];
760         *(host++) = '\0';       /* break up string at the '@' */
761       }
762       ip_mask = check_if_ipmask(host);  /* Store this boolean */
763 #ifdef BADCHAN
764       if ('#' == *host || '&' == *host || '+' == *host)
765          gtype = 1;                /* BAD CHANNEL GLINE */
766 #endif
767       for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
768            gline = gline->next)
769       {
770         if (0 == ircd_strcmp(gline->name, user) &&
771             0 == ircd_strcmp(gline->host, host))
772           break;
773         prev = gline;
774       }
775
776       if (!active && gline)
777       {
778         /*
779          * removing the gline, notify opers
780          */
781         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
782             gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
783
784 #ifdef GPATH
785        write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
786            TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
787             gline->host);
788 #endif /* GPATH */
789
790         free_gline(gline, prev);        /* remove the gline */
791       }
792       else if (active)
793       {                         /* must be adding a gline */
794         expire = atoi(parv[3]) + TStime();      /* expire time? */
795         if (gline && gline->expire < expire)
796         {                       /* new expire time? */
797           /* yes, notify the opers */
798           sendto_op_mask(SNO_GLINE,
799              "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
800              parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
801              expire);
802 #ifdef GPATH
803           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
804               "on %s for %s@%s to " TIME_T_FMT "\n",
805               TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
806               gline->name, gline->host, expire);
807 #endif /* GPATH */
808
809           gline->expire = expire;       /* reset the expire time */
810         }
811         else if (!gline)
812         {                       /* create gline */
813           for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
814             if (!mmatch(gline->name, user) &&
815                 (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
816                 !mmatch(gline->host, host))
817               return 0;         /* found an existing G-line that matches */
818
819           /* add the line: */
820           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
821         }
822       }
823     }
824   }
825   else if (parc < 2 || *parv[1] == '\0')
826   {
827     /* Not enough args and a user; list glines */
828     for (gline = GlobalGlineList; gline; gline = gline->next)
829       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
830           gline->name, gline->host, gline->expire, gline->reason,
831           GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
832           " (Inactive)");
833     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
834   }
835   else
836   {
837     int priv;
838
839 #ifdef LOCOP_LGLINE
840     priv = IsAnOper(cptr);
841 #else
842     priv = IsOper(cptr);
843 #endif
844
845     if (priv)
846     {                           /* non-oper not permitted to change things */
847       if (*parv[1] == '-')
848       {                         /* oper wants to deactivate the gline */
849         active = 0;
850         parv[1]++;
851       }
852       else if (*parv[1] == '+')
853       {                         /* oper wants to activate inactive gline */
854         active = 1;
855         parv[1]++;
856       }
857       else
858         active = -1;
859
860       if (parc > 2)
861         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
862                                                    expire TS */
863     }
864     else
865       active = -1;
866
867     if (!(host = strchr(parv[1], '@')))
868     {
869       user = "*";               /* no @'s; assume username is '*' */
870       host = parv[1];
871     }
872     else
873     {
874       user = parv[1];
875       *(host++) = '\0';         /* break up string at the '@' */
876     }
877     ip_mask = check_if_ipmask(host);    /* Store this boolean */
878 #ifdef BADCHAN
879     if ('#' == *host || '&' == *host || '+' == *host)
880 #ifndef LOCAL_BADCHAN
881      return 0;
882 #else
883      gtype = 1;  /* BAD CHANNEL */
884 #endif
885 #endif
886
887     for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
888          gline = gline->next)
889     {
890       if (!mmatch(gline->name, user) &&
891           (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
892           !mmatch(gline->host, host))
893         break;
894       prev = gline;
895     }
896
897     if (!gline)
898     {
899 #ifdef OPER_LGLINE
900       if (priv && active && expire > CurrentTime)
901       {
902         /* Add local G-line */
903         if (parc < 4 || !strchr(parv[3], ' '))
904           return need_more_params(sptr, "GLINE");
905
906         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
907       }
908       else
909 #endif
910         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
911             host);
912
913       return 0;
914     }
915
916     if (expire <= gline->expire)
917       expire = 0;
918
919     if ((active == -1 ||
920         (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
921         expire == 0)
922     {
923       /* oper wants a list of one gline only */
924       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
925           gline->host, gline->expire, gline->reason,
926           GlineIsActive(gline) ? "" : " (Inactive)");
927       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
928       return 0;
929     }
930
931     if (active != -1 &&
932         (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
933     {
934       if (active)               /* reset activation on gline */
935         SetActive(gline);
936 #ifdef OPER_LGLINE
937       else if (GlineIsLocal(gline))
938       {
939         /* Remove local G-line */
940         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
941             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
942 #ifdef GPATH
943         write_log(GPATH, "# " TIME_T_FMT
944             " %s!%s@%s removed local %s for %s@%s\n",
945             TStime(), parv[0], cptr->user->username, cptr->user->host,
946             gtype ? "BADCHAN" : "GLINE",
947             gline->name, gline->host);
948 #endif /* GPATH */
949         free_gline(gline, prev);        /* remove the gline */
950         return 0;
951       }
952 #endif
953       else
954         ClearActive(gline);
955     }
956     else
957       active = -1;              /* for later sendto_ops and logging functions */
958
959     if (expire)
960       gline->expire = expire;   /* reset expiration time */
961
962     /* inform the operators what's up */
963     if (active != -1)
964     {                           /* changing the activation */
965        sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
966           "%s %sactivating %s for %s@%s and "
967           "resetting expiration time to " TIME_T_FMT,
968           parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
969           gline->name, gline->host, gline->expire);
970 #ifdef GPATH
971       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
972           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
973           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
974           TStime(), parv[0], cptr->user->username, cptr->user->host,
975           active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
976           gline->host, gline->expire);
977 #endif /* GPATH */
978
979     }
980     else if (expire)
981     {                           /* changing only the expiration */
982       sendto_op_mask(SNO_GLINE,
983           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
984           parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
985           gline->expire);
986 #ifdef GPATH
987       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
988           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
989           cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
990           gline->name, gline->host, gline->expire);
991 #endif /* GPATH */
992     }
993   }
994   return 0;
995 }
996
997
998 #if 0
999 /*
1000  * m_gline
1001  *
1002  * parv[0] = Send prefix
1003  *
1004  * From server:
1005  *
1006  * parv[1] = Target: server numeric
1007  * parv[2] = [+|-]<G-line mask>
1008  * parv[3] = Expiration offset
1009  * parv[4] = Comment
1010  *
1011  * From client:
1012  *
1013  * parv[1] = [+|-]<G-line mask>
1014  * parv[2] = Expiration offset
1015  * parv[3] = Comment
1016  *
1017  */
1018 int m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1019 {
1020   struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
1021   struct Gline*  gline;
1022   struct Gline*  prev;
1023   char*          user;
1024   char*          host;
1025   int            active;
1026   int            ip_mask;
1027   int            gtype = 0;
1028   time_t         expire = 0;
1029
1030   /*
1031    * Remove expired G-lines
1032    */
1033   gline_remove_expired(TStime());
1034 #ifdef BADCHAN
1035   /*
1036    * Remove expired bad channels
1037    */
1038   bad_channel_remove_expired(TStime());
1039 #endif
1040
1041   if (IsServer(cptr)) {
1042     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
1043       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
1044         return need_more_params(sptr, "GLINE");
1045
1046       if (*parv[2] == '-') /* add mode or delete mode? */
1047         active = 0;
1048       else
1049         active = 1;
1050
1051       if (*parv[2] == '+' || *parv[2] == '-')
1052         parv[2]++; /* step past mode indicator */
1053
1054       /*
1055        * forward the message appropriately
1056        */
1057       if (0 == ircd_strcmp(parv[1], "*")) {
1058         /*
1059          * global!
1060          */
1061         sendto_serv_butone(cptr,
1062                      active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
1063                      NumServ(cptr), parv[1], parv[2], parv[3], parv[4]);
1064       }
1065       else if ((
1066 #if 1
1067           /*
1068            * REMOVE THIS after all servers upgraded to 2.10.01 and
1069            * Uworld uses a numeric too
1070            */
1071           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
1072           (strlen(parv[1]) == 1 &&
1073 #endif
1074           !(acptr = FindNServer(parv[1]))))
1075         return 0;               /* no such server/user exists; forget it */
1076       else
1077 #if 1
1078 /*
1079  * REMOVE THIS after all servers upgraded to 2.10.01 and
1080  * Uworld uses a numeric too
1081  */
1082       if (IsServer(acptr) || !MyConnect(acptr))
1083 #endif
1084       {
1085         /* single destination */
1086         sendto_one(acptr,
1087                active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
1088                NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
1089         return 0;               /* only the intended  destination
1090                                    should add this gline */
1091       }
1092
1093       if (!(host = strchr(parv[2], '@'))) {
1094         /*
1095          * convert user@host no @'s; assume username is '*'
1096          */
1097         user = "*";     
1098         host = parv[2];
1099       }
1100       else {
1101         user = parv[2];
1102         *(host++) = '\0';       /* break up string at the '@' */
1103       }
1104       ip_mask = check_if_ipmask(host);  /* Store this boolean */
1105 #ifdef BADCHAN
1106       if ('#' == *host || '&' == *host || '+' == *host)
1107          gtype = 1;                /* BAD CHANNEL GLINE */
1108 #endif
1109       for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
1110            gline = gline->next)
1111       {
1112         if (0 == ircd_strcmp(gline->name, user) &&
1113             0 == ircd_strcmp(gline->host, host))
1114           break;
1115         prev = gline;
1116       }
1117
1118       if (!active && gline)
1119       {
1120         /*
1121          * removing the gline, notify opers
1122          */
1123         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
1124             gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
1125
1126 #ifdef GPATH
1127        write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
1128            TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
1129             gline->host);
1130 #endif /* GPATH */
1131
1132         free_gline(gline, prev);        /* remove the gline */
1133       }
1134       else if (active)
1135       {                         /* must be adding a gline */
1136         expire = atoi(parv[3]) + TStime();      /* expire time? */
1137         if (gline && gline->expire < expire)
1138         {                       /* new expire time? */
1139           /* yes, notify the opers */
1140           sendto_op_mask(SNO_GLINE,
1141              "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1142              parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
1143              expire);
1144 #ifdef GPATH
1145           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
1146               "on %s for %s@%s to " TIME_T_FMT "\n",
1147               TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
1148               gline->name, gline->host, expire);
1149 #endif /* GPATH */
1150
1151           gline->expire = expire;       /* reset the expire time */
1152         }
1153         else if (!gline)
1154         {                       /* create gline */
1155           for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
1156             if (!mmatch(gline->name, user) &&
1157                 (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
1158                 !mmatch(gline->host, host))
1159               return 0;         /* found an existing G-line that matches */
1160
1161           /* add the line: */
1162           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
1163         }
1164       }
1165     }
1166   }
1167   else if (parc < 2 || *parv[1] == '\0')
1168   {
1169     /* Not enough args and a user; list glines */
1170     for (gline = GlobalGlineList; gline; gline = gline->next)
1171       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
1172           gline->name, gline->host, gline->expire, gline->reason,
1173           GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
1174           " (Inactive)");
1175     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1176   }
1177   else
1178   {
1179     int priv;
1180
1181 #ifdef LOCOP_LGLINE
1182     priv = IsAnOper(cptr);
1183 #else
1184     priv = IsOper(cptr);
1185 #endif
1186
1187     if (priv)
1188     {                           /* non-oper not permitted to change things */
1189       if (*parv[1] == '-')
1190       {                         /* oper wants to deactivate the gline */
1191         active = 0;
1192         parv[1]++;
1193       }
1194       else if (*parv[1] == '+')
1195       {                         /* oper wants to activate inactive gline */
1196         active = 1;
1197         parv[1]++;
1198       }
1199       else
1200         active = -1;
1201
1202       if (parc > 2)
1203         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
1204                                                    expire TS */
1205     }
1206     else
1207       active = -1;
1208
1209     if (!(host = strchr(parv[1], '@')))
1210     {
1211       user = "*";               /* no @'s; assume username is '*' */
1212       host = parv[1];
1213     }
1214     else
1215     {
1216       user = parv[1];
1217       *(host++) = '\0';         /* break up string at the '@' */
1218     }
1219     ip_mask = check_if_ipmask(host);    /* Store this boolean */
1220 #ifdef BADCHAN
1221     if ('#' == *host || '&' == *host || '+' == *host)
1222 #ifndef LOCAL_BADCHAN
1223      return 0;
1224 #else
1225      gtype = 1;  /* BAD CHANNEL */
1226 #endif
1227 #endif
1228
1229     for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
1230          gline = gline->next)
1231     {
1232       if (!mmatch(gline->name, user) &&
1233           (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
1234           !mmatch(gline->host, host))
1235         break;
1236       prev = gline;
1237     }
1238
1239     if (!gline)
1240     {
1241 #ifdef OPER_LGLINE
1242       if (priv && active && expire > CurrentTime)
1243       {
1244         /* Add local G-line */
1245         if (parc < 4 || !strchr(parv[3], ' '))
1246           return need_more_params(sptr, "GLINE");
1247
1248         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
1249       }
1250       else
1251 #endif
1252         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
1253             host);
1254
1255       return 0;
1256     }
1257
1258     if (expire <= gline->expire)
1259       expire = 0;
1260
1261     if ((active == -1 ||
1262         (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
1263         expire == 0)
1264     {
1265       /* oper wants a list of one gline only */
1266       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
1267           gline->host, gline->expire, gline->reason,
1268           GlineIsActive(gline) ? "" : " (Inactive)");
1269       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1270       return 0;
1271     }
1272
1273     if (active != -1 &&
1274         (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
1275     {
1276       if (active)               /* reset activation on gline */
1277         SetActive(gline);
1278 #ifdef OPER_LGLINE
1279       else if (GlineIsLocal(gline))
1280       {
1281         /* Remove local G-line */
1282         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
1283             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
1284 #ifdef GPATH
1285         write_log(GPATH, "# " TIME_T_FMT
1286             " %s!%s@%s removed local %s for %s@%s\n",
1287             TStime(), parv[0], cptr->user->username, cptr->user->host,
1288             gtype ? "BADCHAN" : "GLINE",
1289             gline->name, gline->host);
1290 #endif /* GPATH */
1291         free_gline(gline, prev);        /* remove the gline */
1292         return 0;
1293       }
1294 #endif
1295       else
1296         ClearActive(gline);
1297     }
1298     else
1299       active = -1;              /* for later sendto_ops and logging functions */
1300
1301     if (expire)
1302       gline->expire = expire;   /* reset expiration time */
1303
1304     /* inform the operators what's up */
1305     if (active != -1)
1306     {                           /* changing the activation */
1307        sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
1308           "%s %sactivating %s for %s@%s and "
1309           "resetting expiration time to " TIME_T_FMT,
1310           parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
1311           gline->name, gline->host, gline->expire);
1312 #ifdef GPATH
1313       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
1314           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
1315           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
1316           TStime(), parv[0], cptr->user->username, cptr->user->host,
1317           active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
1318           gline->host, gline->expire);
1319 #endif /* GPATH */
1320
1321     }
1322     else if (expire)
1323     {                           /* changing only the expiration */
1324       sendto_op_mask(SNO_GLINE,
1325           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1326           parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
1327           gline->expire);
1328 #ifdef GPATH
1329       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
1330           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
1331           cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
1332           gline->name, gline->host, gline->expire);
1333 #endif /* GPATH */
1334     }
1335   }
1336   return 0;
1337 }
1338
1339 #endif /* 0 */
1340
1341 #endif /* 0 */