+
+#define NS_TRACE_CRITERIA_AUTHED 0x01
+#define NS_TRACE_CRITERIA_NUMCHAN 0x02
+
+struct neonserv_cmd_trace_criteria {
+ char *mask;
+ char *nick;
+ char *ident;
+ char *host;
+ char *account;
+ unsigned int flags : 4;
+ unsigned int authed : 1;
+ unsigned int used_channel : 5; //32 max
+ char *channel[10];
+ unsigned int numchannels;
+ unsigned int limit : 16;
+};
+
+static CMD_BIND(neonserv_cmd_trace) {
+ //ok parse the criterias
+ struct neonserv_cmd_trace_criteria *criteria = malloc(sizeof(*criteria));
+ if (!criteria) {
+ perror("malloc() failed");
+ return;
+ }
+ memset(criteria, 0, sizeof(*criteria));
+ criteria->limit = 50;
+ int i, show_user = 0;
+ if(!stricmp(argv[0], "print")) {
+ show_user = 1;
+ }
+ for(i = 1; i < argc; i += 2) {
+ if(argc <= i+1) {
+ reply(getTextBot(), user, "MODCMD_LESS_PARAM_COUNT");
+ return;
+ }
+ if(!stricmp(argv[i], "mask")) criteria->mask = argv[i+1];
+ else if(!stricmp(argv[i], "nick")) criteria->nick = argv[i+1];
+ else if(!stricmp(argv[i], "ident")) criteria->ident = argv[i+1];
+ else if(!stricmp(argv[i], "host")) criteria->host = argv[i+1];
+ else if(!stricmp(argv[i], "account")) criteria->account = argv[i+1];
+ else if(!stricmp(argv[i], "authed")) {
+ if(!strcmp(argv[i+1], "0") || !strcmp(argv[i+1], "off") || !strcmp(argv[i+1], get_language_string(user, "NS_SET_OFF"))) {
+ criteria->authed = 1;
+ } else if(!strcmp(argv[i+1], "0") || !strcmp(argv[i+1], "off") || !strcmp(argv[i+1], get_language_string(user, "NS_SET_OFF"))) {
+ criteria->authed = 0;
+ } else {
+ reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argv[i+1]);
+ return;
+ }
+ criteria->flags |= NS_TRACE_CRITERIA_AUTHED;
+ }
+ else if(!stricmp(argv[i], "channel")) criteria->channel[criteria->used_channel++] = argv[i+1];
+ else if(!stricmp(argv[i], "numchannels")) {
+ criteria->numchannels = atoi(argv[i+1]);
+ criteria->flags |= NS_TRACE_CRITERIA_NUMCHAN;
+ }
+ else if(!stricmp(argv[i], "limit")) {
+ criteria->limit = atoi(argv[i+1]);
+ }
+ }
+ char tmp[MAXLEN];
+ int matches = 0;
+ struct UserNode *cuser;
+ reply(getTextBot(), user, "NS_TRACE_HEADER");
+ for(cuser = getAllUsers(NULL); cuser; cuser = getAllUsers(cuser)) {
+ if(show_user && matches == criteria->limit) {
+ //too many
+ break;
+ }
+ if(criteria->mask) {
+ sprintf(tmp, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+ if(match(criteria->mask, tmp)) continue;
+ }
+ if(criteria->nick && match(criteria->nick, cuser->nick)) continue;
+ if(criteria->ident && match(criteria->ident, cuser->ident)) continue;
+ if(criteria->host && match(criteria->host, cuser->host)) continue;
+ if(criteria->account && (!(cuser->flags & USERFLAG_ISAUTHED) || match(criteria->account, cuser->auth))) continue;
+ if((criteria->flags & NS_TRACE_CRITERIA_AUTHED) && (criteria->authed ^ (cuser->flags & USERFLAG_ISAUTHED))) continue;
+ if((criteria->flags & NS_TRACE_CRITERIA_NUMCHAN)) {
+ int ccount = 0;
+ struct ChanUser *chanuser;
+ for(chanuser = getUserChannels(cuser, NULL); chanuser; chanuser = getUserChannels(cuser, chanuser))
+ ccount++;
+ if(ccount < criteria->numchannels)
+ continue;
+ }
+ matches++;
+ //output
+ if(show_user) {
+ reply(getTextBot(), user, "%s!%s@%s %s", cuser->nick, cuser->ident, cuser->host, ((cuser->flags & USERFLAG_ISAUTHED) ? cuser->auth : "*"));
+ }
+ }
+ reply(getTextBot(), user, "NS_TRACE_FOUND", matches);
+}