Lets hope that I did this right :)
[ircu2.10.12-pk.git] / ircd / opercmds.c
1 /*
2  * IRC - Internet Relay Chat, ircd/opercmds.c (formerly ircd/s_serv.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
24 #include "sys.h"
25 #include <sys/stat.h>
26 #if HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29 #include <stdlib.h>
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #ifdef USE_SYSLOG
34 #include <syslog.h>
35 #endif
36 #include "h.h"
37 #include "opercmds.h"
38 #include "struct.h"
39 #include "ircd.h"
40 #include "s_bsd.h"
41 #include "send.h"
42 #include "s_err.h"
43 #include "numeric.h"
44 #include "match.h"
45 #include "s_misc.h"
46 #include "s_conf.h"
47 #include "class.h"
48 #include "s_user.h"
49 #include "common.h"
50 #include "msg.h"
51 #include "sprintf_irc.h"
52 #include "userload.h"
53 #include "parse.h"
54 #include "numnicks.h"
55 #include "crule.h"
56 #include "version.h"
57 #include "support.h"
58 #include "s_serv.h"
59 #include "hash.h"
60
61 RCSTAG_CC("$Id$");
62
63 /*
64  *  m_squit
65  *
66  *    parv[0] = sender prefix
67  *    parv[1] = server name
68  *    parv[2] = timestamp
69  *    parv[parc-1] = comment
70  */
71 int m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[])
72 {
73   Reg1 aConfItem *aconf;
74   char *server;
75   Reg2 aClient *acptr;
76   char *comment = (parc > ((!IsServer(cptr)) ? 2 : 3) &&
77       !BadPtr(parv[parc - 1])) ? parv[parc - 1] : cptr->name;
78
79   if (!IsPrivileged(sptr))
80   {
81     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
82     return 0;
83   }
84
85   if (parc > (IsServer(cptr) ? 2 : 1))
86   {
87     server = parv[1];
88     /*
89      * To accomodate host masking, a squit for a masked server
90      * name is expanded if the incoming mask is the same as
91      * the server name for that link to the name of link.
92      */
93     if ((*server == '*') && IsServer(cptr) && (aconf = cptr->serv->nline) &&
94         !strCasediff(server, my_name_for_link(me.name, aconf)))
95     {
96       server = cptr->name;
97       acptr = cptr;
98     }
99     else
100     {
101       /*
102        * The following allows wild cards in SQUIT. Only usefull
103        * when the command is issued by an oper.
104        */
105       for (acptr = client; (acptr = next_client(acptr, server));
106           acptr = acptr->next)
107         if (IsServer(acptr) || IsMe(acptr))
108           break;
109
110       if (acptr)
111       {
112         if (IsMe(acptr))
113         {
114           if (IsServer(cptr))
115           {
116             acptr = cptr;
117             server = cptr->sockhost;
118           }
119           else
120             acptr = NULL;
121         }
122         else
123         {
124           /*
125            * Look for a matching server that is closer,
126            * that way we won't accidently squit two close
127            * servers like davis.* and davis-r.* when typing
128            * /SQUIT davis*
129            */
130           aClient *acptr2;
131           for (acptr2 = acptr->serv->up; acptr2 != &me;
132               acptr2 = acptr2->serv->up)
133             if (!match(server, acptr2->name))
134               acptr = acptr2;
135         }
136       }
137     }
138     /* If atoi(parv[2]) == 0 we must indeed squit !
139      * It wil be our neighbour.
140      */
141     if (acptr && IsServer(cptr) &&
142         atoi(parv[2]) && atoi(parv[2]) != acptr->serv->timestamp)
143     {
144       Debug((DEBUG_NOTICE, "Ignoring SQUIT with wrong timestamp"));
145       return 0;
146     }
147   }
148   else
149   {
150     sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SQUIT");
151     if (IsServer(cptr))
152     {
153       /*
154        * This is actually protocol error. But, well, closing
155        * the link is very proper answer to that...
156        */
157       server = cptr->sockhost;
158       acptr = cptr;
159     }
160     else
161       return 0;
162   }
163   if (!acptr)
164   {
165     if (IsUser(sptr))
166       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], server);
167     return 0;
168   }
169   if (IsLocOp(sptr) && !MyConnect(acptr))
170   {
171     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
172     return 0;
173   }
174
175   return exit_client(cptr, acptr, sptr, comment);
176 }
177
178 /*
179  * m_stats/stats_conf
180  *
181  * Report N/C-configuration lines from this server. This could
182  * report other configuration lines too, but converting the
183  * status back to "char" is a bit akward--not worth the code
184  * it needs...
185  *
186  * Note: The info is reported in the order the server uses
187  *       it--not reversed as in ircd.conf!
188  */
189
190 static unsigned int report_array[17][3] = {
191   {CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
192   {CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
193   {CONF_CLIENT, RPL_STATSILINE, 'I'},
194   {CONF_KILL, RPL_STATSKLINE, 'K'},
195   {CONF_IPKILL, RPL_STATSKLINE, 'k'},
196   {CONF_LEAF, RPL_STATSLLINE, 'L'},
197   {CONF_OPERATOR, RPL_STATSOLINE, 'O'},
198   {CONF_HUB, RPL_STATSHLINE, 'H'},
199   {CONF_LOCOP, RPL_STATSOLINE, 'o'},
200   {CONF_CRULEALL, RPL_STATSDLINE, 'D'},
201   {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
202   {CONF_UWORLD, RPL_STATSULINE, 'U'},
203   {CONF_TLINES, RPL_STATSTLINE, 'T'},
204   {CONF_LISTEN_PORT, RPL_STATSPLINE, 'P'},
205   {0, 0}
206 };
207
208 static void report_configured_links(aClient *sptr, int mask)
209 {
210   static char null[] = "<NULL>";
211   aConfItem *tmp;
212   unsigned int *p;
213   unsigned short int port;
214   char c, *host, *pass, *name;
215
216   for (tmp = conf; tmp; tmp = tmp->next)
217     if ((tmp->status & mask))
218     {
219       for (p = &report_array[0][0]; *p; p += 3)
220         if (*p == tmp->status)
221           break;
222       if (!*p)
223         continue;
224       c = (char)*(p + 2);
225       host = BadPtr(tmp->host) ? null : tmp->host;
226       pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
227       name = BadPtr(tmp->name) ? null : tmp->name;
228       port = tmp->port;
229       /*
230        * On K line the passwd contents can be
231        * displayed on STATS reply.    -Vesa
232        */
233       /* Special-case 'k' or 'K' lines as appropriate... -Kev */
234       if ((tmp->status & CONF_KLINE))
235         sendto_one(sptr, rpl_str(p[1]), me.name,
236             sptr->name, c, host, pass, name, port, get_conf_class(tmp));
237       /* connect rules are classless */
238       else if ((tmp->status & CONF_CRULE))
239         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name);
240       else if ((tmp->status & CONF_TLINES))
241         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, pass);
242       else if ((tmp->status & CONF_LISTEN_PORT))
243         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, port,
244             tmp->clients, tmp->status);
245       else if ((tmp->status & CONF_UWORLD))
246         sendto_one(sptr, rpl_str(p[1]),
247             me.name, sptr->name, c, host, pass, name, port,
248             get_conf_class(tmp));
249       else
250         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name,
251             port, get_conf_class(tmp));
252     }
253   return;
254 }
255
256 /*
257  * m_stats
258  *
259  *    parv[0] = sender prefix
260  *    parv[1] = statistics selector (defaults to Message frequency)
261  *    parv[2] = target server (current server defaulted, if omitted)
262  * And 'stats l' and 'stats' L:
263  *    parv[3] = server mask ("*" defaulted, if omitted)
264  * Or for stats p,P:
265  *    parv[3] = port mask (returns p-lines when its port is matched by this)
266  * Or for stats k,K,i and I:
267  *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
268  *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
269  *              (defaults to old reply if ommitted, when local or Oper)
270  *              A remote mask (something containing wildcards) is only
271  *              allowed for IRC Operators.
272  * Or for stats M:
273  *    parv[3] = time param
274  *    parv[4] = time param 
275  *    (see report_memleak_stats() in runmalloc.c for details)
276  *
277  * This function is getting really ugly. -Ghostwolf
278  */
279 int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[])
280 {
281   static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
282       "RcveM RcveKBytes :Open since";
283   static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
284   aMessage *mptr;
285   aClient *acptr;
286   aGline *agline, *a2gline;
287   aConfItem *aconf;
288   char stat = parc > 1 ? parv[1][0] : '\0';
289   Reg1 int i;
290
291 /* m_stats is so obnoxiously full of special cases that the different
292  * hunt_server() possiblites were becoming very messy. It now uses a
293  * switch() so as to be easier to read and update as params change. 
294  * -Ghostwolf 
295  */
296   switch (stat)
297   {
298       /* open to all, standard # of params */
299     case 'U':
300     case 'u':
301     {
302       if (hunt_server(0, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
303           != HUNTED_ISME)
304         return 0;
305       break;
306     }
307
308       /* open to all, varying # of params */
309     case 'k':
310     case 'K':
311     case 'i':
312     case 'I':
313     case 'p':
314     case 'P':
315     {
316       if (parc > 3)
317       {
318         if (hunt_server(0, cptr, sptr, ":%s STATS %s %s :%s", 2, parc, parv)
319             != HUNTED_ISME)
320           return 0;
321       }
322       else
323       {
324         if (hunt_server(0, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
325             != HUNTED_ISME)
326           return 0;
327       }
328       break;
329     }
330
331       /* oper only, varying # of params */
332     case 'l':
333     case 'L':
334     case 'M':
335     {
336       if (parc == 4)
337       {
338         if (hunt_server(1, cptr, sptr, ":%s STATS %s %s :%s", 2, parc, parv)
339             != HUNTED_ISME)
340           return 0;
341       }
342       else if (parc > 4)
343       {
344         if (hunt_server(1, cptr, sptr, ":%s STATS %s %s %s :%s", 2, parc,
345             parv) != HUNTED_ISME)
346           return 0;
347       }
348       else if (hunt_server(1, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
349           != HUNTED_ISME)
350         return 0;
351       break;
352     }
353
354       /* oper only, standard # of params */
355     default:
356     {
357       if (hunt_server(1, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
358           != HUNTED_ISME)
359         return 0;
360       break;
361     }
362   }
363
364   switch (stat)
365   {
366     case 'L':
367     case 'l':
368     {
369       int doall = 0, wilds = 0;
370       char *name = "*";
371       if (parc > 3 && *parv[3])
372       {
373         char *p;
374         name = parv[3];
375         wilds = (*name == '*' || *name == '?');
376         for (p = name + 1; *p; ++p)
377           if ((*p == '*' || *p == '?') && p[-1] != '\\')
378           {
379             wilds = 1;
380             break;
381           }
382       }
383       else
384         doall = 1;
385       /*
386        * Send info about connections which match, or all if the
387        * mask matches me.name.  Only restrictions are on those who
388        * are invisible not being visible to 'foreigners' who use
389        * a wild card based search to list it.
390        */
391       sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
392       for (i = 0; i <= highest_fd; i++)
393       {
394         if (!(acptr = loc_clients[i]))
395           continue;
396         /* Don't return clients when this is a request for `all' */
397         if (doall && IsUser(acptr))
398           continue;
399         /* Don't show invisible people to unauthorized people when using
400          * wildcards  -- Is this still needed now /stats is oper only ? */
401         if (IsInvisible(acptr) && (doall || wilds) &&
402             !(MyConnect(sptr) && IsOper(sptr)) &&
403             !IsAnOper(acptr) && (acptr != sptr))
404           continue;
405         /* Only show the ones that match the given mask - if any */
406         if (!doall && wilds && match(name, acptr->name))
407           continue;
408         /* Skip all that do not match the specific query */
409         if (!(doall || wilds) && strCasediff(name, acptr->name))
410           continue;
411         sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
412             (isUpper(stat)) ?
413             get_client_name(acptr, TRUE) : get_client_name(acptr, FALSE),
414             (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
415             (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
416             time(NULL) - acptr->firsttime);
417       }
418       break;
419     }
420     case 'C':
421     case 'c':
422       report_configured_links(sptr,
423           CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER);
424       break;
425     case 'G':
426     case 'g':
427       /* send glines */
428       for (agline = gline, a2gline = NULL; agline; agline = agline->next)
429       {
430         if (agline->expire <= TStime())
431         {                       /* handle expired glines */
432           free_gline(agline, a2gline);
433           agline = a2gline ? a2gline : gline;   /* make sure to splice
434                                                    list together */
435           if (!agline)
436             break;              /* last gline; break out of loop */
437           continue;             /* continue! */
438         }
439         sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
440             sptr->name, 'G', agline->name, agline->host,
441             agline->expire, agline->reason);
442         a2gline = agline;
443       }
444       break;
445     case 'H':
446     case 'h':
447       report_configured_links(sptr, CONF_HUB | CONF_LEAF);
448       break;
449     case 'I':
450     case 'i':
451     case 'K':
452     case 'k':                   /* display CONF_IPKILL as well
453                                    as CONF_KILL -Kev */
454     {
455       int wilds, count;
456       char *user, *host, *p;
457       int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
458       if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
459       {
460         report_configured_links(sptr, conf_status);
461         break;
462       }
463       if (parc < 4 || *parv[3] == '\0')
464       {
465         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
466             (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
467         return 0;
468       }
469       wilds = 0;
470       for (p = parv[3]; *p; p++)
471       {
472         if (*p == '\\')
473         {
474           if (!*++p)
475             break;
476           continue;
477         }
478         if (*p == '?' || *p == '*')
479         {
480           wilds = 1;
481           break;
482         }
483       }
484       if (!(MyConnect(sptr) || IsOper(sptr)))
485       {
486         wilds = 0;
487         count = 3;
488       }
489       else
490         count = 1000;
491
492       if (conf_status == CONF_CLIENT)
493       {
494         user = NULL;            /* Not used, but to avoid compiler warning. */
495
496         host = parv[3];
497       }
498       else
499       {
500         if ((host = strchr(parv[3], '@')))
501         {
502           user = parv[3];
503           *host++ = 0;;
504         }
505         else
506         {
507           user = NULL;
508           host = parv[3];
509         }
510       }
511       for (aconf = conf; aconf; aconf = aconf->next)
512       {
513         if ((aconf->status & conf_status))
514         {
515           if (conf_status == CONF_KLINE)
516           {
517             if ((!wilds && ((user || aconf->host[1]) &&
518                 !match(aconf->host, host) &&
519                 (!user || !match(aconf->name, user)))) ||
520                 (wilds && !mmatch(host, aconf->host) &&
521                 (!user || !mmatch(user, aconf->name))))
522             {
523               sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
524                   sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
525                   aconf->port, get_conf_class(aconf));
526               if (--count == 0)
527                 break;
528             }
529           }
530           else if (conf_status == CONF_CLIENT)
531           {
532             if ((!wilds && (!match(aconf->host, host) ||
533                 !match(aconf->name, host))) ||
534                 (wilds && (!mmatch(host, aconf->host) ||
535                 !mmatch(host, aconf->name))))
536             {
537               sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
538                   sptr->name, 'I', aconf->host, aconf->name,
539                   aconf->port, get_conf_class(aconf));
540               if (--count == 0)
541                 break;
542             }
543           }
544         }
545       }
546       break;
547     }
548     case 'M':
549 #ifdef MEMSIZESTATS
550       sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
551           me.name, parv[0], get_mem_size(), get_alloc_cnt());
552 #endif
553 #ifdef MEMLEAKSTATS
554       report_memleak_stats(sptr, parc, parv);
555 #endif
556 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
557       sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
558           "is not enabled on this server", me.name, parv[0]);
559 #endif
560       break;
561     case 'm':
562       for (mptr = msgtab; mptr->cmd; mptr++)
563         if (mptr->count)
564           sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
565               me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
566       break;
567     case 'o':
568     case 'O':
569       report_configured_links(sptr, CONF_OPS);
570       break;
571     case 'p':
572     case 'P':
573     {
574       int count = 100;
575       char port[6];
576       if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
577       {
578         report_configured_links(sptr, CONF_LISTEN_PORT);
579         break;
580       }
581       if (!(MyConnect(sptr) || IsOper(sptr)))
582         count = 3;
583       for (aconf = conf; aconf; aconf = aconf->next)
584         if (aconf->status == CONF_LISTEN_PORT)
585         {
586           if (parc >= 4 && *parv[3] != '\0')
587           {
588             sprintf_irc(port, "%u", aconf->port);
589             if (match(parv[3], port))
590               continue;
591           }
592           sendto_one(sptr, rpl_str(RPL_STATSPLINE), me.name, sptr->name, 'P',
593               aconf->port, aconf->clients, aconf->status);
594           if (--count == 0)
595             break;
596         }
597       break;
598     }
599     case 'R':
600     case 'r':
601 #ifdef DEBUGMODE
602       send_usage(sptr, parv[0]);
603 #endif
604       break;
605     case 'D':
606       report_configured_links(sptr, CONF_CRULEALL);
607       break;
608     case 'd':
609       report_configured_links(sptr, CONF_CRULE);
610       break;
611     case 't':
612       tstats(sptr, parv[0]);
613       break;
614     case 'T':
615       report_configured_links(sptr, CONF_TLINES);
616       break;
617     case 'U':
618       report_configured_links(sptr, CONF_UWORLD);
619       break;
620     case 'u':
621     {
622       register time_t nowr;
623
624       nowr = now - me.since;
625       sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
626           nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
627       sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
628           max_connection_count, max_client_count);
629       break;
630     }
631     case 'W':
632     case 'w':
633       calc_load(sptr);
634       break;
635     case 'X':
636     case 'x':
637 #ifdef  DEBUGMODE
638       send_listinfo(sptr, parv[0]);
639 #endif
640       break;
641     case 'Y':
642     case 'y':
643       report_classes(sptr);
644       break;
645     case 'Z':
646     case 'z':
647       count_memory(sptr, parv[0]);
648       break;
649     default:
650       stat = '*';
651       break;
652   }
653   sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
654   return 0;
655 }
656
657 /*
658  *  m_connect                           - Added by Jto 11 Feb 1989
659  *
660  *    parv[0] = sender prefix
661  *    parv[1] = servername
662  *    parv[2] = port number
663  *    parv[3] = remote server
664  */
665 int m_connect(aClient *cptr, aClient *sptr, int parc, char *parv[])
666 {
667   int retval;
668   unsigned short int port, tmpport;
669   aConfItem *aconf, *cconf;
670   aClient *acptr;
671
672   if (!IsPrivileged(sptr))
673   {
674     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
675     return -1;
676   }
677
678   if (IsLocOp(sptr) && parc > 3)        /* Only allow LocOps to make */
679     return 0;                   /* local CONNECTS --SRB      */
680
681   if (parc > 3 && MyUser(sptr))
682   {
683     aClient *acptr2, *acptr3;
684     if (!(acptr3 = find_match_server(parv[3])))
685     {
686       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]);
687       return 0;
688     }
689
690     /* Look for closest matching server */
691     for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up)
692       if (!match(parv[3], acptr2->name))
693         acptr3 = acptr2;
694
695     parv[3] = acptr3->name;
696   }
697
698   if (hunt_server(1, cptr, sptr, ":%s CONNECT %s %s :%s", 3, parc, parv) !=
699       HUNTED_ISME)
700     return 0;
701
702   if (parc < 2 || *parv[1] == '\0')
703   {
704     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "CONNECT");
705     return -1;
706   }
707
708   if ((acptr = FindServer(parv[1])))
709   {
710     if (MyUser(sptr) || Protocol(cptr) < 10)
711       sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
712           me.name, parv[0], parv[1], "already exists from", acptr->from->name);
713     else
714       sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
715           NumServ(&me), NumNick(sptr), parv[1], "already exists from",
716           acptr->from->name);
717     return 0;
718   }
719
720   for (aconf = conf; aconf; aconf = aconf->next)
721     if (aconf->status == CONF_CONNECT_SERVER &&
722         match(parv[1], aconf->name) == 0)
723       break;
724   /* Checked first servernames, then try hostnames. */
725   if (!aconf)
726     for (aconf = conf; aconf; aconf = aconf->next)
727       if (aconf->status == CONF_CONNECT_SERVER &&
728           (match(parv[1], aconf->host) == 0 ||
729           match(parv[1], strchr(aconf->host, '@') + 1) == 0))
730         break;
731
732   if (!aconf)
733   {
734     if (MyUser(sptr) || Protocol(cptr) < 10)
735       sendto_one(sptr,
736           ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
737           me.name, parv[0], parv[1]);
738     else
739       sendto_one(sptr,
740           "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
741           NumServ(&me), NumNick(sptr), parv[1]);
742     return 0;
743   }
744   /*
745    *  Get port number from user, if given. If not specified,
746    *  use the default from configuration structure. If missing
747    *  from there, then use the precompiled default.
748    */
749   tmpport = port = aconf->port;
750   if (parc > 2 && !BadPtr(parv[2]))
751   {
752     if ((port = atoi(parv[2])) == 0)
753     {
754       if (MyUser(sptr) || Protocol(cptr) < 10)
755         sendto_one(sptr,
756             ":%s NOTICE %s :Connect: Invalid port number", me.name, parv[0]);
757       else
758         sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
759             NumServ(&me), NumNick(sptr));
760       return 0;
761     }
762   }
763   else if (port == 0 && (port = PORTNUM) == 0)
764   {
765     if (MyUser(sptr) || Protocol(cptr) < 10)
766       sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
767           me.name, parv[0]);
768     else
769       sendto_one(sptr, "%s NOTICE %s%s :Connect: missing port number",
770           NumServ(&me), NumNick(sptr));
771     return 0;
772   }
773
774   /*
775    * Evaluate connection rules...  If no rules found, allow the
776    * connect.   Otherwise stop with the first true rule (ie: rules
777    * are ored together.  Oper connects are effected only by D
778    * lines (CRULEALL) not d lines (CRULEAUTO).
779    */
780   for (cconf = conf; cconf; cconf = cconf->next)
781     if ((cconf->status == CONF_CRULEALL) &&
782         (match(cconf->host, aconf->name) == 0))
783       if (crule_eval(cconf->passwd))
784       {
785         if (MyUser(sptr) || Protocol(cptr) < 10)
786           sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
787               me.name, parv[0], cconf->name);
788         else
789           sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
790               NumServ(&me), NumNick(sptr), cconf->name);
791         return 0;
792       }
793
794   /*
795    * Notify all operators about remote connect requests
796    */
797   if (!IsAnOper(cptr))
798   {
799     sendto_ops_butone(NULL, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
800         me.name, parv[1], parv[2] ? parv[2] : "", get_client_name(sptr, FALSE));
801 #if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
802     syslog(LOG_DEBUG,
803         "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
804 #endif
805   }
806   aconf->port = port;
807   switch (retval = connect_server(aconf, sptr, NULL))
808   {
809     case 0:
810       if (MyUser(sptr) || Protocol(cptr) < 10)
811         sendto_one(sptr,
812             ":%s NOTICE %s :*** Connecting to %s[%s].",
813             me.name, parv[0], aconf->host, aconf->name);
814       else
815         sendto_one(sptr,
816             "%s NOTICE %s%s :*** Connecting to %s[%s].",
817             NumServ(&me), NumNick(sptr), aconf->host, aconf->name);
818       break;
819     case -1:
820       /* Comments already sent */
821       break;
822     case -2:
823       if (MyUser(sptr) || Protocol(cptr) < 10)
824         sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
825             me.name, parv[0], aconf->host);
826       else
827         sendto_one(sptr, "%s NOTICE %s%s :*** Host %s is unknown.",
828             NumServ(&me), NumNick(sptr), aconf->host);
829       break;
830     default:
831       if (MyUser(sptr) || Protocol(cptr) < 10)
832         sendto_one(sptr,
833             ":%s NOTICE %s :*** Connection to %s failed: %s",
834             me.name, parv[0], aconf->host, strerror(retval));
835       else
836         sendto_one(sptr,
837             "%s NOTICE %s%s :*** Connection to %s failed: %s",
838             NumServ(&me), NumNick(sptr), aconf->host, strerror(retval));
839   }
840   aconf->port = tmpport;
841   return 0;
842 }
843
844 /*
845  * m_wallops
846  *
847  * Writes to all +w users currently online
848  *
849  * parv[0] = sender prefix
850  * parv[1] = message text
851  */
852 int m_wallops(aClient *cptr, aClient *sptr, int parc, char *parv[])
853 {
854   char *message;
855
856   message = parc > 1 ? parv[1] : NULL;
857
858   if (BadPtr(message))
859   {
860     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "WALLOPS");
861     return 0;
862   }
863
864   if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
865   {
866     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
867     return 0;
868   }
869   sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
870       ":%s WALLOPS :%s", parv[0], message);
871   return 0;
872 }
873
874 /*
875  * m_time
876  *
877  * parv[0] = sender prefix
878  * parv[1] = servername
879  */
880 int m_time(aClient *cptr, aClient *sptr, int parc, char *parv[])
881 {
882   if (hunt_server(0, cptr, sptr, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
883     sendto_one(sptr, rpl_str(RPL_TIME), me.name,
884         parv[0], me.name, TStime(), TSoffset, date((long)0));
885   return 0;
886 }
887
888 /*
889  * m_settime
890  *
891  * parv[0] = sender prefix
892  * parv[1] = new time
893  * parv[2] = servername (Only used when sptr is an Oper).
894  */
895 int m_settime(aClient *cptr, aClient *sptr, int parc, char *parv[])
896 {
897   time_t t;
898   long int dt;
899   static char tbuf[11];
900   Dlink *lp;
901
902   if (!IsPrivileged(sptr))
903     return 0;
904
905   if (parc < 2)
906   {
907     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SETTIME");
908     return 0;
909   }
910
911   if (parc == 2 && MyUser(sptr))
912     parv[parc++] = me.name;
913
914   t = atoi(parv[1]);
915   dt = TStime() - t;
916
917   if (t < 779557906 || dt < -9000000)
918   {
919     sendto_one(sptr, ":%s NOTICE %s :SETTIME: Bad value", me.name, parv[0]);
920     return 0;
921   }
922
923   if (IsServer(sptr))           /* send to unlagged servers */
924   {
925 #ifdef RELIABLE_CLOCK
926     sprintf_irc(tbuf, TIME_T_FMT, TStime());
927     parv[1] = tbuf;
928 #endif
929     for (lp = me.serv->down; lp; lp = lp->next)
930       if (cptr != lp->value.cptr && DBufLength(&lp->value.cptr->sendQ) < 8000)
931         sendto_one(lp->value.cptr, ":%s SETTIME %s", parv[0], parv[1]);
932   }
933   else
934   {
935     sprintf_irc(tbuf, TIME_T_FMT, TStime());
936     parv[1] = tbuf;
937     if (hunt_server(1, cptr, sptr, ":%s SETTIME %s %s", 2, parc, parv) !=
938         HUNTED_ISME)
939       return 0;
940   }
941
942 #ifdef RELIABLE_CLOCK
943   if ((dt > 600) || (dt < -600))
944     sendto_serv_butone((aClient *)NULL,
945         ":%s WALLOPS :Bad SETTIME from %s: " TIME_T_FMT, me.name, sptr->name,
946         t);
947   if (IsUser(sptr))
948   {
949     if (MyUser(sptr) || Protocol(cptr) < 10)
950       sendto_one(sptr, ":%s NOTICE %s :clock is not set %ld seconds %s : "
951           "RELIABLE_CLOCK is defined", me.name, parv[0],
952           (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
953     else
954       sendto_one(sptr, "%s NOTICE %s%s :clock is not set %ld seconds %s : "
955           "RELIABLE_CLOCK is defined", NumServ(&me), NumNick(sptr),
956           (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
957   }
958 #else
959   sendto_ops("SETTIME from %s, clock is set %ld seconds %s",
960       get_client_name(sptr, FALSE), (dt < 0) ? -dt : dt,
961       (dt < 0) ? "forwards" : "backwards");
962   TSoffset -= dt;
963   if (IsUser(sptr))
964   {
965     if (MyUser(sptr) || Protocol(cptr) < 10)
966       sendto_one(sptr, ":%s NOTICE %s :clock is set %ld seconds %s", me.name,
967           parv[0], (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
968     else
969       sendto_one(sptr, "%s NOTICE %s%s :clock is set %ld seconds %s",
970           NumServ(&me), NumNick(sptr),
971           (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
972   }
973 #endif
974   return 0;
975 }
976
977 static char *militime(char *sec, char *usec)
978 {
979   struct timeval tv;
980   static char timebuf[18];
981
982   gettimeofday(&tv, NULL);
983   if (sec && usec)
984 #if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
985     sprintf(timebuf, "%ld",
986         (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
987 #else
988     sprintf_irc(timebuf, "%d",
989         (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
990 #endif
991   else
992 #if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
993     sprintf(timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
994 #else
995     sprintf_irc(timebuf, "%d %d", tv.tv_sec, tv.tv_usec);
996 #endif
997   return timebuf;
998 }
999
1000 /*
1001  * m_rping  -- by Run
1002  *
1003  *    parv[0] = sender (sptr->name thus)
1004  * if sender is a person: (traveling towards start server)
1005  *    parv[1] = pinged server[mask]
1006  *    parv[2] = start server (current target)
1007  *    parv[3] = optional remark
1008  * if sender is a server: (traveling towards pinged server)
1009  *    parv[1] = pinged server (current target)
1010  *    parv[2] = original sender (person)
1011  *    parv[3] = start time in s
1012  *    parv[4] = start time in us
1013  *    parv[5] = the optional remark
1014  */
1015 int m_rping(aClient *cptr, aClient *sptr, int parc, char *parv[])
1016 {
1017   aClient *acptr;
1018
1019   if (!IsPrivileged(sptr))
1020     return 0;
1021
1022   if (parc < (IsAnOper(sptr) ? (MyConnect(sptr) ? 2 : 3) : 6))
1023   {
1024     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RPING");
1025     return 0;
1026   }
1027   if (MyUser(sptr))
1028   {
1029     if (parc == 2)
1030       parv[parc++] = me.name;
1031     else if (!(acptr = find_match_server(parv[2])))
1032     {
1033       parv[3] = parv[2];
1034       parv[2] = me.name;
1035       parc++;
1036     }
1037     else
1038       parv[2] = acptr->name;
1039     if (parc == 3)
1040       parv[parc++] = "<No client start time>";
1041   }
1042
1043   if (IsAnOper(sptr))
1044   {
1045     if (hunt_server(1, cptr, sptr, ":%s RPING %s %s :%s", 2, parc, parv) !=
1046         HUNTED_ISME)
1047       return 0;
1048     if (!(acptr = find_match_server(parv[1])) || !IsServer(acptr))
1049     {
1050       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
1051       return 0;
1052     }
1053     if (Protocol(acptr->from) < 10)
1054       sendto_one(acptr, ":%s RPING %s %s %s :%s",
1055           me.name, acptr->name, sptr->name, militime(NULL, NULL), parv[3]);
1056     else
1057       sendto_one(acptr, ":%s RPING %s %s %s :%s",
1058           me.name, NumServ(acptr), sptr->name, militime(NULL, NULL), parv[3]);
1059   }
1060   else
1061   {
1062     if (hunt_server(1, cptr, sptr, ":%s RPING %s %s %s %s :%s", 1, parc, parv)
1063         != HUNTED_ISME)
1064       return 0;
1065     sendto_one(cptr, ":%s RPONG %s %s %s %s :%s", me.name, parv[0],
1066         parv[2], parv[3], parv[4], parv[5]);
1067   }
1068   return 0;
1069 }
1070
1071 /*
1072  * m_rpong  -- by Run too :)
1073  *
1074  * parv[0] = sender prefix
1075  * parv[1] = from pinged server: start server; from start server: sender
1076  * parv[2] = from pinged server: sender; from start server: pinged server
1077  * parv[3] = pingtime in ms
1078  * parv[4] = client info (for instance start time)
1079  */
1080 int m_rpong(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
1081 {
1082   aClient *acptr;
1083
1084   if (!IsServer(sptr))
1085     return 0;
1086
1087   if (parc < 5)
1088   {
1089     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RPING");
1090     return 0;
1091   }
1092
1093   if (!(acptr = FindClient(parv[1])))
1094     return 0;
1095
1096   if (!IsMe(acptr))
1097   {
1098     if (IsServer(acptr) && parc > 5)
1099     {
1100       sendto_one(acptr, ":%s RPONG %s %s %s %s :%s",
1101           parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
1102       return 0;
1103     }
1104   }
1105   else
1106   {
1107     parv[1] = parv[2];
1108     parv[2] = sptr->name;
1109     parv[0] = me.name;
1110     parv[3] = militime(parv[3], parv[4]);
1111     parv[4] = parv[5];
1112     if (!(acptr = FindUser(parv[1])))
1113       return 0;                 /* No bouncing between servers ! */
1114   }
1115
1116   sendto_one(acptr, ":%s RPONG %s %s %s :%s",
1117       parv[0], parv[1], parv[2], parv[3], parv[4]);
1118   return 0;
1119 }
1120
1121 #if defined(OPER_REHASH) || defined(LOCOP_REHASH)
1122 /*
1123  * m_rehash
1124  */
1125 int m_rehash(aClient *cptr, aClient *sptr, int parc, char *parv[])
1126 {
1127 #ifndef LOCOP_REHASH
1128   if (!MyUser(sptr) || !IsOper(sptr))
1129 #else
1130 #ifdef  OPER_REHASH
1131   if (!MyUser(sptr) || !IsAnOper(sptr))
1132 #else
1133   if (!MyUser(sptr) || !IsLocOp(sptr))
1134 #endif
1135 #endif
1136   {
1137     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1138     return 0;
1139   }
1140   sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
1141   sendto_ops("%s is rehashing Server config file", parv[0]);
1142 #ifdef USE_SYSLOG
1143   syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
1144 #endif
1145   return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
1146 }
1147 #endif
1148
1149 #if defined(OPER_RESTART) || defined(LOCOP_RESTART)
1150 /*
1151  * m_restart
1152  */
1153 int m_restart(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc),
1154     char *parv[])
1155 {
1156 #ifndef LOCOP_RESTART
1157   if (!MyUser(sptr) || !IsOper(sptr))
1158 #else
1159 #ifdef  OPER_RESTART
1160   if (!MyUser(sptr) || !IsAnOper(sptr))
1161 #else
1162   if (!MyUser(sptr) || !IsLocOp(sptr))
1163 #endif
1164 #endif
1165   {
1166     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1167     return 0;
1168   }
1169 #ifdef USE_SYSLOG
1170   syslog(LOG_WARNING, "Server RESTART by %s\n", get_client_name(sptr, FALSE));
1171 #endif
1172   server_reboot();
1173   return 0;
1174 }
1175 #endif
1176
1177 /*
1178  * m_trace
1179  *
1180  * parv[0] = sender prefix
1181  * parv[1] = nick or servername
1182  * parv[2] = 'target' servername
1183  */
1184 int m_trace(aClient *cptr, aClient *sptr, int parc, char *parv[])
1185 {
1186   Reg1 int i;
1187   Reg2 aClient *acptr;
1188   aConfClass *cltmp;
1189   char *tname;
1190   int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
1191   int cnt = 0, wilds, dow;
1192
1193   if (parc < 2 || BadPtr(parv[1]))
1194   {
1195     /* just "TRACE" without parameters. Must be from local client */
1196     parc = 1;
1197     acptr = &me;
1198     tname = me.name;
1199     i = HUNTED_ISME;
1200   }
1201   else if (parc < 3 || BadPtr(parv[2]))
1202   {
1203     /* No target specified. Make one before propagating. */
1204     parc = 2;
1205     tname = parv[1];
1206     if ((acptr = find_match_server(parv[1])) ||
1207         ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
1208     {
1209       if (IsUser(acptr))
1210         parv[2] = acptr->user->server->name;
1211       else
1212         parv[2] = acptr->name;
1213       parc = 3;
1214       parv[3] = NULL;
1215       if ((i = hunt_server(IsServer(acptr), cptr, sptr,
1216           ":%s TRACE %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
1217         return 0;
1218     }
1219     else
1220       i = HUNTED_ISME;
1221   }
1222   else
1223   {
1224     /* Got "TRACE <tname> :<target>" */
1225     parc = 3;
1226     if (MyUser(sptr) || Protocol(cptr) < 10)
1227       acptr = find_match_server(parv[2]);
1228     else
1229       acptr = FindNServer(parv[2]);
1230     if ((i = hunt_server(0, cptr, sptr,
1231         ":%s TRACE %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
1232       return 0;
1233     tname = parv[1];
1234   }
1235
1236   if (i == HUNTED_PASS)
1237   {
1238     if (!acptr)
1239       acptr = next_client(client, tname);
1240     else
1241       acptr = acptr->from;
1242     sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
1243 #ifndef GODMODE
1244         version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
1245 #else /* GODMODE */
1246         version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
1247         (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
1248 #endif /* GODMODE */
1249     return 0;
1250   }
1251
1252   doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
1253   wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
1254   dow = wilds || doall;
1255
1256   /* Don't give (long) remote listings to lusers */
1257   if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
1258     return 0;
1259
1260   for (i = 0; i < MAXCONNECTIONS; i++)
1261     link_s[i] = 0, link_u[i] = 0;
1262
1263   if (doall)
1264   {
1265     for (acptr = client; acptr; acptr = acptr->next)
1266       if (IsUser(acptr))
1267         link_u[acptr->from->fd]++;
1268       else if (IsServer(acptr))
1269         link_s[acptr->from->fd]++;
1270   }
1271
1272   /* report all direct connections */
1273
1274   for (i = 0; i <= highest_fd; i++)
1275   {
1276     char *name;
1277     unsigned int conClass;
1278
1279     if (!(acptr = loc_clients[i]))      /* Local Connection? */
1280       continue;
1281     if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
1282         !IsAnOper(acptr) && (acptr != sptr))
1283       continue;
1284     if (!doall && wilds && match(tname, acptr->name))
1285       continue;
1286     if (!dow && strCasediff(tname, acptr->name))
1287       continue;
1288     name = get_client_name(acptr, FALSE);
1289     conClass = get_client_class(acptr);
1290
1291     switch (acptr->status)
1292     {
1293       case STAT_CONNECTING:
1294         sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
1295             me.name, parv[0], conClass, name);
1296         cnt++;
1297         break;
1298       case STAT_HANDSHAKE:
1299         sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
1300             me.name, parv[0], conClass, name);
1301         cnt++;
1302         break;
1303       case STAT_ME:
1304         break;
1305       case STAT_UNKNOWN:
1306       case STAT_UNKNOWN_USER:
1307       case STAT_UNKNOWN_SERVER:
1308         sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
1309             me.name, parv[0], conClass, name);
1310         cnt++;
1311         break;
1312       case STAT_USER:
1313         /* Only opers see users if there is a wildcard
1314            but anyone can see all the opers. */
1315         if ((IsAnOper(sptr) && (MyUser(sptr) ||
1316             !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
1317         {
1318           if (IsAnOper(acptr))
1319             sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
1320                 me.name, parv[0], conClass, name, now - acptr->lasttime);
1321           else
1322             sendto_one(sptr, rpl_str(RPL_TRACEUSER),
1323                 me.name, parv[0], conClass, name, now - acptr->lasttime);
1324           cnt++;
1325         }
1326         break;
1327         /*
1328          * Connection is a server
1329          *
1330          * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
1331          *
1332          * class        Class the server is in
1333          * nS           Number of servers reached via this link
1334          * nC           Number of clients reached via this link
1335          * name         Name of the server linked
1336          * ConnBy       Who established this link
1337          * last         Seconds since we got something from this link
1338          * age          Seconds this link has been alive
1339          *
1340          * Additional comments etc......        -Cym-<cym@acrux.net>
1341          */
1342
1343       case STAT_SERVER:
1344         if (acptr->serv->user)
1345           sendto_one(sptr, rpl_str(RPL_TRACESERVER),
1346               me.name, parv[0], conClass, link_s[i],
1347               link_u[i], name, acptr->serv->by,
1348               acptr->serv->user->username,
1349               acptr->serv->user->host,
1350               now - acptr->lasttime, now - acptr->serv->timestamp);
1351         else
1352           sendto_one(sptr, rpl_str(RPL_TRACESERVER),
1353               me.name, parv[0], conClass, link_s[i],
1354               link_u[i], name, *(acptr->serv->by) ?
1355               acptr->serv->by : "*", "*", me.name,
1356               now - acptr->lasttime, now - acptr->serv->timestamp);
1357         cnt++;
1358         break;
1359       case STAT_LOG:
1360         sendto_one(sptr, rpl_str(RPL_TRACELOG),
1361             me.name, parv[0], LOGFILE, acptr->port);
1362         cnt++;
1363         break;
1364       case STAT_PING:
1365         sendto_one(sptr, rpl_str(RPL_TRACEPING), me.name,
1366             parv[0], name, (acptr->acpt) ? acptr->acpt->name : "<null>");
1367         break;
1368       default:                  /* We actually shouldn't come here, -msa */
1369         sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0], name);
1370         cnt++;
1371         break;
1372     }
1373   }
1374   /*
1375    * Add these lines to summarize the above which can get rather long
1376    * and messy when done remotely - Avalon
1377    */
1378   if (!IsAnOper(sptr) || !cnt)
1379   {
1380     if (!cnt)
1381       /* let the user have some idea that its at the end of the trace */
1382       sendto_one(sptr, rpl_str(RPL_TRACESERVER),
1383           me.name, parv[0], 0, link_s[me.fd],
1384           link_u[me.fd], "<No_match>", *(me.serv->by) ?
1385           me.serv->by : "*", "*", me.name, 0, 0);
1386     return 0;
1387   }
1388   for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
1389     if (Links(cltmp) > 0)
1390       sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
1391           parv[0], ConClass(cltmp), Links(cltmp));
1392   return 0;
1393 }
1394
1395 /*
1396  *  m_close                              - added by Darren Reed Jul 13 1992.
1397  */
1398 int m_close(aClient *cptr, aClient *sptr, int UNUSED(parc), char *parv[])
1399 {
1400   Reg1 aClient *acptr;
1401   Reg2 int i;
1402   int closed = 0;
1403
1404   if (!MyOper(sptr))
1405   {
1406     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1407     return 0;
1408   }
1409
1410   for (i = highest_fd; i; i--)
1411   {
1412     if (!(acptr = loc_clients[i]))
1413       continue;
1414     if (!IsUnknown(acptr) && !IsConnecting(acptr) && !IsHandshake(acptr))
1415       continue;
1416     sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
1417         get_client_name(acptr, TRUE), acptr->status);
1418     exit_client(cptr, acptr, &me, "Oper Closing");
1419     closed++;
1420   }
1421   sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
1422   return 0;
1423 }
1424
1425 #if defined(OPER_DIE) || defined(LOCOP_DIE)
1426 /*
1427  * m_die
1428  */
1429 int m_die(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
1430 {
1431   Reg1 aClient *acptr;
1432   Reg2 int i;
1433
1434 #ifndef LOCOP_DIE
1435   if (!MyUser(sptr) || !IsOper(sptr))
1436 #else
1437 #ifdef  OPER_DIE
1438   if (!MyUser(sptr) || !IsAnOper(sptr))
1439 #else
1440   if (!MyUser(sptr) || !IsLocOp(sptr))
1441 #endif
1442 #endif
1443   {
1444     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1445     return 0;
1446   }
1447
1448   for (i = 0; i <= highest_fd; i++)
1449   {
1450     if (!(acptr = loc_clients[i]))
1451       continue;
1452     if (IsUser(acptr))
1453       sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s",
1454           me.name, acptr->name, get_client_name(sptr, TRUE));
1455     else if (IsServer(acptr))
1456       sendto_one(acptr, ":%s ERROR :Terminated by %s",
1457           me.name, get_client_name(sptr, TRUE));
1458   }
1459 #ifdef __cplusplus
1460   s_die(0);
1461 #else
1462   s_die();
1463 #endif
1464   return 0;
1465 }
1466 #endif
1467
1468 static void add_gline(aClient *sptr, int ip_mask, char *host, char *comment,
1469     char *user, time_t expire, int local)
1470 {
1471   aClient *acptr;
1472   aGline *agline;
1473   int fd,gtype=0;
1474
1475 #ifdef WT_BADCHAN
1476   if(*host=='#')
1477     gtype=1;    /* BAD CHANNEL */
1478 #endif
1479   /* Inform ops */
1480   sendto_op_mask(SNO_GLINE,
1481       "%s adding %s%s for %s@%s, expiring at " TIME_T_FMT ": %s", sptr->name,
1482       local ? "local " : "",
1483       gtype ? "BADCHAN":"GLINE", user, host, expire, comment);
1484
1485 #ifdef GPATH
1486   write_log(GPATH,
1487       "# " TIME_T_FMT " %s adding %s %s for %s@%s, expiring at " TIME_T_FMT
1488       ": %s\n", TStime(), sptr->name, local ? "local" : "global",
1489       gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
1490
1491   /* this can be inserted into the conf */
1492   if(!gtype)
1493     write_log(GPATH, "%c:%s:%s:%s\n", ip_mask ? 'k' : 'K', host, comment, 
1494       user);
1495 #endif /* GPATH */
1496
1497   agline = make_gline(ip_mask, host, comment, user, expire);
1498   if (local)
1499     SetGlineIsLocal(agline);
1500
1501 #ifdef WT_BADCHAN
1502   if(gtype) return;
1503 #endif
1504
1505   for (fd = highest_fd; fd >= 0; --fd)  /* get the users! */
1506     if ((acptr = loc_clients[fd]) && !IsMe(acptr))
1507     {
1508
1509       if (!acptr->user || strlen(acptr->sockhost) > (size_t)HOSTLEN ||
1510           (acptr->user->username ? strlen(acptr->user->username) : 0) >
1511           (size_t)HOSTLEN)
1512         continue;               /* these tests right out of
1513                                    find_kill for safety's sake */
1514
1515       if ((GlineIsIpMask(agline) ?
1516           match(agline->host, inetntoa(acptr->ip)) :
1517           match(agline->host, acptr->sockhost)) == 0 &&
1518           (!acptr->user->username ||
1519           match(agline->name, acptr->user->username) == 0))
1520       {
1521
1522         /* ok, he was the one that got G-lined */
1523         sendto_one(acptr, ":%s %d %s :*** %s.", me.name,
1524             ERR_YOUREBANNEDCREEP, acptr->name, agline->reason);
1525
1526         /* let the ops know about my first kill */
1527         sendto_op_mask(SNO_GLINE, "G-line active for %s",
1528             get_client_name(acptr, FALSE));
1529
1530         /* and get rid of him */
1531         if (sptr != acptr)
1532           exit_client(sptr->from, acptr, &me, "G-lined");
1533       }
1534     }
1535 }
1536
1537 /*
1538  * m_gline
1539  *
1540  * parv[0] = Send prefix
1541  *
1542  * From server:
1543  *
1544  * parv[1] = Target: server numeric
1545  * parv[2] = [+|-]<G-line mask>
1546  * parv[3] = Expiration offset
1547  * parv[4] = Comment
1548  *
1549  * From client:
1550  *
1551  * parv[1] = [+|-]<G-line mask>
1552  * parv[2] = Expiration offset
1553  * parv[3] = Comment
1554  *
1555  */
1556 int m_gline(aClient *cptr, aClient *sptr, int parc, char *parv[])
1557 {
1558   aClient *acptr = NULL;        /* Init. to avoid compiler warning. */
1559
1560   aGline *agline, *a2gline;
1561   char *user, *host;
1562   int active, ip_mask,gtype = 0;
1563   time_t expire = 0;
1564
1565   /* Remove expired G-lines */
1566   for (agline = gline, a2gline = NULL; agline; agline = agline->next)
1567   {
1568     if (agline->expire <= TStime())
1569     {
1570       free_gline(agline, a2gline);
1571       agline = a2gline ? a2gline : gline;
1572       if (!agline)
1573         break;
1574       continue;
1575     }
1576     a2gline = agline;
1577   }
1578
1579 #ifdef WT_BADCHAN
1580   /* Remove expired bad channels */
1581   for (agline = badchan, a2gline = NULL; agline; agline = agline->next)
1582   {
1583     if (agline->expire <= TStime())
1584     {
1585       free_gline(agline, a2gline);
1586       agline = a2gline ? a2gline : badchan;
1587       if (!agline)
1588         break;
1589       continue;
1590     }
1591     a2gline = agline;
1592   }
1593 #endif
1594
1595
1596   if (IsServer(cptr))
1597   {
1598     if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
1599     {
1600       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
1601       {
1602         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
1603             "GLINE");
1604         return 0;
1605       }
1606
1607       if (*parv[2] == '-')      /* add mode or delete mode? */
1608         active = 0;
1609       else
1610         active = 1;
1611
1612       if (*parv[2] == '+' || *parv[2] == '-')
1613         parv[2]++;              /* step past mode indicator */
1614
1615       /* forward the message appropriately */
1616       if (!strCasediff(parv[1], "*"))   /* global! */
1617         sendto_serv_butone(cptr, active ? ":%s GLINE %s +%s %s :%s" :
1618             ":%s GLINE %s -%s", parv[0], parv[1], parv[2], parv[3], parv[4]);
1619       else if ((
1620 #if 1
1621           /*
1622            * REMOVE THIS after all servers upgraded to 2.10.01 and
1623            * Uworld uses a numeric too
1624            */
1625           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
1626           (strlen(parv[1]) == 1 &&
1627 #endif
1628           !(acptr = FindNServer(parv[1]))))
1629         return 0;               /* no such server/user exists; forget it */
1630       else
1631 #if 1
1632 /*
1633  * REMOVE THIS after all servers upgraded to 2.10.01 and
1634  * Uworld uses a numeric too
1635  */
1636       if (IsServer(acptr) || !MyConnect(acptr))
1637 #endif
1638       {
1639         sendto_one(acptr, active ? ":%s GLINE %s +%s %s :%s" :
1640             ":%s GLINE %s -%s", parv[0], parv[1], parv[2], parv[3], parv[4]);   /* single destination */
1641         return 0;               /* only the intended  destination
1642                                    should add this gline */
1643       }
1644
1645       if (!(host = strchr(parv[2], '@')))
1646       {                         /* convert user@host */
1647         user = "*";             /* no @'s; assume username is '*' */
1648         host = parv[2];
1649       }
1650       else
1651       {
1652         user = parv[2];
1653         *(host++) = '\0';       /* break up string at the '@' */
1654       }
1655       ip_mask = check_if_ipmask(host);  /* Store this boolean */
1656 #ifdef WT_BADCHAN
1657       if(*host == '#') gtype=1;         /* BAD CHANNEL GLINE */
1658 #endif
1659
1660       for (agline = (gtype)?badchan:gline, a2gline = NULL; agline; 
1661            agline = agline->next)
1662       {
1663         if (!strCasediff(agline->name, user)
1664             && !strCasediff(agline->host, host))
1665           break;
1666         a2gline = agline;
1667       }
1668
1669       if (!active && agline)
1670       {                         /* removing the gline */
1671         /* notify opers */
1672         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
1673             gtype?"BADCHAN":"GLINE",agline->name, agline->host);
1674
1675 #ifdef GPATH
1676         write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
1677             TStime(), parv[0], gtype?"BADCHAN":"GLINE",agline->name, 
1678             agline->host);
1679 #endif /* GPATH */
1680
1681         free_gline(agline, a2gline);    /* remove the gline */
1682       }
1683       else if (active)
1684       {                         /* must be adding a gline */
1685         expire = atoi(parv[3]) + TStime();      /* expire time? */
1686         if (agline && agline->expire < expire)
1687         {                       /* new expire time? */
1688           /* yes, notify the opers */
1689           sendto_op_mask(SNO_GLINE,
1690               "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1691               parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host, 
1692               expire);
1693
1694 #ifdef GPATH
1695           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
1696               "on %s for %s@%s to " TIME_T_FMT "\n",
1697               TStime(), parv[0], gtype?"BADCHAN":"GLINE",
1698                agline->name, agline->host, expire);
1699 #endif /* GPATH */
1700
1701           agline->expire = expire;      /* reset the expire time */
1702         }
1703         else if (!agline)
1704         {                       /* create gline */
1705           for (agline = gtype?badchan:gline; agline; agline = agline->next)
1706             if (!mmatch(agline->name, user) &&
1707                 (ip_mask ? GlineIsIpMask(agline) : !GlineIsIpMask(agline)) &&
1708                 !mmatch(agline->host, host))
1709               return 0;         /* found an existing G-line that matches */
1710
1711           /* add the line: */
1712           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
1713         }
1714       }
1715     }
1716   }
1717   else if (parc < 2 || *parv[1] == '\0')
1718   {
1719     /* Not enough args and a user; list glines */
1720     for (agline = gline; agline; agline = agline->next)
1721       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
1722           agline->name, agline->host, agline->expire, agline->reason,
1723           GlineIsActive(agline) ? (GlineIsLocal(agline) ? " (local)" : "") :
1724           " (Inactive)");
1725     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1726   }
1727   else
1728   {
1729     int priv;
1730
1731 #ifdef LOCOP_LGLINE
1732     priv = IsAnOper(cptr);
1733 #else
1734     priv = IsOper(cptr);
1735 #endif
1736
1737     if (priv)
1738     {                           /* non-oper not permitted to change things */
1739       if (*parv[1] == '-')
1740       {                         /* oper wants to deactivate the gline */
1741         active = 0;
1742         parv[1]++;
1743       }
1744       else if (*parv[1] == '+')
1745       {                         /* oper wants to activate inactive gline */
1746         active = 1;
1747         parv[1]++;
1748       }
1749       else
1750         active = -1;
1751
1752       if (parc > 2)
1753         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
1754                                                    expire TS */
1755     }
1756     else
1757       active = -1;
1758
1759     if (!(host = strchr(parv[1], '@')))
1760     {
1761       user = "*";               /* no @'s; assume username is '*' */
1762       host = parv[1];
1763     }
1764     else
1765     {
1766       user = parv[1];
1767       *(host++) = '\0';         /* break up string at the '@' */
1768     }
1769     ip_mask = check_if_ipmask(host);    /* Store this boolean */
1770 #ifdef WT_BADCHAN
1771     if(*host == '#')
1772 #ifndef WT_LOCAL_BADCHAN
1773      return 0;
1774 #else
1775      gtype=1;   /* BAD CHANNEL */
1776 #endif
1777 #endif
1778
1779     for (agline = gtype?badchan:gline, a2gline = NULL; agline; 
1780       agline = agline->next)
1781     {
1782       if (!mmatch(agline->name, user) &&
1783           (ip_mask ? GlineIsIpMask(agline) : !GlineIsIpMask(agline)) &&
1784           !mmatch(agline->host, host))
1785         break;
1786       a2gline = agline;
1787     }
1788
1789     if (!agline)
1790     {
1791 #ifdef OPER_LGLINE
1792       if (priv && active && expire > now)
1793       {
1794         /* Add local G-line */
1795         if (parc < 4 || !strchr(parv[3], ' '))
1796         {
1797           sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
1798               me.name, parv[0], "GLINE");
1799           return 0;
1800         }
1801         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
1802       }
1803       else
1804 #endif
1805         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
1806             host);
1807
1808       return 0;
1809     }
1810
1811     if (expire <= agline->expire)
1812       expire = 0;
1813
1814     if ((active == -1 ||
1815         (active ? GlineIsActive(agline) : !GlineIsActive(agline))) &&
1816         expire == 0)
1817     {
1818       /* oper wants a list of one gline only */
1819       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], agline->name,
1820           agline->host, agline->expire, agline->reason,
1821           GlineIsActive(agline) ? "" : " (Inactive)");
1822       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1823       return 0;
1824     }
1825
1826     if (active != -1 &&
1827         (active ? !GlineIsActive(agline) : GlineIsActive(agline)))
1828     {
1829       if (active)               /* reset activation on gline */
1830         SetActive(agline);
1831 #ifdef OPER_LGLINE
1832       else if (GlineIsLocal(agline))
1833       {
1834         /* Remove local G-line */
1835         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
1836             parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host);
1837 #ifdef GPATH
1838         write_log(GPATH, "# " TIME_T_FMT
1839             " %s!%s@%s removed local %s for %s@%s\n",
1840             TStime(), parv[0], cptr->user->username, cptr->user->host,
1841             gtype?"BADCHAN":"GLINE",
1842             agline->name, agline->host);
1843 #endif /* GPATH */
1844         free_gline(agline, a2gline);    /* remove the gline */
1845         return 0;
1846       }
1847 #endif
1848       else
1849         ClearActive(agline);
1850     }
1851     else
1852       active = -1;              /* for later sendto_ops and logging functions */
1853
1854     if (expire)
1855       agline->expire = expire;  /* reset expiration time */
1856
1857     /* inform the operators what's up */
1858     if (active != -1)
1859     {                           /* changing the activation */
1860       sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
1861           "%s %sactivating %s for %s@%s and "
1862           "resetting expiration time to " TIME_T_FMT,
1863           parv[0], active ? "re" : "de", gtype?"BADCHAN":"GLINE",agline->name,
1864           agline->host, agline->expire);
1865 #ifdef GPATH
1866       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
1867           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
1868           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
1869           TStime(), parv[0], cptr->user->username, cptr->user->host,
1870           active ? "re" : "de", gtype?"BADCHAN":"GLINE",agline->name, 
1871           agline->host, agline->expire);
1872 #endif /* GPATH */
1873
1874     }
1875     else if (expire)
1876     {                           /* changing only the expiration */
1877       sendto_op_mask(SNO_GLINE,
1878           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1879           parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host, 
1880           agline->expire);
1881 #ifdef GPATH
1882       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
1883           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
1884           cptr->user->username, cptr->user->host,gtype?"BADCHAN":"GLINE",
1885           agline->name, agline->host, agline->expire);
1886 #endif /* GPATH */
1887     }
1888   }
1889
1890   return 0;
1891 }