/** Send a (prefixed) command to all local users on a channel with or without * a client capability specified. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command (ignored). * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_DEAF, SKIP_NONOPS, SKIP_NONVOICES indicating which clients to skip. * @param[in] withcap CAP_* that the user must have active to receive the message. * @param[in] skipcap CAP_* that the user must not have active to receive the message. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_capab_butserv_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, int withcap, int skipcap, const char *pattern, ...) { struct VarData vd; struct MsgBuf *mb; struct Membership *member; vd.vd_format = pattern; /* set up the struct VarData for %v */ va_start(vd.vd_args, pattern); /* build the buffer */ mb = msgq_make(0, "%:#C %s %v", from, cmd, &vd); va_end(vd.vd_args); /* send the buffer to each local channel member */ for (member = to->members; member; member = member->next_member) { if (!MyConnect(member->user) || member->user == one || IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONHOPS && !IsChanOp(member) && !IsHalfOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !IsHalfOp(member)&& !HasVoice(member)) || ((withcap != CAP_NONE) && !CapActive(member->user, withcap)) || ((skipcap != CAP_NONE) && CapActive(member->user, skipcap))) continue; send_buffer(member->user, mb, 0); } msgq_clean(mb); }
/** Send a bot command to all local users on a channel. * @param[in] botname Bot sending the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command (ignored). * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_DEAF, SKIP_NONOPS, SKIP_NONVOICES indicating which clients to skip. * @param[in] pattern Format string for command arguments. */ void sendcmdbotto_channel(const char *botname, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct VarData vd; struct MsgBuf *mb; struct Membership *member; vd.vd_format = pattern; /* set up the struct VarData for %v */ va_start(vd.vd_args, pattern); /* build the buffer */ mb = msgq_make(0, ":%s %s %v", botname, cmd, &vd); va_end(vd.vd_args); /* send the buffer to each local channel member */ for (member = to->members; member; member = member->next_member) { if (!MyConnect(member->user) || member->user == one || IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) #if defined(DDB) || defined(SERVICES) || (skip & SKIP_NONOPS && !IsChanOwner(member) && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOwner(member) && !IsChanOp(member) && !HasVoice(member))) #else || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member))) #endif continue; send_buffer(member->user, mb, 0); } msgq_clean(mb); }
//----------------------------------------------------------------------------- // Purpose: Implements "deafness" //----------------------------------------------------------------------------- bool CNPC_Crow::QueryHearSound( CSound *pSound ) { if( IsDeaf() ) return false; return BaseClass::QueryHearSound( pSound ); }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST, SKIP_SERVERS. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; vd.vd_format = pattern; /* Build buffer to send to users */ va_start(vd.vd_args, pattern); user_mb = msgq_make(0, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? "%:#C %s @%v" : "%:#C %s %v", from, cmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ if ((skip & SKIP_SERVERS) || IsLocalChannel(to->chname)) serv_mb = NULL; else { va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, skip & SKIP_NONOPS ? "%C %s @%v" : "%C %s %v", from, tok, &vd); va_end(vd.vd_args); } /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip duplicates, zombies, and flagged users... */ if (cli_sentalong(member->user) == sentalong_marker || IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || #if defined(DDB) || defined(SERVICES) (skip & SKIP_NONOPS && !IsChanOwner(member) && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOwner(member) && !IsChanOp(member) && !HasVoice(member)) || #else (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)) || #endif (skip & SKIP_COLOUR && !IsStripColour(member->user)) || (skip & SKIP_NOCOLOUR && IsStripColour(member->user)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || !(serv_mb || MyUser(member->user)) || cli_fd(cli_from(member->user)) < 0) continue; cli_sentalong(member->user) = sentalong_marker; /* pick right buffer to send */ send_buffer(member->user, MyConnect(member->user) ? user_mb : serv_mb, 0); } msgq_clean(user_mb); if (serv_mb) msgq_clean(serv_mb); }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; vd.vd_format = pattern; /* Build buffer to send to users */ va_start(vd.vd_args, pattern); user_mb = msgq_make(0, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? "%:#C %s @%v" : "%:#C %s %v", from, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? MSG_NOTICE : cmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd); va_end(vd.vd_args); /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip one, zombies, and deaf users... */ if (IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || cli_fd(cli_from(member->user)) < 0 || cli_sentalong(member->user) == sentalong_marker) continue; cli_sentalong(member->user) = sentalong_marker; if (MyConnect(member->user)) /* pick right buffer to send */ send_buffer(member->user, user_mb, 0); else send_buffer(member->user, serv_mb, 0); } msgq_clean(user_mb); msgq_clean(serv_mb); }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, unsigned char prefix, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; struct Client *service; const char *userfmt; const char *usercmd; vd.vd_format = pattern; /* Build buffer to send to users */ usercmd = cmd; userfmt = "%:#C %s %v"; if (skip & (SKIP_NONOPS | SKIP_NONHOPS | SKIP_NONVOICES)) { usercmd = MSG_NOTICE; if (skip & SKIP_NONVOICES) userfmt = "%:#C %s +%v"; else if (skip & SKIP_NONHOPS) userfmt = "%:#C %s %%%v"; else userfmt = "%:#C %s @%v"; } va_start(vd.vd_args, pattern); user_mb = msgq_make(0, userfmt, from, usercmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd); va_end(vd.vd_args); /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip one, zombies, and deaf users... */ if (IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONHOPS && !IsChanOp(member) && !IsHalfOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !IsHalfOp(member) && !HasVoice(member)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || (is_silenced(from, member->user, 1)) || cli_fd(cli_from(member->user)) < 0 || cli_sentalong(member->user) == sentalong_marker) continue; cli_sentalong(member->user) = sentalong_marker; if (MyConnect(member->user)) /* pick right buffer to send */ send_buffer(member->user, user_mb, 0); else send_buffer(member->user, serv_mb, 0); } /* Consult service forwarding table. */ if(GlobalForwards[prefix] && (service = FindServer(GlobalForwards[prefix])) && cli_sentalong(service) != sentalong_marker) { cli_sentalong(service) = sentalong_marker; send_buffer(service, serv_mb, 0); } msgq_clean(user_mb); msgq_clean(serv_mb); }
signed int checkHostmask(struct Client *sptr, char *hoststr, int flags) { struct Client *acptr; struct Channel *chptr; struct Membership *lp; int count = 0, found = 0, cidr_check_bits = 0; char outbuf[BUFSIZE]; char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3]; char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1]; char *p = NULL; struct in_addr cidr_check; strcpy(nickm,"*"); strcpy(userm,"*"); strcpy(hostm,"*"); if (!strchr(hoststr, '!') && !strchr(hoststr, '@')) ircd_strncpy(hostm,hoststr,HOSTLEN); else { if ((p = strchr(hoststr, '@'))) { *p++ = '\0'; if (*p) ircd_strncpy(hostm,p, HOSTLEN); } /* Get the nick!user mask */ if ((p = strchr(hoststr, '!'))) { *p++ = '\0'; if (*p) ircd_strncpy(userm,p,USERLEN); if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN); } else if (*hoststr) { /* Durz: We should only do the following *IF* the hoststr has not already been * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com */ ircd_strncpy(userm,hoststr,USERLEN); } } if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) { if (p) *p = '\0'; if (inet_aton(hostm, &cidr_check)) { cidr_check_bits = p ? atoi(p + 1) : 32; if ((cidr_check_bits >= 0) && (cidr_check_bits <= 32)) { flags |= CHECK_CIDRMASK; cidr_check.s_addr &= NETMASK(cidr_check_bits); } } if (p) *p = '/'; } /* Copy formatted string into "targhost" buffer */ ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm); targhost[sizeof(targhost) - 1] = '\0'; /* Note: we have to exclude the last client struct as it is not a real client * structure, and therefore any attempt to access elements in it would cause * a segfault. */ for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { /* Dont process if acptr is a unregistered client, a server or a ping */ if (!IsRegistered(acptr) || IsServer(acptr)) continue; if (IsMe(acptr)) /* Always the last acptr record */ break; if(count > feature_int(FEAT_MAX_CHECK_OUTPUT)) { /* sanity stuff */ ircd_snprintf(0, outbuf, sizeof(outbuf), "More than %d results, truncating...", count); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_ENDOFCHECK, " "); break; } /* Copy host info into buffer */ curhost[0] = '\0'; ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->realusername, acptr->cli_user->realhost); if (flags & CHECK_CIDRMASK) { if (((cli_ip(acptr).s_addr & NETMASK(cidr_check_bits)) == cidr_check.s_addr) && !match(nickm, acptr->cli_name) && (!match(userm, acptr->cli_user->realusername) || !match(userm, acptr->cli_user->username))) found = 1; } else { if(match((const char*)targhost,(const char*)curhost) == 0) found = 1; else { curhost[0] = '\0'; ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->username, acptr->cli_user->host); if(match((const char*)targhost,(const char*)curhost) == 0) found = 1; } } if (found == 1) { found = 0; /* reset that so it doesn't get crazy go nuts */ /* Show header if we've found at least 1 record */ if (count == 0) { /* Output header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "host", targhost); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), "%s %-*s%-*s%s", "No.", (NICKLEN + 2 ), "Nick", (USERLEN + 2), "User", "Host"); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d %-*s%-*s%s", (count+1), (NICKLEN + 2), acptr->cli_name, (USERLEN + 2), acptr->cli_user->realusername, (flags & CHECK_SHOWIPS) ? ircd_ntoa((const char*)&(cli_ip(acptr))) : acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); /* Show channel output (if applicable) - the 50 channel limit sanity check * is specifically to prevent coredumping when someone lamely tries to /check * Q or some other channel service... */ if (flags & CHECK_CHECKCHAN) { if (acptr->cli_user->joined > 0 && acptr->cli_user->joined <= 50) { char chntext[BUFSIZE]; int len = strlen(" on channels: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " on channels: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " on channels: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; else if (has_voice(acptr, chptr)) *(chntext + len++) = '+'; else if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); send_reply(sptr, RPL_DATASTR, " "); } } count++; } } if (count > 0) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_ENDOFCHECK, " "); } return count; }
void checkClient(struct Client *sptr, struct Client *acptr) { struct Channel *chptr; struct Membership *lp; char outbuf[BUFSIZE]; char *privs; time_t nowr; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s", myctime(acptr->cli_firsttime)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host, ircd_ntoa((const char*) &(cli_ip(acptr)))); send_reply(sptr, RPL_DATASTR, outbuf); if (((feature_int(FEAT_HOST_HIDING_STYLE) == 1) ? HasHiddenHost(acptr) : IsHiddenHost(acptr)) || IsSetHost(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF); send_reply(sptr, RPL_DATASTR, outbuf); if (IsService(cli_user(acptr)->server)) { if (acptr) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsAdmin(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator (service)"); else if (IsAnOper(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator (service)"); else send_reply(sptr, RPL_DATASTR, " Status:: Client (service)"); } else if (IsAdmin(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator"); } else if (IsAnOper(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator"); } else { send_reply(sptr, RPL_DATASTR, " Status:: Client"); } if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } privs = client_print_privs(acptr); if (strlen(privs) > 1) client_check_privs(acptr, sptr); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s", cli_name(acptr->cli_user->server)); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_version(acptr)) { if (strlen(cli_version(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " CTCP Version:: %s", cli_version(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_user(acptr) && !EmptyString(cli_user(acptr)->swhois)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " SWHOIS:: %s", cli_user(acptr)->swhois); send_reply(sptr, RPL_DATASTR, outbuf); } if (cli_webirc(acptr)) { if (strlen(cli_webirc(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " WebIRC:: %s", cli_webirc(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (MyUser(acptr)) get_eflags(sptr, acptr); /* +s (SERV_NOTICE) is not relayed to us from remote servers, * so we cannot tell if a remote client has that mode set. * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG * (and breaks if the user is +r) so we won't do that either. */ if (strlen(umode_str(acptr)) < 1) strcpy(outbuf, " Umode(s):: <none>"); else ircd_snprintf(0, outbuf, sizeof(outbuf), " Umode(s):: +%s", umode_str(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (acptr->cli_user->joined == 0) send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>"); else if (acptr->cli_user->joined > 50) { /* NB. As a sanity check, we DO NOT show the individual channels the * client is on if it is on > 50 channels. This is to prevent the ircd * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine * an Oper would want to see every single channel 'x' client is on anyway if * they are on *that* many). */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", acptr->cli_user->joined); send_reply(sptr, RPL_DATASTR, outbuf); } else { char chntext[BUFSIZE]; int len = strlen(" Channel(s):: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); } /* If client processing command ISN'T target (or a registered * Network Service), show idle time since the last time we * parsed something. */ if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) { nowr = CurrentTime - acptr->cli_user->last; ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld", nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60); send_reply(sptr, RPL_DATASTR, outbuf); } /* Away message (if applicable) */ if (acptr->cli_user->away) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", acptr->cli_user->away); send_reply(sptr, RPL_DATASTR, outbuf); } /* If local user.. */ if (MyUser(acptr)) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)", cli_port(acptr), cli_listener(acptr)->port); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { /* Note: sendq = receiveq for a client (it makes sense really) */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %u.%0.3u Kb (%u protocol messages)", cli_receiveK(acptr), cli_receiveB(acptr), cli_receiveM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %u.%0.3u Kb (%u protocol messages)", cli_sendK(acptr), cli_sendB(acptr), cli_sendM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
/* * The function that actually prints out the WHO reply for a client found */ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan, int fields, char* qrt) { char *p1; struct Channel *chptr = repchan; static char buf1[512]; /* NOTE: with current fields list and sizes this _cannot_ overrun, and also the message finally sent shouldn't ever be truncated */ p1 = buf1; buf1[1] = '\0'; /* If we don't have a channel and we need one... try to find it, unless the listing is for a channel service, we already know that there are no common channels, thus use PubChannel and not SeeChannel */ if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) && !IsChannelService(acptr)) { struct Membership* chan; for (chan = cli_user(acptr)->channel; chan && !chptr; chan = chan->next_channel) if (PubChannel(chan->channel) && (acptr == sptr || !IsZombie(chan))) chptr = chan->channel; } /* Place the fields one by one in the buffer and send it note that fields == NULL means "default query" */ if (fields & WHO_FIELD_QTY) /* Query type */ { *(p1++) = ' '; if (BadPtr(qrt)) *(p1++) = '0'; else while ((*qrt) && (*(p1++) = *(qrt++))); } if (!fields || (fields & WHO_FIELD_CHA)) { char *p2; *(p1++) = ' '; if ((p2 = (chptr ? chptr->chname : NULL))) while ((*p2) && (*(p1++) = *(p2++))); else *(p1++) = '*'; } if (!fields || (fields & WHO_FIELD_UID)) { char *p2 = cli_user(acptr)->username; *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } if (fields & WHO_FIELD_NIP) { const char* p2 = IsHiddenHost(acptr) && (!IsViewip(sptr) && acptr != sptr) ? feature_str(FEAT_HIDDEN_IP) : ircd_ntoa((const char*) &(cli_ip(acptr))); *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } if (!fields || (fields & WHO_FIELD_HOS)) { char *p2 = (IsViewip(sptr) || acptr == sptr) ? get_realhost(acptr) : get_virtualhost(acptr); *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } if (!fields || (fields & WHO_FIELD_SER)) { char *p2; int haspriv = IsAnOper(sptr) || es_representante(sptr); if (IsMe(cli_user(acptr)->server)) { if ((sptr != acptr) && feature_bool(FEAT_HIS_WHO_SERVERNAME) && !haspriv) p2 = (char *)feature_str(FEAT_HIS_SERVERNAME); else p2 = cli_name(&me); } else { if (IsHiddenserv(cli_user(acptr)->server) && !haspriv) p2 = (char *)feature_str(FEAT_HIS_SERVERNAME); else p2 = cli_name(cli_user(acptr)->server); } *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } if (!fields || (fields & WHO_FIELD_NIC)) { char *p2 = cli_name(acptr); *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } if (!fields || (fields & WHO_FIELD_FLA)) { *(p1++) = ' '; if (cli_user(acptr)->away) *(p1++) = 'G'; else *(p1++) = 'H'; if ((IsAnOper(acptr) || es_representante(acptr) || IsPreoper(acptr))/* && (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS))*/) *(p1++) = '*'; if (fields) { /* If you specified flags then we assume you know how to parse * multiple channel status flags, as this is currently the only * way to know if someone has @'s *and* is +'d. */ if (chptr && is_chan_op(acptr, chptr)) *(p1++) = '@'; if (chptr && has_voice(acptr, chptr)) *(p1++) = '+'; if (chptr && is_chan_halfop(acptr, chptr)) *(p1++) = '%'; if (chptr && is_chan_owner(acptr, chptr)) *(p1++) = '.'; if (chptr && is_zombie(acptr, chptr)) *(p1++) = '!'; } else { if (chptr && is_chan_op(acptr, chptr)) *(p1++) = '@'; else if (chptr && has_voice(acptr, chptr)) *(p1++) = '+'; else if (chptr && is_zombie(acptr, chptr)) *(p1++) = '!'; else if (chptr && is_chan_halfop(acptr, chptr)) *(p1++) = '%'; else if (chptr && is_chan_owner(acptr, chptr)) *(p1++) = '.'; } if (IsDeaf(acptr)) *(p1++) = 'd'; if (IsAnOper(sptr)) { if (IsInvisible(acptr)) *(p1++) = 'i'; if (SendWallops(acptr)) *(p1++) = 'w'; if (SendDebug(acptr)) *(p1++) = 'g'; } if (HasHiddenHost(acptr)) *(p1++) = 'x'; if (IsAnOper(acptr)) *(p1++) = 'o'; if (IsPreoper(acptr)) *(p1++) = 'p'; if (IsHelpOp(acptr)) *(p1++) = 'h'; if (IsCoadmin(acptr)) *(p1++) = 'a'; if (IsAdmin(acptr)) *(p1++) = 'A'; if (IsDevel(acptr)) *(p1++) = 'D'; if (IsViewip(acptr)) *(p1++) = 'X'; } if (!fields || (fields & WHO_FIELD_DIS)) { *p1++ = ' '; if (!fields) *p1++ = ':'; /* Place colon here for default reply */ if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr)) *p1++ = (sptr == acptr) ? '0' : '3'; else /* three digit hopcount maximum */ p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr)); } if (fields & WHO_FIELD_IDL) { *p1++ = ' '; if (MyUser(acptr)) { p1 += ircd_snprintf(0, p1, 11, "%d", CurrentTime - cli_user(acptr)->last); } else { *p1++ = '0'; } } if (!fields || (fields & WHO_FIELD_REN)) { char *p2 = cli_info(acptr); *p1++ = ' '; if (fields) *p1++ = ':'; /* Place colon here for special reply */ while ((*p2) && (*(p1++) = *(p2++))); } if (fields & WHO_FIELD_ACC) { char *p2 = cli_user(acptr)->account; *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } /* The first char will always be an useless blank and we need to terminate buf1 */ *p1 = '\0'; p1 = buf1; send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1); }
/* * Send whois information for acptr to sptr */ static void do_whois(struct Client* sptr, struct Client *acptr, int parc) { struct Client *a2cptr=0; struct Channel *chptr=0; int mlen; int len; static char buf[512]; const struct User* user = cli_user(acptr); const char* name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr); a2cptr = feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr) && sptr != acptr ? &his : user->server; assert(user); send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host, cli_info(acptr)); /* Display the channels this user is on. */ if (!IsChannelService(acptr)) { struct Membership* chan; mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name); len = 0; *buf = '\0'; for (chan = user->channel; chan; chan = chan->next_channel) { chptr = chan->channel; if (!ShowChannel(sptr, chptr) && !(IsOper(sptr) && IsLocalChannel(chptr->chname))) continue; if (acptr != sptr && IsZombie(chan)) continue; /* Don't show local channels when HIS is defined, unless it's a * remote WHOIS --ULtimaTe_ */ if (IsLocalChannel(chptr->chname) && (acptr != sptr) && (parc == 2) && feature_bool(FEAT_HIS_WHOIS_LOCALCHAN) && !IsAnOper(sptr)) continue; if (len+strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS, "%s :%s", name, buf); *buf = '\0'; len = 0; } if (IsDeaf(acptr)) *(buf + len++) = '-'; if (!ShowChannel(sptr, chptr)) *(buf + len++) = '*'; if (IsDelayedJoin(chan) && (sptr != acptr)) *(buf + len++) = '<'; else if (IsChanOp(chan)) *(buf + len++) = '@'; else if (HasVoice(chan)) *(buf + len++) = '+'; else if (IsZombie(chan)) *(buf + len++) = '!'; if (len) *(buf + len) = '\0'; strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); strcat(buf + len, " "); len++; } if (buf[0] != '\0') send_reply(sptr, RPL_WHOISCHANNELS, name, buf); } send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr), cli_info(a2cptr)); if (user) { if (user->away) send_reply(sptr, RPL_AWAY, name, user->away); if (SeeOper(sptr,acptr)) send_reply(sptr, RPL_WHOISOPERATOR, name); if (IsAccount(acptr)) send_reply(sptr, RPL_WHOISACCOUNT, name, user->account); if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr)) send_reply(sptr, RPL_WHOISACTUALLY, name, user->username, user->realhost, ircd_ntoa(&cli_ip(acptr))); /* Hint: if your looking to add more flags to a user, eg +h, here's * probably a good place to add them :) */ if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) || (sptr == acptr || IsAnOper(sptr) || parc >= 3))) send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last, cli_firsttime(acptr)); } }
void handlewhoischannels(int hooknum, void *arg) { channel **chans; char buffer[1024]; unsigned int bufpos; sstring *name; unsigned long *num; int i; char **args = (char **)arg; nick *sender = (nick *)args[0]; /* sender nick */ nick *target = (nick *)args[1]; /* target nick */ char *sourcenum = args[2]; /* source numeric */ /* do not show channels for +k service clients or IRC Operators * do not show channels for +n users * unless they whois themselves */ if ((IsService(target) || IsHideChan(target)) && sender != target) return; chans = (channel **)(target->channels->content); buffer[0] = '\0'; bufpos=0; /* Not handling delayed joins. */ for(i=target->channels->cursi-1;i>=0;i--) { /* Secret / Private channels: only show if the sender is on the channel as well */ if(IsSecret(chans[i]) || IsPrivate(chans[i])) { if (!getnumerichandlefromchanhash(chans[i]->users, sender->numeric)) continue; } name = chans[i]->index->name; if (bufpos + name->length > 508) { /* why 508? - need room for -@#channame\0 + 1 slack */ irc_send("%s", buffer); buffer[0] = '\0'; bufpos=0; } /* * 319 RPL_WHOISCHANNELS "source 319 target nick :channels" * "irc.netsplit.net 319 foobar barfoo :@#chan1 +#chan2 #chan3" * "irc.netsplit.net 319 foobar barfoo :-@#chan1 -+#chan2 -#chan3" */ if(buffer[0] == '\0') bufpos=snprintf(buffer, sizeof(buffer), "%s 319 %s %s :", getmynumeric(), sourcenum, target->nick); num = getnumerichandlefromchanhash(chans[i]->users, target->numeric); /* Adding these flags might make the string "unsafe" (without terminating \0). */ /* sprintf'ing the channel name afterwards is guaranteed to fix it though */ if (IsDeaf(target)) buffer[bufpos++]='-'; if (*num & CUMODE_OP) buffer[bufpos++]='@'; else if (*num & CUMODE_VOICE) buffer[bufpos++]='+'; bufpos += sprintf(buffer+bufpos, "%s ",name->content); } if (buffer[0] != '\0') irc_send("%s", buffer); }