/* trace.c */
#include "miscreply.h"
-#include "numeric.h"
#include "../core/error.h"
#include "../irc/irc.h"
#include "../lib/irc_string.h"
-#include "../nick/nick.h"
#include "../server/server.h"
#include <string.h>
-/* TODO: make server module keep state of link TS ? */
-/* TODO: make trace_server and trace_user function */
-/* TODO: trace link,
- * loop back from target server til we find ourself, send trace links along the way
+/* trace_user
+ *
*/
+static void trace_user(char *sourcenum, nick *tnick) {
+ if (IsOper(tnick)) {
+ /*
+ * 204 RPL_TRACEOPERATOR "source 204 target Oper class nick[user@IP] last_parse"
+ * "irc.netsplit.net 204 foobar Oper barfoo[fish@127.0.0.1] 0"
+ *
+ * note: no info available on how long ago we last parsed something from this user -> 0 (not idle time)
+ */
+ irc_send("%s 204 %s Oper opers %s[%s@%s] 0", getmynumeric(), sourcenum, tnick->nick,
+ tnick->ident[0] != '~' ? tnick->ident : "", IPtostr(tnick->p_ipaddr));
+ } else {
+ /*
+ * 205 RPL_TRACEUSER "source 205 target User class nick[user@IP] last_parse"
+ * "irc.netsplit.net 205 foobar User barfoo[fish@127.0.0.1] 0"
+ */
+ irc_send("%s 205 %s User users %s[%s@%s] 0", getmynumeric(), sourcenum, tnick->nick,
+ tnick->ident[0] != '~' ? tnick->ident : "", IPtostr(tnick->p_ipaddr));
+ }
+}
+
+
+
+/* trace_server
+ * return number of matched servers
+ */
+static int trace_server(char *sourcenum, char *target, int doall) {
+
+ /* do not show all and no match for my hub */
+ if (!doall && !match2strings(target, serverlist[myhub].name->content))
+ return 0;
+
+ /*
+ * 206 RPL_TRACESERVER "source 206 target Serv class NS NC server connected_by last_parse connected_for"
+ * "irc.netsplit.net 206 foobar Server 2S 6C irc.netsplit.net *!user@host 34 92988"
+ *
+ * note: no info available on how many servers or clients are linked through this server link -> 0S 0C
+ * no info available on who/what established the link, pretend it is by us -> *!*@myservername
+ * no info available on how long ago we last parsed something from this link -> 0
+ * no info available on how long this server has been linked -> 0
+ */
+ irc_send("%s 206 %s Serv servers 0S 0C %s *!*@%s 0 0", getmynumeric(), sourcenum,
+ serverlist[myhub].name->content, myserver->content);
+
+ return 1;
+}
+
+
/* handle remote trace request
*
*/
int handletracemsg(void *source, int cargc, char **cargv) {
- nick *snick; /* struct nick for source nick */
- nick *tnick; /* struct nick for target nick */
- nick **lnick; /* struct nick for looping local users */
+ nick *snick; /* struct nick for source nick */
+ nick *tnick; /* struct nick for target nick */
+ nick **lnick; /* struct nick for looping local users */
+ int c; /* loop variable */
+ int opers = 0; /* number of operators */
+ int users = 0; /* number of users */
+ int servers = 0; /* number of servers */
+ int doall, wilds, dow; /* determine what to show */
+ char *sourcenum = (char *)source; /* source user numeric */
+ char *target; /* target parameter - as given by the source user */
- int i; /* index for serverlist[] */
- int showall = 0; /* show all local server links */
- int opers = 0; /* number of opers */
- int users = 0; /* number of users */
- int servers = 0; /* number of servers */
- char *sourcenum = (char *)source; /* source user numeric */
- char *targetnum = getmynumeric(); /* target server numeric */
- char *target; /* target parameter - as given by the source user */
- char *servernum; /* destination server numeric parameter */
/* check parameters */
if (cargc < 2) {
/* get the parameters */
target = cargv[0];
- servernum = cargv[1];
-
- /* from a server? */
- if (IsServer(sourcenum))
- return CMD_OK;
/* find source user */
if (!(snick = miscreply_finduser(sourcenum, "TRACE")))
return CMD_OK;
- /* TODO: trace here down to target server first? */
-
- /* for me */
- if (IsMeNum(servernum)) {
-
- /* find target user */
- if ((tnick = getnickbynick(target))) {
-
- /* my user? */
- if (MyUser(tnick)) {
- if (IsOper(tnick)) {
- /*
- * 204 RPL_TRACEOPERATOR "source 204 target Oper class nick[user@IP] last_parse"
- * "irc.netsplit.net 204 foobar Oper barfoo[fish@127.0.0.1] 0"
- *
- * note: no info available on how long ago we last parsed something from this user -> 0 (not idle time)
- */
- send_reply(targetnum, RPL_TRACEOPERATOR, sourcenum, "Oper opers %s[%s@%s] 0", tnick->nick,
- tnick->ident[0] != '~' ? tnick->ident : "", IPtostr(tnick->p_ipaddr));
- } else {
- /*
- * 205 RPL_TRACEUSER "source 205 target User class nick[user@IP] last_parse"
- * "irc.netsplit.net 205 foobar User barfoo[fish@127.0.0.1] 0"
- */
- send_reply(targetnum, RPL_TRACEUSER, sourcenum, "User users %s[%s@%s] 0", tnick->nick,
- tnick->ident[0] != '~' ? tnick->ident : "", IPtostr(tnick->p_ipaddr));
- }
- }
- }
- else {
+ /* doall, wilds, dow */
+ doall = match2strings(target, myserver->content);
+ wilds = strchr(target, '*') || strchr(target, '?');
+ dow = wilds || doall;
- /* target is my server,
- * show all local server links
- */
- if (match2strings(target, myserver->content))
- showall = 1;
- /* go over all servers */
- for (i = 0; i < MAXSERVERS; i++) {
- if (serverlist[i].maxusernum == 0) /* not linked */
+ /* find target user */
+ if ((tnick = getnickbynick(target))) {
+
+ /* my user */
+ if (mylongnum == homeserver(tnick->numeric))
+ trace_user(sourcenum, tnick);
+ }
+
+
+ /* source user is an operator */
+ else if (IsOper(snick)) {
+
+ /* show servers */
+ servers = trace_server(sourcenum, target, doall);
+
+ /* do all or wilds */
+ if (dow) {
+
+ /* loop over all local users */
+ lnick = servernicks[mylongnum];
+ for (c = 0; c < serverlist[mylongnum].maxusernum; c++) {
+
+ if (lnick[c] == NULL) /* no user */
continue;
- if (!IsMeLong(serverlist[i].parent) && i != myhub) /* not my server and not my hub */
+
+ /* target is invisible (mode +i), target is not an operator */
+ if (IsInvisible(lnick[c]) && dow && !IsOper(lnick[c]))
continue;
- servers++;
- if (!showall && !match2strings(target, serverlist[i].name->content)) /* do not show all and no match */
+
+ /* dont show all, do wildcards and no match */
+ if (!doall && wilds && !match2strings(target, lnick[c]->nick))
continue;
- /*
- * 206 RPL_TRACESERVER "source 206 target Serv class NS NC server connected_by last_parse connected_for"
- * "irc.netsplit.net 206 foobar Server 2S 6C irc.netsplit.net *!user@host 34 92988"
- *
- * note: no info available on how many servers or clients are linked through this server link -> 0S 0C
- * no info available on who/what established the link, pretend it is by us -> *!*@myservername
- * no info available on how long ago we last parsed something from this link -> 0
- * no info available on how long this server has been linked -> 0
- */
- send_reply(targetnum, RPL_TRACESERVER, sourcenum, "Serv servers 0S 0C %s *!*@%s 0 0",
- serverlist[i].name->content, myserver->content);
- }
- /* show my users, show class total */
- if (showall) {
-
- /* loop over all local users */
- lnick = servernicks[mylongnum];
- for (i = 0; i < MAXLOCALUSER; i++) {
-
- if (lnick[i] == NULL) /* no user */
- continue;
-
- if (!match2strings(target, lnick[i]->nick)) /* no match */
- continue;
-
- if (IsOper(lnick[i])) {
- opers++;
- /* 204 RPL_TRACEOPERATOR see above */
- send_reply(targetnum, RPL_TRACEOPERATOR, sourcenum, "Oper opers %s[%s@%s] 0", lnick[i]->nick,
- lnick[i]->ident[0] != '~' ? lnick[i]->ident : "", IPtostr(lnick[i]->p_ipaddr));
- } else {
- users++;
- /* TODO: perhaps do show +k and/or +X clients? */
- /* ircd does not show all local users in remote trace - might be too many users with trojan scan / nickjupes? */
- continue;
- /* 205 RPL_TRACEUSER see above */
- send_reply(targetnum, RPL_TRACEUSER, sourcenum, "User users %s[%s@%s] 0", lnick[i]->nick,
- lnick[i]->ident[0] != '~' ? lnick[i]->ident : "", IPtostr(lnick[i]->p_ipaddr));
- }
- }
- /*
- * class has no meaning here,
- * but showing the total count for users/opers/servers might be useful anyway
- *
- * 209 RPL_TRACECLASS "source 209 target Class class count"
- * "irc.netsplit.net 209 foobar Class users 2"
- */
- if (users)
- send_reply(targetnum, RPL_TRACECLASS, sourcenum, "Class users %d", users);
- if (opers)
- send_reply(targetnum, RPL_TRACECLASS, sourcenum, "Class opers %d", opers);
- /* should always be true - we are connected so at least 1 local server link */
- if (servers)
- send_reply(targetnum, RPL_TRACECLASS, sourcenum, "Class servers %d", servers);
+ if (IsOper(lnick[c]))
+ opers++;
+ else
+ users++;
+ trace_user(sourcenum, lnick[c]);
}
+ /*
+ * class has no meaning here,
+ * but showing the total count for users/opers/servers might be useful anyway
+ *
+ * 209 RPL_TRACECLASS "source 209 target Class class count"
+ * "irc.netsplit.net 209 foobar Class users 2"
+ */
+ if (users)
+ irc_send("%s 209 %s Class users %d", getmynumeric(), sourcenum, users);
+ if (opers)
+ irc_send("%s 209 %s Class opers %d", getmynumeric(), sourcenum, opers);
+ if (servers)
+ irc_send("%s 209 %s Class servers %d", getmynumeric(), sourcenum, servers);
}
}
+
/*
* 262 RPL_TRACEEND "source 262 target :End of TRACE"
* "irc.netsplit.net 262 foobar :End of TRACE"
*/
- send_reply(targetnum, RPL_TRACEEND, sourcenum, ":End of TRACE");
+ irc_send("%s 262 %s :End of TRACE", getmynumeric(), sourcenum);
return CMD_OK;
}