2 * IRC - Internet Relay Chat, ircd/m_trace.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
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)
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.
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.
27 * m_functions execute protocol messages on this server:
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...).
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.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
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 ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
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*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
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
94 #include "ircd_reply.h"
95 #include "ircd_string.h"
110 * m_trace - generic message handler
112 * parv[0] = sender prefix
113 * parv[1] = nick or servername
114 * parv[2] = 'target' servername
116 int m_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
119 struct Client *acptr;
120 struct ConfClass *cltmp;
122 int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
123 int cnt = 0, wilds, dow;
125 if (parc < 2 || BadPtr(parv[1]))
127 /* just "TRACE" without parameters. Must be from local client */
133 else if (parc < 3 || BadPtr(parv[2]))
135 /* No target specified. Make one before propagating. */
138 if ((acptr = find_match_server(parv[1])) ||
139 ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
142 parv[2] = acptr->user->server->name;
144 parv[2] = acptr->name;
147 if ((i = hunt_server(IsServer(acptr), cptr, sptr,
148 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
156 /* Got "TRACE <tname> :<target>" */
158 if (MyUser(sptr) || Protocol(cptr) < 10)
159 acptr = find_match_server(parv[2]);
161 acptr = FindNServer(parv[2]);
162 if ((i = hunt_server(0, cptr, sptr,
163 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
168 if (i == HUNTED_PASS)
171 acptr = next_client(GlobalClientList, tname);
174 sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
176 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
178 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
179 (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
184 doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : 1;
185 wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
186 dow = wilds || doall;
188 /* Don't give (long) remote listings to lusers */
189 if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
192 for (i = 0; i < MAXCONNECTIONS; i++)
193 link_s[i] = 0, link_u[i] = 0;
197 for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
199 link_u[acptr->from->fd]++;
200 else if (IsServer(acptr))
201 link_s[acptr->from->fd]++;
205 /* report all direct connections */
207 for (i = 0; i <= HighestFd; i++)
209 unsigned int conClass;
211 if (!(acptr = LocalClientArray[i])) /* Local Connection? */
213 if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
214 !IsAnOper(acptr) && (acptr != sptr))
216 if (!doall && wilds && match(tname, acptr->name))
218 if (!dow && 0 != ircd_strcmp(tname, acptr->name))
221 conClass = get_client_class(acptr);
223 switch (acptr->status)
225 case STAT_CONNECTING:
226 sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
227 me.name, parv[0], conClass, acptr->name);
231 sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
232 me.name, parv[0], conClass, acptr->name);
238 case STAT_UNKNOWN_USER:
239 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
240 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP));
243 case STAT_UNKNOWN_SERVER:
244 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
245 me.name, parv[0], conClass, "Unknown Server");
249 /* Only opers see users if there is a wildcard
250 but anyone can see all the opers. */
251 if ((IsAnOper(sptr) && (MyUser(sptr) ||
252 !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
255 sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
256 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
257 CurrentTime - acptr->lasttime);
259 sendto_one(sptr, rpl_str(RPL_TRACEUSER),
260 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
261 CurrentTime - acptr->lasttime);
266 * Connection is a server
268 * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
270 * class Class the server is in
271 * nS Number of servers reached via this link
272 * nC Number of clients reached via this link
273 * name Name of the server linked
274 * ConnBy Who established this link
275 * last Seconds since we got something from this link
276 * age Seconds this link has been alive
278 * Additional comments etc...... -Cym-<cym@acrux.net>
282 if (acptr->serv->user)
283 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
284 me.name, parv[0], conClass, link_s[i],
285 link_u[i], acptr->name,
286 (*acptr->serv->by) ? acptr->serv->by : "*",
287 acptr->serv->user->username, acptr->serv->user->host,
288 CurrentTime - acptr->lasttime,
289 CurrentTime - acptr->serv->timestamp);
291 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
292 me.name, parv[0], conClass, link_s[i],
293 link_u[i], acptr->name,
294 (*acptr->serv->by) ? acptr->serv->by : "*", "*",
295 me.name, CurrentTime - acptr->lasttime,
296 CurrentTime - acptr->serv->timestamp);
299 default: /* We actually shouldn't come here, -msa */
300 sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0],
301 get_client_name(acptr, HIDE_IP));
307 * Add these lines to summarize the above which can get rather long
308 * and messy when done remotely - Avalon
310 if (!IsAnOper(sptr) || !cnt)
313 /* let the user have some idea that its at the end of the trace */
314 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
315 me.name, parv[0], 0, link_s[me.fd],
316 link_u[me.fd], "<No_match>", *(me.serv->by) ?
317 me.serv->by : "*", "*", me.name, 0, 0);
320 for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
321 if (Links(cltmp) > 0)
322 sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
323 parv[0], ConClass(cltmp), Links(cltmp));
328 * ms_trace - server message handler
330 * parv[0] = sender prefix
331 * parv[1] = nick or servername
332 * parv[2] = 'target' servername
334 int ms_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
337 struct Client *acptr;
338 struct ConfClass *cltmp;
340 int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
341 int cnt = 0, wilds, dow;
343 if (parc < 2 || BadPtr(parv[1]))
345 /* just "TRACE" without parameters. Must be from local client */
351 else if (parc < 3 || BadPtr(parv[2]))
353 /* No target specified. Make one before propagating. */
356 if ((acptr = find_match_server(parv[1])) ||
357 ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
360 parv[2] = acptr->user->server->name;
362 parv[2] = acptr->name;
365 if ((i = hunt_server(IsServer(acptr), cptr, sptr,
366 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
374 /* Got "TRACE <tname> :<target>" */
376 if (MyUser(sptr) || Protocol(cptr) < 10)
377 acptr = find_match_server(parv[2]);
379 acptr = FindNServer(parv[2]);
380 if ((i = hunt_server(0, cptr, sptr,
381 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
386 if (i == HUNTED_PASS)
389 acptr = next_client(GlobalClientList, tname);
392 sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
394 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
396 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
397 (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
402 doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : 1;
403 wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
404 dow = wilds || doall;
406 /* Don't give (long) remote listings to lusers */
407 if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
410 for (i = 0; i < MAXCONNECTIONS; i++)
411 link_s[i] = 0, link_u[i] = 0;
415 for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
417 link_u[acptr->from->fd]++;
418 else if (IsServer(acptr))
419 link_s[acptr->from->fd]++;
423 /* report all direct connections */
425 for (i = 0; i <= HighestFd; i++)
427 unsigned int conClass;
429 if (!(acptr = LocalClientArray[i])) /* Local Connection? */
431 if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
432 !IsAnOper(acptr) && (acptr != sptr))
434 if (!doall && wilds && match(tname, acptr->name))
436 if (!dow && 0 != ircd_strcmp(tname, acptr->name))
438 conClass = get_client_class(acptr);
440 switch (acptr->status)
442 case STAT_CONNECTING:
443 sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
444 me.name, parv[0], conClass, acptr->name);
448 sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
449 me.name, parv[0], conClass, acptr->name);
455 case STAT_UNKNOWN_USER:
456 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
457 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP));
460 case STAT_UNKNOWN_SERVER:
461 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
462 me.name, parv[0], conClass, "Unknown Server");
466 /* Only opers see users if there is a wildcard
467 but anyone can see all the opers. */
468 if ((IsAnOper(sptr) && (MyUser(sptr) ||
469 !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
472 sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
473 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
474 CurrentTime - acptr->lasttime);
476 sendto_one(sptr, rpl_str(RPL_TRACEUSER),
477 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
478 CurrentTime - acptr->lasttime);
483 * Connection is a server
485 * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
487 * class Class the server is in
488 * nS Number of servers reached via this link
489 * nC Number of clients reached via this link
490 * name Name of the server linked
491 * ConnBy Who established this link
492 * last Seconds since we got something from this link
493 * age Seconds this link has been alive
495 * Additional comments etc...... -Cym-<cym@acrux.net>
499 if (acptr->serv->user)
500 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
501 me.name, parv[0], conClass, link_s[i],
502 link_u[i], acptr->name,
503 (*acptr->serv->by) ? acptr->serv->by : "*",
504 acptr->serv->user->username, acptr->serv->user->host,
505 CurrentTime - acptr->lasttime,
506 CurrentTime - acptr->serv->timestamp);
508 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
509 me.name, parv[0], conClass, link_s[i],
510 link_u[i], acptr->name,
511 (*acptr->serv->by) ? acptr->serv->by : "*", "*",
512 me.name, CurrentTime - acptr->lasttime,
513 CurrentTime - acptr->serv->timestamp);
516 default: /* We actually shouldn't come here, -msa */
517 sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0],
518 get_client_name(acptr, HIDE_IP));
524 * Add these lines to summarize the above which can get rather long
525 * and messy when done remotely - Avalon
527 if (!IsAnOper(sptr) || !cnt)
530 /* let the user have some idea that its at the end of the trace */
531 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
532 me.name, parv[0], 0, link_s[me.fd],
533 link_u[me.fd], "<No_match>", *(me.serv->by) ?
534 me.serv->by : "*", "*", me.name, 0, 0);
537 for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
538 if (Links(cltmp) > 0)
539 sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
540 parv[0], ConClass(cltmp), Links(cltmp));
545 * mo_trace - oper message handler
547 * parv[0] = sender prefix
548 * parv[1] = nick or servername
549 * parv[2] = 'target' servername
551 int mo_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
554 struct Client *acptr;
555 struct ConfClass *cltmp;
557 int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
558 int cnt = 0, wilds, dow;
560 if (parc < 2 || BadPtr(parv[1]))
562 /* just "TRACE" without parameters. Must be from local client */
568 else if (parc < 3 || BadPtr(parv[2]))
570 /* No target specified. Make one before propagating. */
573 if ((acptr = find_match_server(parv[1])) ||
574 ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
577 parv[2] = acptr->user->server->name;
579 parv[2] = acptr->name;
582 if ((i = hunt_server(IsServer(acptr), cptr, sptr,
583 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
591 /* Got "TRACE <tname> :<target>" */
593 if (MyUser(sptr) || Protocol(cptr) < 10)
594 acptr = find_match_server(parv[2]);
596 acptr = FindNServer(parv[2]);
597 if ((i = hunt_server(0, cptr, sptr,
598 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
603 if (i == HUNTED_PASS)
606 acptr = next_client(GlobalClientList, tname);
609 sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
611 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
613 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
614 (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
619 doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : 1;
620 wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
621 dow = wilds || doall;
623 /* Don't give (long) remote listings to lusers */
624 if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
627 for (i = 0; i < MAXCONNECTIONS; i++)
628 link_s[i] = 0, link_u[i] = 0;
632 for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
634 link_u[acptr->from->fd]++;
635 else if (IsServer(acptr))
636 link_s[acptr->from->fd]++;
640 /* report all direct connections */
642 for (i = 0; i <= HighestFd; i++)
644 unsigned int conClass;
646 if (!(acptr = LocalClientArray[i])) /* Local Connection? */
648 if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
649 !IsAnOper(acptr) && (acptr != sptr))
651 if (!doall && wilds && match(tname, acptr->name))
653 if (!dow && 0 != ircd_strcmp(tname, acptr->name))
655 conClass = get_client_class(acptr);
657 switch (acptr->status)
659 case STAT_CONNECTING:
660 sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
661 me.name, parv[0], conClass, acptr->name);
665 sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
666 me.name, parv[0], conClass, acptr->name);
672 case STAT_UNKNOWN_USER:
673 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
674 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP));
677 case STAT_UNKNOWN_SERVER:
678 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
679 me.name, parv[0], conClass, "Unknown Server");
683 /* Only opers see users if there is a wildcard
684 but anyone can see all the opers. */
685 if ((IsAnOper(sptr) && (MyUser(sptr) ||
686 !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
689 sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
690 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
691 CurrentTime - acptr->lasttime);
693 sendto_one(sptr, rpl_str(RPL_TRACEUSER),
694 me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
695 CurrentTime - acptr->lasttime);
700 * Connection is a server
702 * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
704 * class Class the server is in
705 * nS Number of servers reached via this link
706 * nC Number of clients reached via this link
707 * name Name of the server linked
708 * ConnBy Who established this link
709 * last Seconds since we got something from this link
710 * age Seconds this link has been alive
712 * Additional comments etc...... -Cym-<cym@acrux.net>
716 if (acptr->serv->user)
717 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
718 me.name, parv[0], conClass, link_s[i],
719 link_u[i], acptr->name,
720 (*acptr->serv->by) ? acptr->serv->by : "*",
721 acptr->serv->user->username, acptr->serv->user->host,
722 CurrentTime - acptr->lasttime,
723 CurrentTime - acptr->serv->timestamp);
725 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
726 me.name, parv[0], conClass, link_s[i],
727 link_u[i], acptr->name,
728 (*acptr->serv->by) ? acptr->serv->by : "*", "*",
729 me.name, CurrentTime - acptr->lasttime,
730 CurrentTime - acptr->serv->timestamp);
733 default: /* We actually shouldn't come here, -msa */
734 sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0],
735 get_client_name(acptr, HIDE_IP));
741 * Add these lines to summarize the above which can get rather long
742 * and messy when done remotely - Avalon
744 if (!IsAnOper(sptr) || !cnt)
747 /* let the user have some idea that its at the end of the trace */
748 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
749 me.name, parv[0], 0, link_s[me.fd],
750 link_u[me.fd], "<No_match>", *(me.serv->by) ?
751 me.serv->by : "*", "*", me.name, 0, 0);
754 for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
755 if (Links(cltmp) > 0)
756 sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
757 parv[0], ConClass(cltmp), Links(cltmp));
766 * parv[0] = sender prefix
767 * parv[1] = nick or servername
768 * parv[2] = 'target' servername
770 int m_trace(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
773 struct Client *acptr;
774 struct ConfClass *cltmp;
776 int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
777 int cnt = 0, wilds, dow;
779 if (parc < 2 || BadPtr(parv[1]))
781 /* just "TRACE" without parameters. Must be from local client */
787 else if (parc < 3 || BadPtr(parv[2]))
789 /* No target specified. Make one before propagating. */
792 if ((acptr = find_match_server(parv[1])) ||
793 ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
796 parv[2] = acptr->user->server->name;
798 parv[2] = acptr->name;
801 if ((i = hunt_server(IsServer(acptr), cptr, sptr,
802 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
810 /* Got "TRACE <tname> :<target>" */
812 if (MyUser(sptr) || Protocol(cptr) < 10)
813 acptr = find_match_server(parv[2]);
815 acptr = FindNServer(parv[2]);
816 if ((i = hunt_server(0, cptr, sptr,
817 "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
822 if (i == HUNTED_PASS)
825 acptr = next_client(GlobalClientList, tname);
828 sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
830 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
832 version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
833 (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
838 doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
839 wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
840 dow = wilds || doall;
842 /* Don't give (long) remote listings to lusers */
843 if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
846 for (i = 0; i < MAXCONNECTIONS; i++)
847 link_s[i] = 0, link_u[i] = 0;
851 for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
853 link_u[acptr->from->fd]++;
854 else if (IsServer(acptr))
855 link_s[acptr->from->fd]++;
859 /* report all direct connections */
861 for (i = 0; i <= HighestFd; i++)
864 unsigned int conClass;
866 if (!(acptr = LocalClientArray[i])) /* Local Connection? */
868 if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
869 !IsAnOper(acptr) && (acptr != sptr))
871 if (!doall && wilds && match(tname, acptr->name))
873 if (!dow && 0 != ircd_strcmp(tname, acptr->name))
875 conClass = get_client_class(acptr);
877 switch (acptr->status)
879 case STAT_CONNECTING:
880 sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
881 me.name, parv[0], conClass, name);
885 sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
886 me.name, parv[0], conClass, name);
892 case STAT_UNKNOWN_USER:
893 case STAT_UNKNOWN_SERVER:
894 sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
895 me.name, parv[0], conClass, name);
899 /* Only opers see users if there is a wildcard
900 but anyone can see all the opers. */
901 if ((IsAnOper(sptr) && (MyUser(sptr) ||
902 !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
905 sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
906 me.name, parv[0], conClass, name, CurrentTime - acptr->lasttime);
908 sendto_one(sptr, rpl_str(RPL_TRACEUSER),
909 me.name, parv[0], conClass, name, CurrentTime - acptr->lasttime);
914 * Connection is a server
916 * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
918 * class Class the server is in
919 * nS Number of servers reached via this link
920 * nC Number of clients reached via this link
921 * name Name of the server linked
922 * ConnBy Who established this link
923 * last Seconds since we got something from this link
924 * age Seconds this link has been alive
926 * Additional comments etc...... -Cym-<cym@acrux.net>
930 if (acptr->serv->user)
931 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
932 me.name, parv[0], conClass, link_s[i],
933 link_u[i], name, (*acptr->serv->by) ? acptr->serv->by : "*",
934 acptr->serv->user->username, acptr->serv->user->host,
935 CurrentTime - acptr->lasttime,
936 CurrentTime - acptr->serv->timestamp);
938 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
939 me.name, parv[0], conClass, link_s[i],
940 link_u[i], name, (*acptr->serv->by) ? acptr->serv->by : "*", "*",
941 me.name, CurrentTime - acptr->lasttime,
942 CurrentTime - acptr->serv->timestamp);
945 default: /* We actually shouldn't come here, -msa */
946 sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0], name);
952 * Add these lines to summarize the above which can get rather long
953 * and messy when done remotely - Avalon
955 if (!IsAnOper(sptr) || !cnt)
958 /* let the user have some idea that its at the end of the trace */
959 sendto_one(sptr, rpl_str(RPL_TRACESERVER),
960 me.name, parv[0], 0, link_s[me.fd],
961 link_u[me.fd], "<No_match>", *(me.serv->by) ?
962 me.serv->by : "*", "*", me.name, 0, 0);
965 for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
966 if (Links(cltmp) > 0)
967 sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
968 parv[0], ConClass(cltmp), Links(cltmp));