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